diff --git a/pyflakes/checker.py b/pyflakes/checker.py index 9888d7ac..0c96af3b 100644 --- a/pyflakes/checker.py +++ b/pyflakes/checker.py @@ -526,7 +526,10 @@ def __repr__(self): class ClassScope(Scope): - pass + def __init__(self): + super().__init__() + # {name: node} + self.indirect_assignments = {} class FunctionScope(Scope): @@ -566,9 +569,6 @@ def unused_annotations(self): if not binding.used and isinstance(binding, Annotation): yield name, binding - def unused_indirect_assignments(self): - return self.indirect_assignments.items() - class TypeScope(Scope): pass @@ -835,6 +835,10 @@ def checkDeadScopes(self): which were imported but unused. """ for scope in self.deadScopes: + if isinstance(scope, (ClassScope, FunctionScope)): + for name, node in scope.indirect_assignments.items(): + self.report(messages.UnusedIndirectAssignment, node, name) + # imports in classes are public members if isinstance(scope, ClassScope): continue @@ -844,8 +848,6 @@ def checkDeadScopes(self): self.report(messages.UnusedVariable, binding.source, name) for name, binding in scope.unused_annotations(): self.report(messages.UnusedAnnotation, binding.source, name) - for name, node in scope.unused_indirect_assignments(): - self.report(messages.UnusedIndirectAssignment, node, name) all_binding = scope.get('__all__') if all_binding and not isinstance(all_binding, ExportBinding): @@ -988,7 +990,7 @@ def addBinding(self, node, value): self.report(messages.RedefinedWhileUnused, node, value.name, existing.source) - if isinstance(scope, FunctionScope): + if isinstance(scope, (ClassScope, FunctionScope)): scope.indirect_assignments.pop(value.name, None) elif isinstance(existing, Importation) and value.redefines(existing): @@ -1191,7 +1193,7 @@ def on_conditional_branch(): # be executed. return - if isinstance(self.scope, FunctionScope): + if isinstance(self.scope, (ClassScope, FunctionScope)): self.scope.indirect_assignments.pop(name, None) if isinstance(self.scope, FunctionScope) and name in self.scope.globals: diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py index 23990820..fcf95572 100644 --- a/pyflakes/test/test_other.py +++ b/pyflakes/test/test_other.py @@ -1121,6 +1121,36 @@ def f2(): g = 2 ''', m.UnusedIndirectAssignment, m.UnusedVariable) + def test_global_nonlocal_in_class_bodies(self): + self.flakes(''' + g = 0 + class C: + global g + g = 1 + def f(): + nl = 0 + class C: + nonlocal nl + nl = 1 + ''') + + def test_unused_global_in_class(self): + self.flakes(''' + g = 0 + class C: + global g + u = g + ''', m.UnusedIndirectAssignment) + + def test_unused_nonlocal_in_clas(self): + self.flakes(''' + def f(): + nl = 1 + class C: + nonlocal nl + u = nl + ''', m.UnusedIndirectAssignment) + def test_function_arguments(self): """ Test to traverse ARG and ARGUMENT handler