diff options
author | Claudiu Popa <pcmanticore@gmail.com> | 2015-12-06 18:00:01 +0200 |
---|---|---|
committer | Claudiu Popa <pcmanticore@gmail.com> | 2015-12-06 18:00:01 +0200 |
commit | 7c7aa15f200df3e4ab7b83aa8402ddcfb7458846 (patch) | |
tree | c95f6b112a0447669de214fa9d3f517a21e05124 | |
parent | 433a5b874cb8bff40c26451a75586be512707bab (diff) | |
download | astroid-git-7c7aa15f200df3e4ab7b83aa8402ddcfb7458846.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-- | ChangeLog | 3 | ||||
-rw-r--r-- | astroid/exceptions.py | 15 | ||||
-rw-r--r-- | astroid/scoped_nodes.py | 4 | ||||
-rw-r--r-- | astroid/tests/unittest_scoped_nodes.py | 13 |
4 files changed, 35 insertions, 0 deletions
@@ -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 993e4b15..3cfadbd2 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/scoped_nodes.py b/astroid/scoped_nodes.py index de4b394e..25d28aed 100644 --- a/astroid/scoped_nodes.py +++ b/astroid/scoped_nodes.py @@ -442,6 +442,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 diff --git a/astroid/tests/unittest_scoped_nodes.py b/astroid/tests/unittest_scoped_nodes.py index 6f215e47..d49154dc 100644 --- a/astroid/tests/unittest_scoped_nodes.py +++ b/astroid/tests/unittest_scoped_nodes.py @@ -32,6 +32,7 @@ from astroid.exceptions import ( InferenceError, AttributeInferenceError, NoDefault, ResolveError, MroError, InconsistentMroError, DuplicateBasesError, + TooManyLevelsError, ) from astroid.bases import ( BUILTINS, Instance, @@ -160,6 +161,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')) |