Add importlib.util.resolve_name().

This commit is contained in:
Brett Cannon 2012-05-13 13:45:09 -04:00
parent 61009468c5
commit d200bf534b
4 changed files with 73 additions and 1 deletions

View File

@ -737,6 +737,22 @@ find and load modules.
This module contains the various objects that help in the construction of
an :term:`importer`.
.. function:: resolve_name(name, package)
Resolve a relative module name to an absolute one.
If **name** has no leading dots, then **name** is simply returned. This
allows for usage such as
``importlib.util.resolve_name('sys', __package__)`` without doing a
check to see if the **package** argument is needed.
:exc:`ValueError` is raised if **name** is a relative module name but
package is a false value (e.g. ``None`` or the empty string).
:exc:`ValueError` is also raised a relative name would escape its containing
package (e.g. requesting ``..bacon`` from within the ``spam`` package).
.. versionadded:: 3.3
.. decorator:: module_for_loader
A :term:`decorator` for a :term:`loader` method,

View File

@ -161,9 +161,47 @@ class SetPackageTests(unittest.TestCase):
self.assertEqual(wrapped.__name__, fxn.__name__)
self.assertEqual(wrapped.__qualname__, fxn.__qualname__)
class ResolveNameTests(unittest.TestCase):
"""Tests importlib.util.resolve_name()."""
def test_absolute(self):
# bacon
self.assertEqual('bacon', util.resolve_name('bacon', None))
def test_aboslute_within_package(self):
# bacon in spam
self.assertEqual('bacon', util.resolve_name('bacon', 'spam'))
def test_no_package(self):
# .bacon in ''
with self.assertRaises(ValueError):
util.resolve_name('.bacon', '')
def test_in_package(self):
# .bacon in spam
self.assertEqual('spam.eggs.bacon',
util.resolve_name('.bacon', 'spam.eggs'))
def test_other_package(self):
# ..bacon in spam.bacon
self.assertEqual('spam.bacon',
util.resolve_name('..bacon', 'spam.eggs'))
def test_escape(self):
# ..bacon in spam
with self.assertRaises(ValueError):
util.resolve_name('..bacon', 'spam')
def test_main():
from test import support
support.run_unittest(ModuleForLoaderTests, SetPackageTests)
support.run_unittest(
ModuleForLoaderTests,
SetPackageTests,
ResolveNameTests
)
if __name__ == '__main__':

View File

@ -3,3 +3,19 @@
from ._bootstrap import module_for_loader
from ._bootstrap import set_loader
from ._bootstrap import set_package
from ._bootstrap import _resolve_name
def resolve_name(name, package):
"""Resolve a relative module name to an absolute one."""
if not name.startswith('.'):
return name
elif not package:
raise ValueError('{!r} is not a relative name '
'(no leading dot)'.format(name))
level = 0
for character in name:
if character != '.':
break
level += 1
return _resolve_name(name[level:], package, level)

View File

@ -23,6 +23,8 @@ Core and Builtins
Library
-------
- Add importlib.util.resolve_name().
- Issue #14366: Support lzma compression in zip files.
Patch by Serhiy Storchaka.