From 842ee1710db77e200b248f29f66df5707527e82f Mon Sep 17 00:00:00 2001 From: cpopa Date: Fri, 3 Jan 2014 22:16:12 +0200 Subject: Add missing-submodule check for fixing issue #126. --- checkers/imports.py | 4 ++++ checkers/variables.py | 25 ++++++++++++++++++++++--- test/regrtest_data/package_all/__init__.py | 3 +++ test/regrtest_data/package_all/notmissing.py | 2 ++ test/test_func.py | 5 +++-- test/test_misc.py | 15 +++++++++++++-- 6 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 test/regrtest_data/package_all/__init__.py create mode 100644 test/regrtest_data/package_all/notmissing.py diff --git a/checkers/imports.py b/checkers/imports.py index b0a9872..b3cea23 100644 --- a/checkers/imports.py +++ b/checkers/imports.py @@ -149,6 +149,10 @@ MSGS = { 'misplaced-future', 'Python 2.5 and greater require __future__ import to be the \ first non docstring statement in the module.'), + 'W0407': ('Missing submodule: %s', + 'missing-submodule', + 'Used when trying to import a submodule from a package ' + 'and the submodule is missing.'), } class ImportsChecker(BaseChecker): diff --git a/checkers/variables.py b/checkers/variables.py index 90b7fe7..a0bf796 100644 --- a/checkers/variables.py +++ b/checkers/variables.py @@ -15,13 +15,15 @@ # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. """variables checkers for Python code """ - +import os import sys from copy import copy import astroid from astroid import are_exclusive, builtin_lookup, AstroidBuildingException +from logilab.common.modutils import load_module_from_name + from pylint.interfaces import IAstroidChecker from pylint.checkers import BaseChecker from pylint.checkers.utils import (PYMETHODS, is_ancestor_name, is_builtin, @@ -192,7 +194,8 @@ builtins. Remember that you should avoid to define new builtins when possible.' # do not print Redefining builtin for additional builtins self.add_message('W0622', args=name, node=stmts[0]) - @check_messages('W0611', 'W0614', 'W0622', 'E0603', 'E0604') + @check_messages('W0611', 'W0614', 'W0622', 'E0603', 'E0604', + 'missing-submodule') def leave_module(self, node): """leave module: check globals """ @@ -217,7 +220,23 @@ builtins. Remember that you should avoid to define new builtins when possible.' del not_consumed[elt_name] continue if elt_name not in node.locals: - self.add_message('E0603', args=elt_name, node=elt) + if not node.package: + self.add_message('E0603', args=elt_name, node=elt) + else: + basename = os.path.splitext(node.file)[0] + if os.path.basename(basename) == '__init__': + name = node.name + "." + elt_name + try: + load_module_from_name(name) + except ImportError: + self.add_message('missing-submodule', + args=elt_name, + node=elt) + except SyntaxError as exc: + # don't yield an syntax-error warning, + # because it will be later yielded + # when the file will be checked + pass # don't check unused imports in __init__ files if not self.config.init_import and node.package: return diff --git a/test/regrtest_data/package_all/__init__.py b/test/regrtest_data/package_all/__init__.py new file mode 100644 index 0000000..a00d416 --- /dev/null +++ b/test/regrtest_data/package_all/__init__.py @@ -0,0 +1,3 @@ +""" Check for missing-submodule """ +__revision__ = 1 +__all__ = ['notmissing', 'missing'] diff --git a/test/regrtest_data/package_all/notmissing.py b/test/regrtest_data/package_all/notmissing.py new file mode 100644 index 0000000..7cf8543 --- /dev/null +++ b/test/regrtest_data/package_all/notmissing.py @@ -0,0 +1,2 @@ +""" empty """ +__revision__ = 1 diff --git a/test/test_func.py b/test/test_func.py index e8c746d..3b98209 100644 --- a/test/test_func.py +++ b/test/test_func.py @@ -58,12 +58,13 @@ class TestTests(testlib.TestCase): rest = ['I0001', # XXX : no use case for now : 'W0402', # deprecated module - 'W0403', # implicit relative import + 'W0403', # implicit relative import, + 'W0407', # tested in test_misc.py 'W0410', # __future__ import not first statement ] self.assertEqual(todo, rest) else: - self.assertEqual(todo, ['I0001']) + self.assertEqual(todo, ['I0001', 'W0407']) class LintBuiltinModuleTest(LintTestUsingModule): output = join(MSG_DIR, 'builtin_module.txt') diff --git a/test/test_misc.py b/test/test_misc.py index a2cba9b..b77510f 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -22,8 +22,12 @@ import contextlib from logilab.common.testlib import unittest_main from astroid import test_utils -from pylint.checkers import misc -from pylint.testutils import CheckerTestCase, Message +from pylint.checkers import misc, variables +from pylint.testutils import CheckerTestCase, Message, linter + +REGR_DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'regrtest_data') +sys.path.insert(1, REGR_DATA) @contextlib.contextmanager def create_file_backed_module(code): @@ -66,6 +70,13 @@ class FixmeTest(CheckerTestCase): with self.assertNoMessages(): self.checker.process_module(module) +class MissingSubmoduleTest(CheckerTestCase): + CHECKER_CLASS = variables.VariablesChecker + + def test_package_all(self): + linter.check(os.path.join(REGR_DATA, 'package_all')) + got = linter.reporter.finalize().strip() + self.assertEqual(got, 'W: 3: Missing submodule: missing') if __name__ == '__main__': unittest_main() -- cgit v1.2.1 From 4688e5d469264157f2c39d389fc1a25797c4ccdf Mon Sep 17 00:00:00 2001 From: cpopa Date: Sat, 18 Jan 2014 00:06:54 +0200 Subject: Remove missing-submodule, move test fixture inside test. --- checkers/imports.py | 4 ---- checkers/variables.py | 5 ++--- test/regrtest_data/package_all/__init__.py | 2 +- test/test_func.py | 3 +-- test/test_misc.py | 16 ++++++++++------ 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/checkers/imports.py b/checkers/imports.py index b3cea23..b0a9872 100644 --- a/checkers/imports.py +++ b/checkers/imports.py @@ -149,10 +149,6 @@ MSGS = { 'misplaced-future', 'Python 2.5 and greater require __future__ import to be the \ first non docstring statement in the module.'), - 'W0407': ('Missing submodule: %s', - 'missing-submodule', - 'Used when trying to import a submodule from a package ' - 'and the submodule is missing.'), } class ImportsChecker(BaseChecker): diff --git a/checkers/variables.py b/checkers/variables.py index a0bf796..df049c6 100644 --- a/checkers/variables.py +++ b/checkers/variables.py @@ -194,8 +194,7 @@ builtins. Remember that you should avoid to define new builtins when possible.' # do not print Redefining builtin for additional builtins self.add_message('W0622', args=name, node=stmts[0]) - @check_messages('W0611', 'W0614', 'W0622', 'E0603', 'E0604', - 'missing-submodule') + @check_messages('W0611', 'W0614', 'W0622', 'E0603', 'E0604') def leave_module(self, node): """leave module: check globals """ @@ -229,7 +228,7 @@ builtins. Remember that you should avoid to define new builtins when possible.' try: load_module_from_name(name) except ImportError: - self.add_message('missing-submodule', + self.add_message('E0603', args=elt_name, node=elt) except SyntaxError as exc: diff --git a/test/regrtest_data/package_all/__init__.py b/test/regrtest_data/package_all/__init__.py index a00d416..4e3696b 100644 --- a/test/regrtest_data/package_all/__init__.py +++ b/test/regrtest_data/package_all/__init__.py @@ -1,3 +1,3 @@ -""" Check for missing-submodule """ +""" Check for E0603 for missing submodule found in __all__ """ __revision__ = 1 __all__ = ['notmissing', 'missing'] diff --git a/test/test_func.py b/test/test_func.py index 3b98209..9e4639e 100644 --- a/test/test_func.py +++ b/test/test_func.py @@ -59,12 +59,11 @@ class TestTests(testlib.TestCase): # XXX : no use case for now : 'W0402', # deprecated module 'W0403', # implicit relative import, - 'W0407', # tested in test_misc.py 'W0410', # __future__ import not first statement ] self.assertEqual(todo, rest) else: - self.assertEqual(todo, ['I0001', 'W0407']) + self.assertEqual(todo, ['I0001']) class LintBuiltinModuleTest(LintTestUsingModule): output = join(MSG_DIR, 'builtin_module.txt') diff --git a/test/test_misc.py b/test/test_misc.py index b77510f..e71b26e 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -25,9 +25,6 @@ from astroid import test_utils from pylint.checkers import misc, variables from pylint.testutils import CheckerTestCase, Message, linter -REGR_DATA = os.path.join(os.path.dirname(os.path.abspath(__file__)), - 'regrtest_data') -sys.path.insert(1, REGR_DATA) @contextlib.contextmanager def create_file_backed_module(code): @@ -74,9 +71,16 @@ class MissingSubmoduleTest(CheckerTestCase): CHECKER_CLASS = variables.VariablesChecker def test_package_all(self): - linter.check(os.path.join(REGR_DATA, 'package_all')) - got = linter.reporter.finalize().strip() - self.assertEqual(got, 'W: 3: Missing submodule: missing') + regr_data = os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'regrtest_data') + sys.path.insert(0, regr_data) + try: + linter.check(os.path.join(regr_data, 'package_all')) + got = linter.reporter.finalize().strip() + self.assertEqual(got, "E: 3: Undefined variable name " + "'missing' in __all__") + finally: + sys.path.pop(0) if __name__ == '__main__': unittest_main() -- cgit v1.2.1 From 6158e88a3684aa67215ba809cbb7890a73b057d9 Mon Sep 17 00:00:00 2001 From: cpopa Date: Sat, 18 Jan 2014 00:09:45 +0200 Subject: Use symbolic name. --- checkers/variables.py | 6 ++++-- test/test_func.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/checkers/variables.py b/checkers/variables.py index df049c6..09dc5af 100644 --- a/checkers/variables.py +++ b/checkers/variables.py @@ -220,7 +220,9 @@ builtins. Remember that you should avoid to define new builtins when possible.' continue if elt_name not in node.locals: if not node.package: - self.add_message('E0603', args=elt_name, node=elt) + self.add_message('undefined-all-variable', + args=elt_name, + node=elt) else: basename = os.path.splitext(node.file)[0] if os.path.basename(basename) == '__init__': @@ -228,7 +230,7 @@ builtins. Remember that you should avoid to define new builtins when possible.' try: load_module_from_name(name) except ImportError: - self.add_message('E0603', + self.add_message('undefined-all-variable', args=elt_name, node=elt) except SyntaxError as exc: diff --git a/test/test_func.py b/test/test_func.py index 9e4639e..e8c746d 100644 --- a/test/test_func.py +++ b/test/test_func.py @@ -58,7 +58,7 @@ class TestTests(testlib.TestCase): rest = ['I0001', # XXX : no use case for now : 'W0402', # deprecated module - 'W0403', # implicit relative import, + 'W0403', # implicit relative import 'W0410', # __future__ import not first statement ] self.assertEqual(todo, rest) -- cgit v1.2.1 From 74199d78839eb163f18dd3307aef2b8fb9107c91 Mon Sep 17 00:00:00 2001 From: cpopa Date: Thu, 30 Jan 2014 00:32:13 +0200 Subject: Use file_from_modpath instead of load_module_from_name. --- checkers/variables.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/checkers/variables.py b/checkers/variables.py index 9e8169f..d5bb715 100644 --- a/checkers/variables.py +++ b/checkers/variables.py @@ -22,7 +22,7 @@ from copy import copy import astroid from astroid import are_exclusive, builtin_lookup, AstroidBuildingException -from logilab.common.modutils import load_module_from_name +from logilab.common.modutils import file_from_modpath from pylint.interfaces import IAstroidChecker from pylint.checkers import BaseChecker @@ -228,7 +228,7 @@ builtins. Remember that you should avoid to define new builtins when possible.' if os.path.basename(basename) == '__init__': name = node.name + "." + elt_name try: - load_module_from_name(name) + file_from_modpath(name.split(".")) except ImportError: self.add_message('undefined-all-variable', args=elt_name, -- cgit v1.2.1 From 4670e1eb3845987880f50a305b55a5e674916e09 Mon Sep 17 00:00:00 2001 From: cpopa Date: Tue, 4 Feb 2014 16:42:07 +0200 Subject: Add ChangeLog entry for issue #126. --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index e18fa04..e20d609 100644 --- a/ChangeLog +++ b/ChangeLog @@ -20,6 +20,8 @@ ChangeLog for Pylint * Enhance the check for 'used-before-assignment' to look for 'nonlocal' uses. + * Emit 'undefined-all-variable' if a package's __all__ + variable contains a missing submodule (closes #126). 2013-12-22 -- 1.1.0 * Add new check for use of deprecated pragma directives "pylint:disable-msg" -- cgit v1.2.1