summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniƫl van Noord <13665637+DanielNoord@users.noreply.github.com>2021-12-02 19:12:51 +0100
committerGitHub <noreply@github.com>2021-12-02 19:12:51 +0100
commit8f12337deed0e532516307522041842227bd25a6 (patch)
tree14bfbff0d56add25a8da93ac8dcfa65af655f93b
parentc15d1cf642f1731ca22e12dbe6e5b0dddb1856a2 (diff)
downloadpylint-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--ChangeLog5
-rw-r--r--pylint/checkers/variables.py5
-rw-r--r--tests/functional/u/use/used_before_assignment.py30
-rw-r--r--tests/functional/u/use/used_before_assignment.txt7
-rw-r--r--tests/functional/u/use/used_before_assignment_typing.py63
-rw-r--r--tests/functional/u/use/used_before_assignment_typing.txt3
6 files changed, 77 insertions, 36 deletions
diff --git a/ChangeLog b/ChangeLog
index 4ba15898b..a48b4ff39 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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