Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix false positive undefined-variable
and ``used-before-assignment`` with nonlocal keyword usage.

incorporate review comments

fix existing test case
  • Loading branch information
sushobhit27 committed Aug 17, 2018
1 parent d8e7840 commit 28a2690
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 2 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Expand Up @@ -15,6 +15,10 @@ Release date: TBA

Close #2309

* Fix false positive ``undefined-variable`` and ``used-before-assignment`` with nonlocal keyword usage.

Close #2049

* Stop ``protected-access`` exception for missing class attributes

* Don't emit `assignment-from-no-return` for decorated function nodes
Expand Down
2 changes: 2 additions & 0 deletions doc/whatsnew/2.2.rst
Expand Up @@ -21,4 +21,6 @@ Other Changes
* `unnecessary-pass` is now also emitted when a function or class contains only docstring and pass statement,
in which case, docstring is enough for empty definition.

* Fix false positive ``undefined-variable`` and ``used-before-assignment`` with nonlocal keyword usage.


9 changes: 8 additions & 1 deletion pylint/checkers/utils.py
Expand Up @@ -205,7 +205,14 @@ def is_builtin(name):


def is_defined_in_scope(var_node, varname, scope):
if isinstance(scope, (COMP_NODE_TYPES, astroid.For)):
if isinstance(scope, astroid.If):
for node in scope.body:
if ((isinstance(node, astroid.Assign) and
any(isinstance(target, astroid.AssignName) and target.name == varname
for target in node.targets)) or
(isinstance(node, astroid.Nonlocal) and varname in node.names)):
return True
elif isinstance(scope, (COMP_NODE_TYPES, astroid.For)):
for ass_node in scope.nodes_of_class(astroid.AssignName):
if ass_node.name == varname:
return True
Expand Down
15 changes: 14 additions & 1 deletion pylint/test/functional/undefined_variable.py
@@ -1,5 +1,5 @@
# pylint: disable=missing-docstring, multiple-statements, useless-object-inheritance
# pylint: disable=too-few-public-methods, no-init, no-self-use,bare-except,broad-except
# pylint: disable=too-few-public-methods, no-init, no-self-use,bare-except,broad-except, import-error
from __future__ import print_function
DEFINED = 1

Expand Down Expand Up @@ -232,3 +232,16 @@ class LambdaClass5:
myattr = 1
mylambda = lambda: LambdaClass5.myattr
mylambda4 = lambda a=LambdaClass5: lambda: a # [undefined-variable]


def nonlocal_in_ifexp():
import matplotlib.pyplot as plt
def onclick(event):
if event:
nonlocal i
i += 1
print(i)
i = 0
fig = plt.figure()
fig.canvas.mpl_connect('button_press_event', onclick)
plt.show(block=True)
13 changes: 13 additions & 0 deletions pylint/test/functional/used_before_assignment_nonlocal.py
Expand Up @@ -45,3 +45,16 @@ def undefined():

def undefined1():
""" no op """


def nonlocal_in_ifexp():
"""bar"""
bug2 = True
def on_click(event):
"""on_click"""
if event:
nonlocal bug2
bug2 = not bug2
on_click(True)

nonlocal_in_ifexp()

0 comments on commit 28a2690

Please sign in to comment.