diff options
author | Yann Sartori <yannsartori@gmail.com> | 2022-05-30 12:20:13 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-05-30 12:20:13 -0400 |
commit | e02336c3d47c621feed730f5bdaa792babca75be (patch) | |
tree | c6a67e5c5ae22c5561a06d488e73ae9d4f9646f7 | |
parent | dd446ed156837f50a06596ec79efc292e856954f (diff) | |
download | pyflakes-e02336c3d47c621feed730f5bdaa792babca75be.tar.gz |
assignment expression in comprehension should target outer scope (#698)
Co-authored-by: Yann Sartori <sartori2@llnl.gov>
-rw-r--r-- | pyflakes/checker.py | 17 | ||||
-rw-r--r-- | pyflakes/test/test_other.py | 17 |
2 files changed, 33 insertions, 1 deletions
diff --git a/pyflakes/checker.py b/pyflakes/checker.py index 7f33d6a..0c3f66e 100644 --- a/pyflakes/checker.py +++ b/pyflakes/checker.py @@ -540,6 +540,12 @@ class Assignment(Binding): """ +class NamedExprAssignment(Assignment): + """ + Represents binding a name with an assignment expression. + """ + + class Annotation(Binding): """ Represents binding a name to a type without an associated value. @@ -1159,7 +1165,14 @@ class Checker(object): # don't treat annotations as assignments if there is an existing value # in scope if value.name not in self.scope or not isinstance(value, Annotation): - self.scope[value.name] = value + cur_scope_pos = -1 + # As per PEP 572, use scope in which outermost generator is defined + while ( + isinstance(value, NamedExprAssignment) and + isinstance(self.scopeStack[cur_scope_pos], GeneratorScope) + ): + cur_scope_pos -= 1 + self.scopeStack[cur_scope_pos][value.name] = value def _unknown_handler(self, node): # this environment variable configures whether to error on unknown @@ -1302,6 +1315,8 @@ class Checker(object): binding = ExportBinding(name, node._pyflakes_parent, self.scope) elif PY2 and isinstance(getattr(node, 'ctx', None), ast.Param): binding = Argument(name, self.getScopeNode(node)) + elif PY38_PLUS and isinstance(parent_stmt, ast.NamedExpr): + binding = NamedExprAssignment(name, node) else: binding = Assignment(name, node) self.addBinding(node, binding) diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py index 68813bd..efbc75d 100644 --- a/pyflakes/test/test_other.py +++ b/pyflakes/test/test_other.py @@ -1772,6 +1772,23 @@ class TestUnusedAssignment(TestCase): print(x) ''') + @skipIf(version_info < (3, 8), 'new in Python 3.8') + def test_assign_expr_generator_scope(self): + """Test assignment expressions in generator expressions.""" + self.flakes(''' + if (any((y := x[0]) for x in [[True]])): + print(y) + ''') + + @skipIf(version_info < (3, 8), 'new in Python 3.8') + def test_assign_expr_nested(self): + """Test assignment expressions in nested expressions.""" + self.flakes(''' + if ([(y:=x) for x in range(4) if [(z:=q) for q in range(4)]]): + print(y) + print(z) + ''') + class TestStringFormatting(TestCase): |