Source code for rude.rules.pyflakes.variables

"""
Variable-related rules.

F824: UnusedIndirectAssignment - global/nonlocal declared but never assigned locally
F842: UnusedAnnotation - variable annotated but never used or assigned
"""

from __future__ import annotations

from collections.abc import Iterator
from typing import TYPE_CHECKING, ClassVar

from rude.core.node_types import NodeType
from rude.core.rule import Rule
from rude.core.types import Diagnostic, Location, Severity
from rude.providers import ScopeProvider

if TYPE_CHECKING:
    from rude.core.node import Node


[docs] class UnusedAnnotation(Rule): """ F842: Variable is annotated but never used or assigned a value. Rationale: An annotation without an assignment or use is dead code that should be removed or completed. Example:: # Bad def foo(): x: int # F842 - x is never used or assigned # Good def foo(): x: int = 1 Optimized: Uses pre-computed unused_annotations from Rust SemanticModel. """ code: ClassVar[str] = "F842" message: ClassVar[str] = "local variable '{name}' is annotated but never used" severity: ClassVar[Severity] = Severity.WARNING node_types = {NodeType.MODULE} metadata_dependencies: ClassVar[set[type]] = {ScopeProvider}
[docs] def check(self, node: Node) -> Iterator[Diagnostic]: """Find annotations without assignments using pre-computed list from Rust.""" scope_prov: ScopeProvider = node.ctx.get_metadata(ScopeProvider) model = scope_prov.model # Iterate over pre-computed unused annotations for entry in model.unused_annotations: yield Diagnostic( code=self.code, message=self.message.format(name=entry.name), location=Location(line=entry.line, column=entry.column), severity=self.severity, )
[docs] class UnusedIndirectAssignment(Rule): """ F824: Global or nonlocal declaration but name is never assigned in this scope. Rationale: A ``global`` or ``nonlocal`` declaration without a subsequent assignment is unnecessary and misleading. Example:: # Bad def foo(): global x # F824 - x is never assigned in foo() print(x) # Good def foo(): print(x) # just read the global directly Optimized: Uses pre-computed unused_declarations from Rust SemanticModel. """ code: ClassVar[str] = "F824" message: ClassVar[str] = "local variable '{name}' is declared {kind} but never assigned" severity: ClassVar[Severity] = Severity.WARNING node_types = {NodeType.MODULE} metadata_dependencies: ClassVar[set[type]] = {ScopeProvider}
[docs] def check(self, node: Node) -> Iterator[Diagnostic]: """Check for global/nonlocal declarations using pre-computed list from Rust.""" scope_prov: ScopeProvider = node.ctx.get_metadata(ScopeProvider) model = scope_prov.model # Iterate over pre-computed unused declarations for decl in model.unused_declarations: kind = "global" if decl.is_global else "nonlocal" yield Diagnostic( code=self.code, message=self.message.format(name=decl.name, kind=kind), location=Location(line=decl.line, column=decl.column), severity=self.severity, )
VARIABLE_RULES = [ UnusedAnnotation, UnusedIndirectAssignment, ] __all__ = [ "VARIABLE_RULES", "UnusedAnnotation", "UnusedIndirectAssignment", ]