summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrett Cannon <brett@python.org>2012-05-13 17:45:09 (GMT)
committerBrett Cannon <brett@python.org>2012-05-13 17:45:09 (GMT)
commitd200bf534b6d97ee607e1071d0cb2d93e4506268 (patch)
tree2aab0e9eb36b8362d0d6ee2afe1e2245b69d1cbf
parent61009468c5be2757c50c9b7bd14582788b83a646 (diff)
downloadcpython-d200bf534b6d97ee607e1071d0cb2d93e4506268.zip
cpython-d200bf534b6d97ee607e1071d0cb2d93e4506268.tar.gz
cpython-d200bf534b6d97ee607e1071d0cb2d93e4506268.tar.bz2
Add importlib.util.resolve_name().
-rw-r--r--Doc/library/importlib.rst16
-rw-r--r--Lib/importlib/test/test_util.py40
-rw-r--r--Lib/importlib/util.py16
-rw-r--r--Misc/NEWS2
4 files changed, 73 insertions, 1 deletions
diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
index 0bc1b65..35a99bf 100644
--- a/Doc/library/importlib.rst
+++ b/Doc/library/importlib.rst
@@ -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,
diff --git a/Lib/importlib/test/test_util.py b/Lib/importlib/test/test_util.py
index 7963e4f..e477f17 100644
--- a/Lib/importlib/test/test_util.py
+++ b/Lib/importlib/test/test_util.py
@@ -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__':
diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
index 7b44fa1..1316437 100644
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -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)
diff --git a/Misc/NEWS b/Misc/NEWS
index 5458385..9adce9f 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.