Issue 19944: Fix importlib.find_spec() so it imports parents as needed.

The function is also moved to importlib.util.
This commit is contained in:
Eric Snow 2014-01-25 15:32:46 -07:00
parent 128ee220e2
commit 6029e08691
11 changed files with 292 additions and 230 deletions

View file

@ -4,7 +4,6 @@ frozen_init, source_init = util.import_importlib('importlib')
frozen_util, source_util = util.import_importlib('importlib.util')
frozen_machinery, source_machinery = util.import_importlib('importlib.machinery')
from contextlib import contextmanager
import os.path
import sys
from test import support
@ -13,37 +12,6 @@ import unittest
import warnings
@contextmanager
def temp_module(name, content='', *, pkg=False):
conflicts = [n for n in sys.modules if n.partition('.')[0] == name]
with support.temp_cwd(None) as cwd:
with util.uncache(name, *conflicts):
with support.DirsOnSysPath(cwd):
frozen_init.invalidate_caches()
location = os.path.join(cwd, name)
if pkg:
modpath = os.path.join(location, '__init__.py')
os.mkdir(name)
else:
modpath = location + '.py'
if content is None:
# Make sure the module file gets created.
content = ''
if content is not None:
# not a namespace package
with open(modpath, 'w') as modfile:
modfile.write(content)
yield location
def submodule(parent, name, pkg_dir, content=''):
path = os.path.join(pkg_dir, name + '.py')
with open(path, 'w') as subfile:
subfile.write(content)
return '{}.{}'.format(parent, name), path
class ImportModuleTests:
"""Test importlib.import_module."""
@ -210,121 +178,6 @@ class Source_FindLoaderTests(FindLoaderTests, unittest.TestCase):
init = source_init
class FindSpecTests:
class FakeMetaFinder:
@staticmethod
def find_spec(name, path=None, target=None): return name, path, target
def test_sys_modules(self):
name = 'some_mod'
with util.uncache(name):
module = types.ModuleType(name)
loader = 'a loader!'
spec = self.machinery.ModuleSpec(name, loader)
module.__loader__ = loader
module.__spec__ = spec
sys.modules[name] = module
found = self.init.find_spec(name)
self.assertEqual(found, spec)
def test_sys_modules_without___loader__(self):
name = 'some_mod'
with util.uncache(name):
module = types.ModuleType(name)
del module.__loader__
loader = 'a loader!'
spec = self.machinery.ModuleSpec(name, loader)
module.__spec__ = spec
sys.modules[name] = module
found = self.init.find_spec(name)
self.assertEqual(found, spec)
def test_sys_modules_spec_is_None(self):
name = 'some_mod'
with util.uncache(name):
module = types.ModuleType(name)
module.__spec__ = None
sys.modules[name] = module
with self.assertRaises(ValueError):
self.init.find_spec(name)
def test_sys_modules_loader_is_None(self):
name = 'some_mod'
with util.uncache(name):
module = types.ModuleType(name)
spec = self.machinery.ModuleSpec(name, None)
module.__spec__ = spec
sys.modules[name] = module
found = self.init.find_spec(name)
self.assertEqual(found, spec)
def test_sys_modules_spec_is_not_set(self):
name = 'some_mod'
with util.uncache(name):
module = types.ModuleType(name)
try:
del module.__spec__
except AttributeError:
pass
sys.modules[name] = module
with self.assertRaises(ValueError):
self.init.find_spec(name)
def test_success(self):
name = 'some_mod'
with util.uncache(name):
with util.import_state(meta_path=[self.FakeMetaFinder]):
self.assertEqual((name, None, None),
self.init.find_spec(name))
def test_success_path(self):
# Searching on a path should work.
name = 'some_mod'
path = 'path to some place'
with util.uncache(name):
with util.import_state(meta_path=[self.FakeMetaFinder]):
self.assertEqual((name, path, None),
self.init.find_spec(name, path))
def test_nothing(self):
# None is returned upon failure to find a loader.
self.assertIsNone(self.init.find_spec('nevergoingtofindthismodule'))
def test_find_submodule(self):
name = 'spam'
subname = 'ham'
with temp_module(name, pkg=True) as pkg_dir:
fullname, _ = submodule(name, subname, pkg_dir)
spec = self.init.find_spec(fullname, [pkg_dir])
self.assertIsNot(spec, None)
self.assertNotIn(name, sorted(sys.modules))
# Ensure successive calls behave the same.
spec_again = self.init.find_spec(fullname, [pkg_dir])
self.assertEqual(spec_again, spec)
def test_find_submodule_missing_path(self):
name = 'spam'
subname = 'ham'
with temp_module(name, pkg=True) as pkg_dir:
fullname, _ = submodule(name, subname, pkg_dir)
spec = self.init.find_spec(fullname)
self.assertIs(spec, None)
self.assertNotIn(name, sorted(sys.modules))
# Ensure successive calls behave the same.
spec = self.init.find_spec(fullname)
self.assertIs(spec, None)
class Frozen_FindSpecTests(FindSpecTests, unittest.TestCase):
init = frozen_init
machinery = frozen_machinery
class Source_FindSpecTests(FindSpecTests, unittest.TestCase):
init = source_init
machinery = source_machinery
class ReloadTests:
"""Test module reloading for builtin and extension modules."""
@ -484,8 +337,8 @@ class ReloadTests:
# See #19851.
name = 'spam'
subname = 'ham'
with temp_module(name, pkg=True) as pkg_dir:
fullname, _ = submodule(name, subname, pkg_dir)
with util.temp_module(name, pkg=True) as pkg_dir:
fullname, _ = util.submodule(name, subname, pkg_dir)
ham = self.init.import_module(fullname)
reloaded = self.init.reload(ham)
self.assertIs(reloaded, ham)