summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <cpopa@cloudbasesolutions.com>2015-07-14 16:22:00 +0300
committerClaudiu Popa <cpopa@cloudbasesolutions.com>2015-07-14 16:22:00 +0300
commit72cd3b2d573b6a1331d2cfd4c52f230da76f8f84 (patch)
tree0d77076cbbe52c0802db34360a42c6853ae0cc5e
parentc90eae70b2d8974027b749f6996488a0b1a8903b (diff)
downloadpylint-72cd3b2d573b6a1331d2cfd4c52f230da76f8f84.tar.gz
Improve detection of relative imports in non-packages, as well as importing missing modules with a relative import from a package.
The change improves how relative imports are shown when they are missing, with the absolute name, instead of the relative one.
-rw-r--r--ChangeLog4
-rw-r--r--pylint/checkers/imports.py24
-rw-r--r--pylint/checkers/variables.py2
-rw-r--r--pylint/test/functional/import_error.py2
-rw-r--r--pylint/test/functional/import_error.txt5
-rw-r--r--pylint/test/functional/no_name_in_module.py4
-rw-r--r--pylint/test/functional/no_name_in_module.txt4
-rw-r--r--pylint/test/test_functional.py1
-rw-r--r--pylint/test/test_regr.py2
9 files changed, 39 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 0e59c22..7a9dfa6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -219,6 +219,10 @@ ChangeLog for Pylint
* ignored-modules can work with qualified names as well as with Unix pattern
matching for recursive ignoring. Closes issues #244.
+
+ * Improve detection of relative imports in non-packages, as well as importing
+ missing modules with a relative import from a package.
+
diff --git a/pylint/checkers/imports.py b/pylint/checkers/imports.py
index 9e2af7e..b45cabc 100644
--- a/pylint/checkers/imports.py
+++ b/pylint/checkers/imports.py
@@ -33,6 +33,23 @@ from pylint.checkers import BaseChecker
from pylint.checkers.utils import check_messages, node_ignores_exception
+def _get_import_name(importnode, modname):
+ """Get a prepared module name from the given import node
+
+ In the case of relative imports, this will return the
+ absolute qualified module name, which might be useful
+ for debugging. Otherwise, the initial module name
+ is returned unchanged.
+ """
+ if isinstance(importnode, astroid.From):
+ if importnode.level:
+ root = importnode.root()
+ if isinstance(root, astroid.Module):
+ modname = root.relative_to_absolute_name(
+ modname, level=importnode.level)
+ return modname
+
+
def get_first_import(node, context, name, base, level):
"""return the node where [base.]<name> is imported or None if not found
"""
@@ -280,11 +297,12 @@ given file (report RP0402 must not be disabled)'}
try:
return importnode.do_import_module(modname)
except astroid.InferenceError as ex:
+ dotted_modname = _get_import_name(importnode, modname)
if str(ex) != modname:
- args = '%r (%s)' % (modname, ex)
+ args = '%r (%s)' % (dotted_modname, ex)
else:
- args = repr(modname)
-
+ args = repr(dotted_modname)
+
for submodule in self._qualified_names(modname):
if submodule in self._ignored_modules:
return None
diff --git a/pylint/checkers/variables.py b/pylint/checkers/variables.py
index 3156f6f..2821283 100644
--- a/pylint/checkers/variables.py
+++ b/pylint/checkers/variables.py
@@ -1009,7 +1009,7 @@ builtins. Remember that you should avoid to define new builtins when possible.'
name_parts = node.modname.split('.')
level = getattr(node, 'level', None)
try:
- module = node.root().import_module(name_parts[0], level=level)
+ module = node.do_import_module(name_parts[0])
except Exception:
return
module = self._check_module_attrs(node, module, name_parts[1:])
diff --git a/pylint/test/functional/import_error.py b/pylint/test/functional/import_error.py
index f7a024d..b715377 100644
--- a/pylint/test/functional/import_error.py
+++ b/pylint/test/functional/import_error.py
@@ -32,3 +32,5 @@ try:
import really_missing
except ImportError:
pass
+
+from .collections import missing # [import-error]
diff --git a/pylint/test/functional/import_error.txt b/pylint/test/functional/import_error.txt
index 0602d2a..82ca0d4 100644
--- a/pylint/test/functional/import_error.txt
+++ b/pylint/test/functional/import_error.txt
@@ -1,2 +1,3 @@
-import-error:3::Unable to import 'totally_missing'
-import-error:16::Unable to import 'maybe_missing_2'
+import-error:3::"Unable to import 'totally_missing'"
+import-error:16::"Unable to import 'maybe_missing_2'"
+import-error:36::"Unable to import 'functional.collections'"
diff --git a/pylint/test/functional/no_name_in_module.py b/pylint/test/functional/no_name_in_module.py
index a59327b..47e8c5f 100644
--- a/pylint/test/functional/no_name_in_module.py
+++ b/pylint/test/functional/no_name_in_module.py
@@ -60,3 +60,7 @@ try:
import collections.please_dont_emit
except Exception:
pass
+
+from .no_self_use import Super
+from .no_self_use import lala # [no-name-in-module]
+from .no_self_use.bla import lala1 # [no-name-in-module]
diff --git a/pylint/test/functional/no_name_in_module.txt b/pylint/test/functional/no_name_in_module.txt
index dd78c1b..aa26791 100644
--- a/pylint/test/functional/no_name_in_module.txt
+++ b/pylint/test/functional/no_name_in_module.txt
@@ -8,4 +8,6 @@ no-name-in-module:23::No name 'compiile' in module 're'
no-name-in-module:23::No name 'findiiter' in module 're'
pointless-statement:26::Statement seems to have no effect
no-name-in-module:34::No name 'anything' in module 'collections'
-no-name-in-module:44::No name 'indeed_missing' in module 'collections' \ No newline at end of file
+no-name-in-module:44::No name 'indeed_missing' in module 'collections'
+no-name-in-module:65::No name 'lala' in module 'functional.no_self_use'
+no-name-in-module:66::No name 'bla' in module 'functional.no_self_use' \ No newline at end of file
diff --git a/pylint/test/test_functional.py b/pylint/test/test_functional.py
index ddf737d..e9d6a9a 100644
--- a/pylint/test/test_functional.py
+++ b/pylint/test/test_functional.py
@@ -1,5 +1,4 @@
"""Functional full-module tests for PyLint."""
-from __future__ import unicode_literals
import csv
import collections
import io
diff --git a/pylint/test/test_regr.py b/pylint/test/test_regr.py
index 34b43f6..94085c3 100644
--- a/pylint/test/test_regr.py
+++ b/pylint/test/test_regr.py
@@ -139,7 +139,7 @@ class NonRegrTC(unittest.TestCase):
self.assertEqual(got, "")
def test_no_context_file(self):
- expected = "E: 5: No name 'missing' in module ''\n"
+ expected = "Unused import missing"
linter.check(join(REGR_DATA, 'bad_package'))
got = linter.reporter.finalize().strip()
self.assertIn(expected, got)