summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudiu Popa <pcmanticore@gmail.com>2015-12-06 18:00:01 +0200
committerClaudiu Popa <pcmanticore@gmail.com>2015-12-06 18:00:01 +0200
commitf77f5e36632bf6ea76d044bf14a132ff6e22dbfb (patch)
treef6a34d4946bb7c8f6052b9071dc9ba9930aecd79
parent853726a295a8b4000bbb7ff9032cd1573e5ddf6c (diff)
downloadastroid-git-f77f5e36632bf6ea76d044bf14a132ff6e22dbfb.tar.gz
relative_to_absolute_name will now raise TooManyLevelsError when a relative import is trying to access something beyond the top-level package.
-rw-r--r--ChangeLog3
-rw-r--r--astroid/exceptions.py15
-rw-r--r--astroid/tests/unittest_scoped_nodes.py13
-rw-r--r--astroid/tree/scoped_nodes.py4
4 files changed, 35 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 1b340b2e..acc87506 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -2,6 +2,9 @@ Change log for the astroid package (used to be astng)
=====================================================
--
+ * relative_to_absolute_name or methods calling it will now raise
+ TooManyLevelsError when a relative import was trying to
+ access something beyond the top-level package.
* AstroidBuildingException is now AstroidBuildingError. The first
name will exist until astroid 2.0.
diff --git a/astroid/exceptions.py b/astroid/exceptions.py
index 9d57058c..21e9b61f 100644
--- a/astroid/exceptions.py
+++ b/astroid/exceptions.py
@@ -58,6 +58,21 @@ class AstroidImportError(AstroidBuildingError):
"""Exception class used when a module can't be imported by astroid."""
+class TooManyLevelsError(AstroidImportError):
+ """Exception class which is raised when a relative import was beyond the top-level.
+
+ Standard attributes:
+ level: The level which was attempted.
+ name: the name of the module on which the relative import was attempted.
+ """
+ level = None
+ name = None
+
+ def __init__(self, message='Relative import with too many levels '
+ '({level}) for module {name!r}', **kws):
+ super(TooManyLevelsError, self).__init__(message, **kws)
+
+
class AstroidSyntaxError(AstroidBuildingError):
"""Exception class used when a module can't be parsed."""
diff --git a/astroid/tests/unittest_scoped_nodes.py b/astroid/tests/unittest_scoped_nodes.py
index b66e83d5..8467099c 100644
--- a/astroid/tests/unittest_scoped_nodes.py
+++ b/astroid/tests/unittest_scoped_nodes.py
@@ -35,6 +35,7 @@ from astroid.exceptions import (
InferenceError, AttributeInferenceError,
NoDefault, ResolveError, MroError,
InconsistentMroError, DuplicateBasesError,
+ TooManyLevelsError,
)
from astroid.interpreter.objects import (
Instance, BoundMethod, UnboundMethod, Generator
@@ -165,6 +166,18 @@ class ModuleNodeTest(ModuleLoader, unittest.TestCase):
modname = mod.relative_to_absolute_name('', 1)
self.assertEqual(modname, 'very.multi')
+ def test_relative_to_absolute_name_beyond_top_level(self):
+ mod = nodes.Module('a.b.c', '')
+ mod.package = True
+ for level in (5, 4):
+ with self.assertRaises(TooManyLevelsError) as cm:
+ mod.relative_to_absolute_name('test', level)
+
+ expected = ("Relative import with too many levels "
+ "({level}) for module {name!r}".format(
+ level=level - 1, name=mod.name))
+ self.assertEqual(expected, str(cm.exception))
+
def test_import_1(self):
data = '''from . import subpackage'''
sys.path.insert(0, resources.find('data'))
diff --git a/astroid/tree/scoped_nodes.py b/astroid/tree/scoped_nodes.py
index 6aa5948c..ae8da65f 100644
--- a/astroid/tree/scoped_nodes.py
+++ b/astroid/tree/scoped_nodes.py
@@ -541,6 +541,10 @@ class Module(LocalsDictNodeNG):
if level:
if self.package:
level = level - 1
+ if level and self.name.count('.') < level:
+ raise exceptions.TooManyLevelsError(
+ level=level, name=self.name)
+
package_name = self.name.rsplit('.', level)[0]
elif self.package:
package_name = self.name