summaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorÉric Araujo <merwok@netwok.org>2011-10-19 04:46:13 (GMT)
committerÉric Araujo <merwok@netwok.org>2011-10-19 04:46:13 (GMT)
commit8ccd18fff334b9b9a32e9662684f59cac332c524 (patch)
treefc791ef84f973171ca049f21694c6f04c3a62d4e /Lib
parent4f996449bf9364f9c21fa6bfb0e8363e96987179 (diff)
downloadcpython-8ccd18fff334b9b9a32e9662684f59cac332c524.zip
cpython-8ccd18fff334b9b9a32e9662684f59cac332c524.tar.gz
cpython-8ccd18fff334b9b9a32e9662684f59cac332c524.tar.bz2
Expand tests and fix bugs in packaging.util.resolve_name.
The code is still ugly, but at least it works better now. Patches to make it easier to read are welcome, as well as support in #12915.
Diffstat (limited to 'Lib')
-rw-r--r--Lib/packaging/tests/test_util.py72
-rw-r--r--Lib/packaging/util.py21
2 files changed, 60 insertions, 33 deletions
diff --git a/Lib/packaging/tests/test_util.py b/Lib/packaging/tests/test_util.py
index 3d71a96..4d8614a 100644
--- a/Lib/packaging/tests/test_util.py
+++ b/Lib/packaging/tests/test_util.py
@@ -4,6 +4,7 @@ import sys
import time
import logging
import tempfile
+import textwrap
import subprocess
from io import StringIO
@@ -375,35 +376,48 @@ class UtilTestCase(support.EnvironRestorer,
'pkg1.pkg3.pkg6']))
def test_resolve_name(self):
- self.assertIs(str, resolve_name('builtins.str'))
- self.assertEqual(
- UtilTestCase.__name__,
- resolve_name("packaging.tests.test_util.UtilTestCase").__name__)
- self.assertEqual(
- UtilTestCase.test_resolve_name.__name__,
- resolve_name("packaging.tests.test_util.UtilTestCase."
- "test_resolve_name").__name__)
-
- self.assertRaises(ImportError, resolve_name,
- "packaging.tests.test_util.UtilTestCaseNot")
- self.assertRaises(ImportError, resolve_name,
- "packaging.tests.test_util.UtilTestCase."
- "nonexistent_attribute")
-
- def test_import_nested_first_time(self):
- tmp_dir = self.mkdtemp()
- os.makedirs(os.path.join(tmp_dir, 'a', 'b'))
- self.write_file(os.path.join(tmp_dir, 'a', '__init__.py'), '')
- self.write_file(os.path.join(tmp_dir, 'a', 'b', '__init__.py'), '')
- self.write_file(os.path.join(tmp_dir, 'a', 'b', 'c.py'),
- 'class Foo: pass')
-
- try:
- sys.path.append(tmp_dir)
- resolve_name("a.b.c.Foo")
- # assert nothing raised
- finally:
- sys.path.remove(tmp_dir)
+ # test raw module name
+ tmpdir = self.mkdtemp()
+ sys.path.append(tmpdir)
+ self.addCleanup(sys.path.remove, tmpdir)
+ self.write_file((tmpdir, 'hello.py'), '')
+
+ os.makedirs(os.path.join(tmpdir, 'a', 'b'))
+ self.write_file((tmpdir, 'a', '__init__.py'), '')
+ self.write_file((tmpdir, 'a', 'b', '__init__.py'), '')
+ self.write_file((tmpdir, 'a', 'b', 'c.py'), 'class Foo: pass')
+ self.write_file((tmpdir, 'a', 'b', 'd.py'), textwrap.dedent("""\
+ class FooBar:
+ class Bar:
+ def baz(self):
+ pass
+ """))
+
+ # check Python, C and built-in module
+ self.assertEqual(resolve_name('hello').__name__, 'hello')
+ self.assertEqual(resolve_name('_csv').__name__, '_csv')
+ self.assertEqual(resolve_name('sys').__name__, 'sys')
+
+ # test module.attr
+ self.assertIs(resolve_name('builtins.str'), str)
+ self.assertIsNone(resolve_name('hello.__doc__'))
+ self.assertEqual(resolve_name('a.b.c.Foo').__name__, 'Foo')
+ self.assertEqual(resolve_name('a.b.d.FooBar.Bar.baz').__name__, 'baz')
+
+ # error if module not found
+ self.assertRaises(ImportError, resolve_name, 'nonexistent')
+ self.assertRaises(ImportError, resolve_name, 'non.existent')
+ self.assertRaises(ImportError, resolve_name, 'a.no')
+ self.assertRaises(ImportError, resolve_name, 'a.b.no')
+ self.assertRaises(ImportError, resolve_name, 'a.b.no.no')
+ self.assertRaises(ImportError, resolve_name, 'inva-lid')
+
+ # looking up built-in names is not supported
+ self.assertRaises(ImportError, resolve_name, 'str')
+
+ # error if module found but not attr
+ self.assertRaises(ImportError, resolve_name, 'a.b.Spam')
+ self.assertRaises(ImportError, resolve_name, 'a.b.c.Spam')
def test_run_2to3_on_code(self):
content = "print 'test'"
diff --git a/Lib/packaging/util.py b/Lib/packaging/util.py
index f8a8058..2af1149 100644
--- a/Lib/packaging/util.py
+++ b/Lib/packaging/util.py
@@ -630,22 +630,35 @@ def find_packages(paths=(os.curdir,), exclude=()):
def resolve_name(name):
"""Resolve a name like ``module.object`` to an object and return it.
- Raise ImportError if the module or name is not found.
+ This functions supports packages and attributes without depth limitation:
+ ``package.package.module.class.class.function.attr`` is valid input.
+ However, looking up builtins is not directly supported: use
+ ``builtins.name``.
+
+ Raises ImportError if importing the module fails or if one requested
+ attribute is not found.
"""
+ if '.' not in name:
+ # shortcut
+ __import__(name)
+ return sys.modules[name]
+
+ # FIXME clean up this code!
parts = name.split('.')
cursor = len(parts)
module_name = parts[:cursor]
+ ret = ''
while cursor > 0:
try:
ret = __import__('.'.join(module_name))
break
except ImportError:
- if cursor == 0:
- raise
cursor -= 1
module_name = parts[:cursor]
- ret = ''
+
+ if ret == '':
+ raise ImportError(parts[0])
for part in parts[1:]:
try: