Skip to content

Commit

Permalink
Fix false positive for used-before-assignment for vars in methods (
Browse files Browse the repository at this point in the history
…#5454)

* Create new ``used_before_assignment_typing`` test file

* Fix false positive for ``used-before-assignment`` for vars in methods
  • Loading branch information
DanielNoord committed Dec 2, 2021
1 parent c15d1cf commit 8f12337
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 36 deletions.
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 4 additions & 1 deletion pylint/checkers/variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -1688,7 +1688,10 @@ def _is_first_level_self_reference(
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):
Expand Down
30 changes: 0 additions & 30 deletions tests/functional/u/use/used_before_assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
7 changes: 2 additions & 5 deletions tests/functional/u/use/used_before_assignment.txt
Original file line number Diff line number Diff line change
@@ -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
63 changes: 63 additions & 0 deletions tests/functional/u/use/used_before_assignment_typing.py
Original file line number Diff line number Diff line change
@@ -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)
3 changes: 3 additions & 0 deletions tests/functional/u/use/used_before_assignment_typing.txt
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 8f12337

Please sign in to comment.