summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcpopa <devnull@localhost>2014-01-03 22:16:12 +0200
committercpopa <devnull@localhost>2014-01-03 22:16:12 +0200
commit842ee1710db77e200b248f29f66df5707527e82f (patch)
treeeddb92f9df49c27e4f017ac98a4a829fa5c6acde
parente099a5685de2fd625de831d060d0b4a91ed4481d (diff)
downloadpylint-842ee1710db77e200b248f29f66df5707527e82f.tar.gz
Add missing-submodule check for fixing issue #126.
-rw-r--r--checkers/imports.py4
-rw-r--r--checkers/variables.py25
-rw-r--r--test/regrtest_data/package_all/__init__.py3
-rw-r--r--test/regrtest_data/package_all/notmissing.py2
-rw-r--r--test/test_func.py5
-rw-r--r--test/test_misc.py15
6 files changed, 47 insertions, 7 deletions
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()