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:
parent
4f996449bf
commit
8ccd18fff3
|
@ -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'"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue