summaryrefslogtreecommitdiff
path: root/pylint/checkers/base.py
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 /pylint/checkers/base.py
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.
Diffstat (limited to 'pylint/checkers/base.py')
-rw-r--r--pylint/checkers/base.py22
1 files changed, 21 insertions, 1 deletions
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):