summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-07-06 17:46:22 +0300
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-07-06 17:46:22 +0300
commit020e84007e7cffb52936e021e6ddb40971f43f62 (patch)
tree7e94b78ec7dfef9de291bc03f8b8728076328869
parent4c5377ce1b4f59c96147851567b6c95d5ef7cd2e (diff)
downloadpylint-020e84007e7cffb52936e021e6ddb40971f43f62.tar.gz
Add a new error, 'nonlocal-and-global'.
This error is emitted when a name is found to be both nonlocal and global in the same scope. This is a SyntaxError in Python 2, but Python 3's ast happily parses it, so it needs to be a separate error. Closes issue #581.
-rw-r--r--ChangeLog4
-rw-r--r--pylint/checkers/base.py22
-rw-r--r--pylint/test/functional/nonlocal_and_global.py12
-rw-r--r--pylint/test/functional/nonlocal_and_global.rc2
-rw-r--r--pylint/test/functional/nonlocal_and_global.txt1
5 files changed, 40 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 5c9eb39..bd23848 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -209,6 +209,10 @@ ChangeLog for Pylint
These were moved since they didn't belong in astroid.
* Enable misplaced-future for Python 3. Closes issue #580.
+
+ * Add a new error, 'nonlocal-and-global', which is emitted when a
+ name is found to be both nonlocal and global in the same scope.
+ Closes issue #581.
diff --git a/pylint/checkers/base.py b/pylint/checkers/base.py
index f2d2969..2ef4b8f 100644
--- a/pylint/checkers/base.py
+++ b/pylint/checkers/base.py
@@ -322,6 +322,10 @@ class BasicErrorChecker(_BasicChecker):
'Emitted when a star expression is not used in an '
'assignment target.',
{'minversion': (3, 0)}),
+ 'E0115': ('Name %r is nonlocal and global',
+ 'nonlocal-and-global',
+ 'Emitted when a name is both nonlocal and global.',
+ {'minversion': (3, 0)}),
}
@check_messages('function-redefined')
@@ -351,8 +355,9 @@ class BasicErrorChecker(_BasicChecker):
@check_messages('init-is-generator', 'return-in-init',
'function-redefined', 'return-arg-in-generator',
- 'duplicate-argument-name')
+ 'duplicate-argument-name', 'nonlocal-and-global')
def visit_function(self, node):
+ self._check_nonlocal_and_global(node)
if not redefined_by_decorator(node):
self._check_redefinition(node.is_method() and 'method' or 'function', node)
# checks for max returns, branch, return in __init__
@@ -386,6 +391,21 @@ class BasicErrorChecker(_BasicChecker):
else:
args.add(name)
+ def _check_nonlocal_and_global(self, node):
+ """Check that a name is both nonlocal and global."""
+ def same_scope(current):
+ return current.scope() is node
+
+ from_iter = itertools.chain.from_iterable
+ nonlocals = set(from_iter(
+ child.names for child in node.nodes_of_class(astroid.Nonlocal)
+ if same_scope(child)))
+ global_vars = set(from_iter(
+ child.names for child in node.nodes_of_class(astroid.Global)
+ if same_scope(child)))
+ for name in nonlocals.intersection(global_vars):
+ self.add_message('nonlocal-and-global',
+ args=(name, ), node=node)
@check_messages('return-outside-function')
def visit_return(self, node):
diff --git a/pylint/test/functional/nonlocal_and_global.py b/pylint/test/functional/nonlocal_and_global.py
new file mode 100644
index 0000000..c601a29
--- /dev/null
+++ b/pylint/test/functional/nonlocal_and_global.py
@@ -0,0 +1,12 @@
+"""Test that a name is both nonlocal and global in the same scope."""
+# pylint: disable=missing-docstring,global-variable-not-assigned,invalid-name
+
+def bad(): # [nonlocal-and-global]
+ nonlocal missing
+ global missing
+
+def good():
+ nonlocal missing
+ def test():
+ global missing
+ return test
diff --git a/pylint/test/functional/nonlocal_and_global.rc b/pylint/test/functional/nonlocal_and_global.rc
new file mode 100644
index 0000000..c093be2
--- /dev/null
+++ b/pylint/test/functional/nonlocal_and_global.rc
@@ -0,0 +1,2 @@
+[testoptions]
+min_pyver=3.0
diff --git a/pylint/test/functional/nonlocal_and_global.txt b/pylint/test/functional/nonlocal_and_global.txt
new file mode 100644
index 0000000..46f0d0f
--- /dev/null
+++ b/pylint/test/functional/nonlocal_and_global.txt
@@ -0,0 +1 @@
+nonlocal-and-global:4:bad:"Name 'missing' is nonlocal and global" \ No newline at end of file