diff options
author | Andrew Simmons <a.simmons@deakin.edu.au> | 2020-04-20 22:40:09 +1000 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2020-04-22 08:26:43 +0200 |
commit | d1484608e89c3e7e2900183e9fb9cbc183de1fb5 (patch) | |
tree | 947568a7b728feea1df966068c26f547795921ee | |
parent | 67d05722b705c949a6bc0638f65e60c5f888c8d4 (diff) | |
download | pylint-git-d1484608e89c3e7e2900183e9fb9cbc183de1fb5.tar.gz |
Fix false positive for ``undefined-variable`` when using class attribute in decorator (#511)
-rw-r--r-- | CONTRIBUTORS.txt | 2 | ||||
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | pylint/checkers/variables.py | 33 | ||||
-rw-r--r-- | tests/unittest_checker_variables.py | 26 |
4 files changed, 53 insertions, 12 deletions
diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index cd15199a8..420c62417 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -379,3 +379,5 @@ contributors: * Matthew Beckers (mattlbeck): contributor * Yang Yang: contributor + +* Andrew J. Simmons (anjsimmo): contributor @@ -7,6 +7,10 @@ What's New in Pylint 2.5.0? Release date: TBA +* Fix a false positive for ``undefined-variable`` when using class attribute in decorator + + Close #511 + * Remove HTML quoting of messages in JSON output. Close #2769 diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index e93e1b3d0..ac1d176ee 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -1249,16 +1249,20 @@ class VariablesChecker(BaseChecker): @staticmethod def _defined_in_function_definition(node, frame): - in_annotation_or_default = False + in_annotation_or_default_or_decorator = False if isinstance(frame, astroid.FunctionDef) and node.statement() is frame: - in_annotation_or_default = ( - node in frame.args.annotations - or node in frame.args.posonlyargs_annotations - or node in frame.args.kwonlyargs_annotations - or node is frame.args.varargannotation - or node is frame.args.kwargannotation - ) or frame.args.parent_of(node) - return in_annotation_or_default + in_annotation_or_default_or_decorator = ( + ( + node in frame.args.annotations + or node in frame.args.posonlyargs_annotations + or node in frame.args.kwonlyargs_annotations + or node is frame.args.varargannotation + or node is frame.args.kwargannotation + ) + or frame.args.parent_of(node) + or (frame.decorators and frame.decorators.parent_of(node)) + ) + return in_annotation_or_default_or_decorator @staticmethod def _is_variable_violation( @@ -1419,13 +1423,18 @@ class VariablesChecker(BaseChecker): name = node.name frame = node.statement().scope() - in_annotation_or_default = self._defined_in_function_definition(node, frame) - if in_annotation_or_default: + in_annotation_or_default_or_decorator = self._defined_in_function_definition( + node, frame + ) + if in_annotation_or_default_or_decorator: frame_locals = frame.parent.scope().locals else: frame_locals = frame.locals return not ( - (isinstance(frame, astroid.ClassDef) or in_annotation_or_default) + ( + isinstance(frame, astroid.ClassDef) + or in_annotation_or_default_or_decorator + ) and name in frame_locals ) diff --git a/tests/unittest_checker_variables.py b/tests/unittest_checker_variables.py index b594e7d18..f33dbf8af 100644 --- a/tests/unittest_checker_variables.py +++ b/tests/unittest_checker_variables.py @@ -119,6 +119,32 @@ class TestVariablesChecker(CheckerTestCase): with self.assertAddsMessages(msg): self.checker.visit_global(node) + def test_listcomp_in_decorator(self): + """ Make sure class attributes in scope for listcomp in decorator. + + https://github.com/PyCQA/pylint/issues/511 + """ + module = astroid.parse( + """ + def dec(inp): + def inner(func): + print(inp) + return func + return inner + + + class Cls: + + DATA = "foo" + + @dec([x for x in DATA]) + def fun(self): + pass + """ + ) + with self.assertNoMessages(): + self.walk(module) + class TestVariablesCheckerWithTearDown(CheckerTestCase): |