diff options
author | cpopa <devnull@localhost> | 2013-12-27 18:41:47 +0200 |
---|---|---|
committer | cpopa <devnull@localhost> | 2013-12-27 18:41:47 +0200 |
commit | 54bba4b019a2da504351469ee3cef7c1c8665817 (patch) | |
tree | b15d4e15cd0d29fe8e4881747386e46790320eea | |
parent | 3927b761d923c9d8d32290c5a694acda9083480b (diff) | |
download | pylint-54bba4b019a2da504351469ee3cef7c1c8665817.tar.gz |
Enhance used-before-assignment check to look for nonlocal uses.
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | checkers/variables.py | 25 | ||||
-rw-r--r-- | test/input/func_used_before_assignment_py30.py | 27 | ||||
-rw-r--r-- | test/messages/func_used_before_assignment_py30.txt | 2 |
4 files changed, 58 insertions, 0 deletions
@@ -1,6 +1,10 @@ ChangeLog for Pylint ==================== +-- + * Enhance the check for 'used-before-assignment' to look + for 'nonlocal' uses. + 2013-12-22 -- 1.1.0 * Add new check for use of deprecated pragma directives "pylint:disable-msg" or "pylint:enable-msg" (I0022, deprecated-pragma) which was previously diff --git a/checkers/variables.py b/checkers/variables.py index 90b7fe7..4ad82c4 100644 --- a/checkers/variables.py +++ b/checkers/variables.py @@ -507,6 +507,31 @@ builtins. Remember that you should avoid to define new builtins when possible.' # defined in global or builtin scope if defframe.root().lookup(name)[1]: maybee0601 = False + else: + # check if we have a nonlocal + frame = node.frame() + frame_parent = frame.parent + if (isinstance(frame, astroid.Function) and + isinstance(frame_parent, astroid.Function)): + # detect that the name exists + # in the upper level + defined_higher = False + for assign in frame_parent.get_children(): + if not isinstance(assign, astroid.Assign): + continue + for target in assign.targets: + if (isinstance(target, astroid.AssName) and + target.name == name): + defined_higher = True + break + if defined_higher: + break + for child in frame.get_children(): + if not isinstance(child, astroid.Nonlocal): + continue + if name in child.names and defined_higher: + maybee0601 = False + break if (maybee0601 and stmt.fromlineno <= defstmt.fromlineno and not is_defined_before(node) diff --git a/test/input/func_used_before_assignment_py30.py b/test/input/func_used_before_assignment_py30.py new file mode 100644 index 0000000..04987f3 --- /dev/null +++ b/test/input/func_used_before_assignment_py30.py @@ -0,0 +1,27 @@ +"""Check for nonlocal and used-before-assignment"""
+# pylint: disable=missing-docstring, unused-variable
+
+__revision__ = 0
+
+def test_ok():
+ """ uses nonlocal """
+ cnt = 1
+ def wrap():
+ nonlocal cnt
+ cnt = cnt + 1
+ wrap()
+
+def test_fail():
+ """ doesn't use nonlocal """
+ cnt = 1
+ def wrap():
+ cnt = cnt + 1
+ wrap()
+
+def test2_fail():
+ """ uses nonlocal, but without an
+ outer label defined. """
+ def wrap():
+ nonlocal cnt
+ cnt = cnt + 1
+ wrap()
diff --git a/test/messages/func_used_before_assignment_py30.txt b/test/messages/func_used_before_assignment_py30.txt new file mode 100644 index 0000000..f731b3c --- /dev/null +++ b/test/messages/func_used_before_assignment_py30.txt @@ -0,0 +1,2 @@ +E: 18:test_fail.wrap: Using variable 'cnt' before assignment
+E: 26:test2_fail.wrap: Using variable 'cnt' before assignment
\ No newline at end of file |