diff options
author | Jacob Walls <jacobtylerwalls@gmail.com> | 2022-04-06 13:17:46 -0400 |
---|---|---|
committer | Pierre Sassoulas <pierre.sassoulas@gmail.com> | 2022-04-06 21:15:17 +0200 |
commit | a03b6e77bef920a7c72be9f3e2c2babddecd2fd2 (patch) | |
tree | 9f06689c45ca2d6291931047af7acfce19045e0c | |
parent | 074131312977fbd423fe4faff004d4fa8dbba4e5 (diff) | |
download | pylint-git-a03b6e77bef920a7c72be9f3e2c2babddecd2fd2.tar.gz |
Prevent `used-before-assignment` for assignment via nonlocal after type annotation (#6185)
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | doc/whatsnew/2.13.rst | 5 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 14 | ||||
-rw-r--r-- | tests/functional/u/used/used_before_assignment_nonlocal.py | 31 | ||||
-rw-r--r-- | tests/functional/u/used/used_before_assignment_nonlocal.txt | 1 |
5 files changed, 56 insertions, 0 deletions
@@ -40,6 +40,11 @@ Release date: TBA * functions & classes which contain both a docstring and an ellipsis. * A body which contains an ellipsis ``nodes.Expr`` node & at least one other statement. +* Fix false positive for ``used-before-assignment`` for assignments taking place via + nonlocal declarations after an earlier type annotation. + + Closes #5394 + * Fix crash for ``redefined-slots-in-subclass`` when the type of the slot is not a const or a string. Closes #6100 diff --git a/doc/whatsnew/2.13.rst b/doc/whatsnew/2.13.rst index d8d105f3c..73e898d24 100644 --- a/doc/whatsnew/2.13.rst +++ b/doc/whatsnew/2.13.rst @@ -576,6 +576,11 @@ Other Changes Closes #5803 +* Fix false positive for ``used-before-assignment`` for assignments taking place via + nonlocal declarations after an earlier type annotation. + + Closes #5394 + * Fix false positive for 'nonexistent-operator' when repeated '-' are separated (e.g. by parens). diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index dcd59b39b..be30c0579 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -2074,6 +2074,20 @@ class VariablesChecker(BaseChecker): parent = node while parent is not defstmt_frame.parent: parent_scope = parent.scope() + + # Find out if any nonlocals receive values in nested functions + for inner_func in parent_scope.nodes_of_class(nodes.FunctionDef): + if inner_func is parent_scope: + continue + if any( + node.name in nl.names + for nl in inner_func.nodes_of_class(nodes.Nonlocal) + ) and any( + node.name == an.name + for an in inner_func.nodes_of_class(nodes.AssignName) + ): + return False + local_refs = parent_scope.locals.get(node.name, []) for ref_node in local_refs: # If local ref is in the same frame as our node, but on a later lineno diff --git a/tests/functional/u/used/used_before_assignment_nonlocal.py b/tests/functional/u/used/used_before_assignment_nonlocal.py index 5cbdd510c..aa0b654b7 100644 --- a/tests/functional/u/used/used_before_assignment_nonlocal.py +++ b/tests/functional/u/used/used_before_assignment_nonlocal.py @@ -58,3 +58,34 @@ def nonlocal_in_ifexp(): on_click(True)
nonlocal_in_ifexp()
+
+
+def type_annotation_only_gets_value_via_nonlocal():
+ """https://github.com/PyCQA/pylint/issues/5394"""
+ some_num: int
+ def inner():
+ nonlocal some_num
+ some_num = 5
+ inner()
+ print(some_num)
+
+
+def type_annotation_only_gets_value_via_nonlocal_nested():
+ """Similar, with nesting"""
+ some_num: int
+ def inner():
+ def inner2():
+ nonlocal some_num
+ some_num = 5
+ inner2()
+ inner()
+ print(some_num)
+
+
+def type_annotation_never_gets_value_despite_nonlocal():
+ """Type annotation lacks a value despite nonlocal declaration"""
+ some_num: int
+ def inner():
+ nonlocal some_num
+ inner()
+ print(some_num) # [used-before-assignment]
diff --git a/tests/functional/u/used/used_before_assignment_nonlocal.txt b/tests/functional/u/used/used_before_assignment_nonlocal.txt index 90525457e..f3e873315 100644 --- a/tests/functional/u/used/used_before_assignment_nonlocal.txt +++ b/tests/functional/u/used/used_before_assignment_nonlocal.txt @@ -4,3 +4,4 @@ used-before-assignment:30:20:30:30:test_fail3:Using variable 'test_fail4' before used-before-assignment:34:22:34:32:test_fail4:Using variable 'test_fail5' before assignment:HIGH used-before-assignment:34:44:34:53:test_fail4:Using variable 'undefined' before assignment:HIGH used-before-assignment:40:18:40:28:test_fail5:Using variable 'undefined1' before assignment:HIGH +used-before-assignment:91:10:91:18:type_annotation_never_gets_value_despite_nonlocal:Using variable 'some_num' before assignment:HIGH |