Skip to content

Commit

Permalink
Exempt type checking definitions defined in both clauses of a type ch…
Browse files Browse the repository at this point in the history
…ecking guard

Close #3127
  • Loading branch information
PCManticore committed Sep 25, 2019
1 parent 2fa5d43 commit 3159b17
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 33 deletions.
24 changes: 20 additions & 4 deletions pylint/checkers/variables.py
Expand Up @@ -1338,12 +1338,28 @@ def _is_variable_violation(
# Single statement function, with the statement on the
# same line as the function definition
maybee0601 = False

# Look for type checking definitions inside a type checking guard.
if isinstance(defstmt, (astroid.Import, astroid.ImportFrom)):
defstmt_parent = defstmt.parent
if isinstance(
defstmt_parent, astroid.If
) and not defstmt_parent.parent_of(node):
if defstmt_parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS:

if (
isinstance(defstmt_parent, astroid.If)
and defstmt_parent.test.as_string() in TYPING_TYPE_CHECKS_GUARDS
):
# Exempt those definitions that are used inside the type checking
# guard or that are defined in both type checking guard branches.
used_in_branch = defstmt_parent.parent_of(node)
defined_in_or_else = False

for definition in defstmt_parent.orelse:
if isinstance(definition, astroid.Assign):
defined_in_or_else = any(
target.name == name for target in definition.targets
)
break

if not used_in_branch and not defined_in_or_else:
maybee0601 = True

return maybee0601, annotation_return, use_outer_definition
Expand Down
16 changes: 14 additions & 2 deletions tests/functional/u/undefined_variable.py
@@ -1,6 +1,10 @@
# pylint: disable=missing-docstring, multiple-statements, useless-object-inheritance,import-outside-toplevel
# pylint: disable=too-few-public-methods, no-init, no-self-use,bare-except,broad-except, import-error
from __future__ import print_function

# pylint: disable=wrong-import-position
from typing import TYPE_CHECKING

DEFINED = 1

if DEFINED != 1:
Expand Down Expand Up @@ -247,8 +251,6 @@ def onclick(event):
plt.show(block=True)


# pylint: disable=wrong-import-position
from typing import TYPE_CHECKING

if TYPE_CHECKING:
from datetime import datetime
Expand All @@ -264,3 +266,13 @@ def func_should_fail(_dt: datetime): # [used-before-assignment]
from typing_extensions import Literal

AllowedValues = Literal['hello', 'world']


if TYPE_CHECKING:
from collections import Counter
else:
Counter = object


def tick(counter: Counter, name: str) -> None:
counter[name] += 1
54 changes: 27 additions & 27 deletions tests/functional/u/undefined_variable.txt
@@ -1,27 +1,27 @@
undefined-variable:7::Undefined variable 'unknown'
undefined-variable:13:in_method:Undefined variable 'nomoreknown'
undefined-variable:16::Undefined variable '__revision__'
undefined-variable:18::Undefined variable '__revision__'
undefined-variable:22:bad_default:Undefined variable 'unknown2'
undefined-variable:25:bad_default:Undefined variable 'xxxx'
undefined-variable:26:bad_default:Undefined variable 'augvar'
undefined-variable:27:bad_default:Undefined variable 'vardel'
undefined-variable:29:<lambda>:Undefined variable 'doesnotexist'
undefined-variable:30:<lambda>:Undefined variable 'z'
used-before-assignment:38::Using variable 'POUETT' before assignment
used-before-assignment:51::Using variable 'PLOUF' before assignment
used-before-assignment:60:if_branch_test:Using variable 'xxx' before assignment
used-before-assignment:86:test_arguments:Using variable 'TestClass' before assignment
used-before-assignment:90:TestClass:Using variable 'Ancestor' before assignment
used-before-assignment:93:TestClass.MissingAncestor:Using variable 'Ancestor1' before assignment
used-before-assignment:100:TestClass.test1.UsingBeforeDefinition:Using variable 'Empty' before assignment
undefined-variable:114:Self:Undefined variable 'Self'
undefined-variable:130::Undefined variable 'BAT'
used-before-assignment:141:KeywordArgument.test1:Using variable 'enabled' before assignment
undefined-variable:144:KeywordArgument.test2:Undefined variable 'disabled'
undefined-variable:149:KeywordArgument.<lambda>:Undefined variable 'arg'
undefined-variable:161::Undefined variable 'unicode_2'
undefined-variable:171::Undefined variable 'unicode_4'
undefined-variable:226:LambdaClass4.<lambda>:Undefined variable 'LambdaClass4'
undefined-variable:234:LambdaClass5.<lambda>:Undefined variable 'LambdaClass5'
used-before-assignment:257:func_should_fail:Using variable 'datetime' before assignment
undefined-variable:11::Undefined variable 'unknown'
undefined-variable:17:in_method:Undefined variable 'nomoreknown'
undefined-variable:20::Undefined variable '__revision__'
undefined-variable:22::Undefined variable '__revision__'
undefined-variable:26:bad_default:Undefined variable 'unknown2'
undefined-variable:29:bad_default:Undefined variable 'xxxx'
undefined-variable:30:bad_default:Undefined variable 'augvar'
undefined-variable:31:bad_default:Undefined variable 'vardel'
undefined-variable:33:<lambda>:Undefined variable 'doesnotexist'
undefined-variable:34:<lambda>:Undefined variable 'z'
used-before-assignment:42::Using variable 'POUETT' before assignment
used-before-assignment:55::Using variable 'PLOUF' before assignment
used-before-assignment:64:if_branch_test:Using variable 'xxx' before assignment
used-before-assignment:90:test_arguments:Using variable 'TestClass' before assignment
used-before-assignment:94:TestClass:Using variable 'Ancestor' before assignment
used-before-assignment:97:TestClass.MissingAncestor:Using variable 'Ancestor1' before assignment
used-before-assignment:104:TestClass.test1.UsingBeforeDefinition:Using variable 'Empty' before assignment
undefined-variable:118:Self:Undefined variable 'Self'
undefined-variable:134::Undefined variable 'BAT'
used-before-assignment:145:KeywordArgument.test1:Using variable 'enabled' before assignment
undefined-variable:148:KeywordArgument.test2:Undefined variable 'disabled'
undefined-variable:153:KeywordArgument.<lambda>:Undefined variable 'arg'
undefined-variable:165::Undefined variable 'unicode_2'
undefined-variable:175::Undefined variable 'unicode_4'
undefined-variable:230:LambdaClass4.<lambda>:Undefined variable 'LambdaClass4'
undefined-variable:238:LambdaClass5.<lambda>:Undefined variable 'LambdaClass5'
used-before-assignment:259:func_should_fail:Using variable 'datetime' before assignment

0 comments on commit 3159b17

Please sign in to comment.