diff options
-rw-r--r-- | ChangeLog | 4 | ||||
-rw-r--r-- | pylint/checkers/imports.py | 21 | ||||
-rw-r--r-- | pylint/test/unittest_checker_imports.py | 60 |
3 files changed, 82 insertions, 3 deletions
@@ -2,6 +2,10 @@ ChangeLog for Pylint -------------------- -- + * Don't emit import-error for ignored modules. PyLint will not emit import + errors for any import which is, or is a subpackage of, a module in + the ignored-modules list. Closes issue #223. + * Fix unused-import false positive when the import is used in a class assignment. Closes issue #475 diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py index eb93b4f..20f8db9 100644 --- a/pylint/checkers/imports.py +++ b/pylint/checkers/imports.py @@ -291,12 +291,27 @@ given file (report RP0402 must not be disabled)'} args = '%r (%s)' % (modname, ex) else: args = repr(modname) + ignored_modules = get_global_option(self, 'ignored-modules', default=[]) - while modname and modname not in ignored_modules: - modname = modname.rpartition('.')[0] - if not modname and not _except_import_error(importnode.parent): + for submodule in self._module_hierarchy(modname): + if submodule in ignored_modules: + return None + + if not _except_import_error(importnode.parent): self.add_message("import-error", args=args, node=importnode) + def _module_hierarchy(self, modname): + """Returns a list representing the module heirarchy, where each element + is the fullly qualified name of the parent of the next element. + + For example, + _module_hierarchy('pylint.checkers.ImportsChecker') + returns + ['pylint', 'pylint.checkers', 'pylint.checkers.ImportsChecker'] + """ + names = modname.split('.') + return ['.'.join(names[0:i+1]) for i in range(len(names))] + def _check_relative_import(self, modnode, importnode, importedmodnode, importedasname): """check relative import. node is either an Import or From node, modname diff --git a/pylint/test/unittest_checker_imports.py b/pylint/test/unittest_checker_imports.py new file mode 100644 index 0000000..55948ec --- /dev/null +++ b/pylint/test/unittest_checker_imports.py @@ -0,0 +1,60 @@ +"""Unit tests for the imports checker.""" +import unittest + +from astroid import test_utils +from pylint.checkers import imports +from pylint.testutils import CheckerTestCase, set_config + +class ImportsCheckerTC(CheckerTestCase): + + CHECKER_CLASS = imports.ImportsChecker + + def test_bitbucket_issue_78(self): + """ Issue 78 report a false positive for unused-module """ + module = test_utils.build_module(""" + from sys import path + path += ['stuff'] + def func(): + other = 1 + return len(other) + """) + with self.assertNoMessages(): + self.walk(module) + + @set_config(ignored_modules=('external_module', 'fake_module.submodule')) + def test_import_error_skipped(self): + """Make sure that imports do not emit a 'import-error' when the + module is configured to be ignored.""" + + node = test_utils.extract_node(""" + from external_module import anything + """) + with self.assertNoMessages(): + self.checker.visit_from(node) + + node = test_utils.extract_node(""" + from external_module.another_module import anything + """) + with self.assertNoMessages(): + self.checker.visit_from(node) + + node = test_utils.extract_node(""" + import external_module + """) + with self.assertNoMessages(): + self.checker.visit_import(node) + + node = test_utils.extract_node(""" + from fake_module.submodule import anything + """) + with self.assertNoMessages(): + self.checker.visit_from(node) + + node = test_utils.extract_node(""" + from fake_module.submodule.deeper import anything + """) + with self.assertNoMessages(): + self.checker.visit_from(node) + +if __name__ == '__main__': + unittest.main() |