diff options
author | Daniƫl van Noord <13665637+DanielNoord@users.noreply.github.com> | 2021-12-02 19:12:51 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-12-02 19:12:51 +0100 |
commit | 8f12337deed0e532516307522041842227bd25a6 (patch) | |
tree | 14bfbff0d56add25a8da93ac8dcfa65af655f93b | |
parent | c15d1cf642f1731ca22e12dbe6e5b0dddb1856a2 (diff) | |
download | pylint-git-8f12337deed0e532516307522041842227bd25a6.tar.gz |
Fix false positive for ``used-before-assignment`` for vars in methods (#5454)
* Create new ``used_before_assignment_typing`` test file
* Fix false positive for ``used-before-assignment`` for vars in methods
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 5 | ||||
-rw-r--r-- | tests/functional/u/use/used_before_assignment.py | 30 | ||||
-rw-r--r-- | tests/functional/u/use/used_before_assignment.txt | 7 | ||||
-rw-r--r-- | tests/functional/u/use/used_before_assignment_typing.py | 63 | ||||
-rw-r--r-- | tests/functional/u/use/used_before_assignment_typing.txt | 3 |
6 files changed, 77 insertions, 36 deletions
@@ -25,6 +25,11 @@ Release date: TBA * Fixed a false positive for ``unused-import`` where everything was not analyzed properly inside typing guards. +* Fixed a false-positive regression for ``used-before-assignment`` for + typed variables in the body of class methods that reference the same class + + Closes #5342 + * Specified that the ``ignore-paths`` option considers "\" to represent a windows directory delimiter instead of a regular expression escape character. diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index 63216adea..ecc425313 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -1688,7 +1688,10 @@ class VariablesChecker(BaseChecker): 1 = Break 2 = Break + emit message """ - if node.frame().parent == defstmt: + if ( + node.frame().parent == defstmt + and node.statement(future=True) not in node.frame().body + ): # Check if used as type annotation # Break but don't emit message if postponed evaluation is enabled if utils.is_node_in_type_annotation_context(node): diff --git a/tests/functional/u/use/used_before_assignment.py b/tests/functional/u/use/used_before_assignment.py index 376515c54..5b469041e 100644 --- a/tests/functional/u/use/used_before_assignment.py +++ b/tests/functional/u/use/used_before_assignment.py @@ -2,37 +2,7 @@ # pylint: disable=consider-using-f-string, missing-function-docstring __revision__ = None -from typing import List - MSG = "hello %s" % MSG # [used-before-assignment] MSG2 = "hello %s" % MSG2 # [used-before-assignment] - - -class MyClass: - """Type annotation or default values for first level methods can't refer to their own class""" - - def incorrect_typing_method( - self, other: MyClass # [used-before-assignment] - ) -> bool: - return self == other - - def incorrect_nested_typing_method( - self, other: List[MyClass] # [used-before-assignment] - ) -> bool: - return self == other[0] - - def incorrect_default_method( - self, other=MyClass() # [used-before-assignment] - ) -> bool: - return self == other - - def correct_string_typing_method(self, other: "MyClass") -> bool: - return self == other - - def correct_inner_typing_method(self) -> bool: - def inner_method(self, other: MyClass) -> bool: - return self == other - - return inner_method(self, MyClass()) diff --git a/tests/functional/u/use/used_before_assignment.txt b/tests/functional/u/use/used_before_assignment.txt index f654f261c..d063aa000 100644 --- a/tests/functional/u/use/used_before_assignment.txt +++ b/tests/functional/u/use/used_before_assignment.txt @@ -1,5 +1,2 @@ -used-before-assignment:8:19:8:22::Using variable 'MSG' before assignment:UNDEFINED -used-before-assignment:10:20:10:24::Using variable 'MSG2' before assignment:UNDEFINED -used-before-assignment:17:21:17:28:MyClass.incorrect_typing_method:Using variable 'MyClass' before assignment:UNDEFINED -used-before-assignment:22:26:22:33:MyClass.incorrect_nested_typing_method:Using variable 'MyClass' before assignment:UNDEFINED -used-before-assignment:27:20:27:27:MyClass.incorrect_default_method:Using variable 'MyClass' before assignment:UNDEFINED +used-before-assignment:6:19:6:22::Using variable 'MSG' before assignment:UNDEFINED +used-before-assignment:8:20:8:24::Using variable 'MSG2' before assignment:UNDEFINED diff --git a/tests/functional/u/use/used_before_assignment_typing.py b/tests/functional/u/use/used_before_assignment_typing.py new file mode 100644 index 000000000..a9961c890 --- /dev/null +++ b/tests/functional/u/use/used_before_assignment_typing.py @@ -0,0 +1,63 @@ +"""Tests for used-before-assignment for typing related issues""" +# pylint: disable=missing-function-docstring + + +from typing import List, Optional + + +class MyClass: + """Type annotation or default values for first level methods can't refer to their own class""" + + def incorrect_typing_method( + self, other: MyClass # [used-before-assignment] + ) -> bool: + return self == other + + def incorrect_nested_typing_method( + self, other: List[MyClass] # [used-before-assignment] + ) -> bool: + return self == other[0] + + def incorrect_default_method( + self, other=MyClass() # [used-before-assignment] + ) -> bool: + return self == other + + def correct_string_typing_method(self, other: "MyClass") -> bool: + return self == other + + def correct_inner_typing_method(self) -> bool: + def inner_method(self, other: MyClass) -> bool: + return self == other + + return inner_method(self, MyClass()) + + +class MySecondClass: + """Class to test self referential variable typing. + This regressed, reported in: https://github.com/PyCQA/pylint/issues/5342 + """ + + def self_referential_optional_within_method(self) -> None: + variable: Optional[MySecondClass] = self + print(variable) + + def correct_inner_typing_method(self) -> bool: + def inner_method(self, other: MySecondClass) -> bool: + return self == other + + return inner_method(self, MySecondClass()) + + +class MyOtherClass: + """Class to test self referential variable typing, no regression.""" + + def correct_inner_typing_method(self) -> bool: + def inner_method(self, other: MyOtherClass) -> bool: + return self == other + + return inner_method(self, MyOtherClass()) + + def self_referential_optional_within_method(self) -> None: + variable: Optional[MyOtherClass] = self + print(variable) diff --git a/tests/functional/u/use/used_before_assignment_typing.txt b/tests/functional/u/use/used_before_assignment_typing.txt new file mode 100644 index 000000000..7f73a9eb6 --- /dev/null +++ b/tests/functional/u/use/used_before_assignment_typing.txt @@ -0,0 +1,3 @@ +used-before-assignment:12:21:12:28:MyClass.incorrect_typing_method:Using variable 'MyClass' before assignment:UNDEFINED +used-before-assignment:17:26:17:33:MyClass.incorrect_nested_typing_method:Using variable 'MyClass' before assignment:UNDEFINED +used-before-assignment:22:20:22:27:MyClass.incorrect_default_method:Using variable 'MyClass' before assignment:UNDEFINED |