diff options
author | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-07-06 17:46:22 +0300 |
---|---|---|
committer | Claudiu Popa <cpopa@cloudbasesolutions.com> | 2015-07-06 17:46:22 +0300 |
commit | 020e84007e7cffb52936e021e6ddb40971f43f62 (patch) | |
tree | 7e94b78ec7dfef9de291bc03f8b8728076328869 /pylint/checkers/base.py | |
parent | 4c5377ce1b4f59c96147851567b6c95d5ef7cd2e (diff) | |
download | pylint-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.py | 22 |
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): |