diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2019-09-25 09:40:18 +0200 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2019-09-25 09:43:58 +0200 |
commit | 3159b1744caee14068b4d875bb5adaa5ffbebd44 (patch) | |
tree | d2ea9bc96da4e9bb6b431fb687bc9760701020d1 | |
parent | 2fa5d435df32ff363596de6e0285c13264e4ba30 (diff) | |
download | pylint-git-3159b1744caee14068b4d875bb5adaa5ffbebd44.tar.gz |
Exempt type checking definitions defined in both clauses of a type checking guard
Close #3127
-rw-r--r-- | pylint/checkers/variables.py | 24 | ||||
-rw-r--r-- | tests/functional/u/undefined_variable.py | 16 | ||||
-rw-r--r-- | tests/functional/u/undefined_variable.txt | 54 |
3 files changed, 61 insertions, 33 deletions
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index e4be053cd..dcbf4ec0c 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -1338,12 +1338,28 @@ class VariablesChecker(BaseChecker): # 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 diff --git a/tests/functional/u/undefined_variable.py b/tests/functional/u/undefined_variable.py index 71df92960..909898f16 100644 --- a/tests/functional/u/undefined_variable.py +++ b/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: @@ -247,8 +251,6 @@ def nonlocal_in_ifexp(): plt.show(block=True) -# pylint: disable=wrong-import-position -from typing import TYPE_CHECKING if TYPE_CHECKING: from datetime import datetime @@ -264,3 +266,13 @@ if TYPE_CHECKING: 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 diff --git a/tests/functional/u/undefined_variable.txt b/tests/functional/u/undefined_variable.txt index 5f9ca9747..4a0e83aec 100644 --- a/tests/functional/u/undefined_variable.txt +++ b/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 |