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.
This commit is contained in:
Éric Araujo 2011-10-19 06:46:13 +02:00
parent 4f996449bf
commit 8ccd18fff3
2 changed files with 57 additions and 30 deletions

View File

@ -4,6 +4,7 @@ import sys
import time import time
import logging import logging
import tempfile import tempfile
import textwrap
import subprocess import subprocess
from io import StringIO from io import StringIO
@ -375,35 +376,48 @@ class UtilTestCase(support.EnvironRestorer,
'pkg1.pkg3.pkg6'])) 'pkg1.pkg3.pkg6']))
def test_resolve_name(self): def test_resolve_name(self):
self.assertIs(str, resolve_name('builtins.str')) # test raw module name
self.assertEqual( tmpdir = self.mkdtemp()
UtilTestCase.__name__, sys.path.append(tmpdir)
resolve_name("packaging.tests.test_util.UtilTestCase").__name__) self.addCleanup(sys.path.remove, tmpdir)
self.assertEqual( self.write_file((tmpdir, 'hello.py'), '')
UtilTestCase.test_resolve_name.__name__,
resolve_name("packaging.tests.test_util.UtilTestCase."
"test_resolve_name").__name__)
self.assertRaises(ImportError, resolve_name, os.makedirs(os.path.join(tmpdir, 'a', 'b'))
"packaging.tests.test_util.UtilTestCaseNot") self.write_file((tmpdir, 'a', '__init__.py'), '')
self.assertRaises(ImportError, resolve_name, self.write_file((tmpdir, 'a', 'b', '__init__.py'), '')
"packaging.tests.test_util.UtilTestCase." self.write_file((tmpdir, 'a', 'b', 'c.py'), 'class Foo: pass')
"nonexistent_attribute") self.write_file((tmpdir, 'a', 'b', 'd.py'), textwrap.dedent("""\
class FooBar:
class Bar:
def baz(self):
pass
"""))
def test_import_nested_first_time(self): # check Python, C and built-in module
tmp_dir = self.mkdtemp() self.assertEqual(resolve_name('hello').__name__, 'hello')
os.makedirs(os.path.join(tmp_dir, 'a', 'b')) self.assertEqual(resolve_name('_csv').__name__, '_csv')
self.write_file(os.path.join(tmp_dir, 'a', '__init__.py'), '') self.assertEqual(resolve_name('sys').__name__, 'sys')
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: # test module.attr
sys.path.append(tmp_dir) self.assertIs(resolve_name('builtins.str'), str)
resolve_name("a.b.c.Foo") self.assertIsNone(resolve_name('hello.__doc__'))
# assert nothing raised self.assertEqual(resolve_name('a.b.c.Foo').__name__, 'Foo')
finally: self.assertEqual(resolve_name('a.b.d.FooBar.Bar.baz').__name__, 'baz')
sys.path.remove(tmp_dir)
# 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): def test_run_2to3_on_code(self):
content = "print 'test'" content = "print 'test'"

View File

@ -630,22 +630,35 @@ def find_packages(paths=(os.curdir,), exclude=()):
def resolve_name(name): def resolve_name(name):
"""Resolve a name like ``module.object`` to an object and return it. """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('.') parts = name.split('.')
cursor = len(parts) cursor = len(parts)
module_name = parts[:cursor] module_name = parts[:cursor]
ret = ''
while cursor > 0: while cursor > 0:
try: try:
ret = __import__('.'.join(module_name)) ret = __import__('.'.join(module_name))
break break
except ImportError: except ImportError:
if cursor == 0:
raise
cursor -= 1 cursor -= 1
module_name = parts[:cursor] module_name = parts[:cursor]
ret = ''
if ret == '':
raise ImportError(parts[0])
for part in parts[1:]: for part in parts[1:]:
try: try: