From ad7c2cd38f7213edd1ff37aaead86d5ae8390df4 Mon Sep 17 00:00:00 2001 From: Claudiu Popa Date: Fri, 25 Mar 2016 14:36:31 +0000 Subject: Add a new option, 'redefining-builtins-modules'. The option can be used for controlling the modules which can redefine builtins, such as six.moves and future.builtins. Close #464. --- pylint/checkers/variables.py | 19 ++++++++++++++--- pylint/test/unittest_checker_variables.py | 34 +++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) (limited to 'pylint') diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py index db03e3a9d..ee2a55792 100644 --- a/pylint/checkers/variables.py +++ b/pylint/checkers/variables.py @@ -339,7 +339,13 @@ class VariablesChecker(BaseChecker): 'help' : 'List of strings which can identify a callback ' 'function by name. A callback name must start or ' 'end with one of those strings.'} - ) + ), + ("redefining-builtins-modules", + {'default': ('six.moves', 'future.builtins'), 'type': 'csv', + 'metavar': '', + 'help': 'List of qualified module names which can have objects ' + 'that can redefine builtins.'} + ), ) def __init__(self, linter=None): BaseChecker.__init__(self, linter) @@ -353,7 +359,8 @@ class VariablesChecker(BaseChecker): self._to_consume = [(copy(node.locals), {}, 'module')] for name, stmts in six.iteritems(node.locals): if is_builtin(name) and not is_inside_except(stmts[0]): - # do not print Redefining builtin for additional builtins + if self._should_ignore_redefined_builtin(stmts[0]): + continue self.add_message('redefined-builtin', args=name, node=stmts[0]) @check_messages('unused-import', 'unused-wildcard-import', @@ -552,7 +559,8 @@ class VariablesChecker(BaseChecker): if not dummy_rgx.match(name): self.add_message('redefined-outer-name', args=(name, line), node=stmt) - elif is_builtin(name): + + elif is_builtin(name) and not self._should_ignore_redefined_builtin(stmt): # do not print Redefining builtin for additional builtins self.add_message('redefined-builtin', args=name, node=stmt) @@ -737,6 +745,11 @@ class VariablesChecker(BaseChecker): and assign.statement() is not node.statement()): self.add_message('undefined-loop-variable', args=name, node=node) + def _should_ignore_redefined_builtin(self, stmt): + if not isinstance(stmt, astroid.ImportFrom): + return False + return stmt.modname in self.config.redefining_builtins_modules + @check_messages('redefine-in-handler') def visit_excepthandler(self, node): for name in get_all_elements(node.name): diff --git a/pylint/test/unittest_checker_variables.py b/pylint/test/unittest_checker_variables.py index e42dffcfd..141a34071 100644 --- a/pylint/test/unittest_checker_variables.py +++ b/pylint/test/unittest_checker_variables.py @@ -89,6 +89,40 @@ class VariablesCheckerTC(CheckerTestCase): self.checker.visit_functiondef(node) self.checker.leave_functiondef(node) + def test_redefined_builtin_ignored(self): + node = astroid.parse(''' + from future.builtins import open + ''') + with self.assertNoMessages(): + self.checker.visit_module(node) + + @set_config(redefining_builtins_modules=('os',)) + def test_redefined_builtin_custom_modules(self): + node = astroid.parse(''' + from os import open + ''') + with self.assertNoMessages(): + self.checker.visit_module(node) + + @set_config(redefining_builtins_modules=('os',)) + def test_redefined_builtin_modname_not_ignored(self): + node = astroid.parse(''' + from future.builtins import open + ''') + with self.assertAddsMessages( + Message('redefined-builtin', node=node.body[0], args='open')): + self.checker.visit_module(node) + + @set_config(redefining_builtins_modules=('os',)) + def test_redefined_builtin_in_function(self): + node = test_utils.extract_node(''' + def test(): + from os import open + ''') + with self.assertNoMessages(): + self.checker.visit_module(node.root()) + self.checker.visit_functiondef(node) + class MissingSubmoduleTest(CheckerTestCase): CHECKER_CLASS = variables.VariablesChecker -- cgit v1.2.1