Kaydet (Commit) 86aae6a7 authored tarafından Brett Cannon's avatar Brett Cannon

Issue #19712: Update test.test_importlib.import_ to test/use PEP 451

where appropriate.
üst 010ff584
...@@ -36,7 +36,7 @@ class Using__package__: ...@@ -36,7 +36,7 @@ class Using__package__:
def test_using___package__(self): def test_using___package__(self):
# [__package__] # [__package__]
with util.mock_modules('pkg.__init__', 'pkg.fake') as importer: with self.mock_modules('pkg.__init__', 'pkg.fake') as importer:
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
self.__import__('pkg.fake') self.__import__('pkg.fake')
module = self.__import__('', module = self.__import__('',
...@@ -49,7 +49,7 @@ class Using__package__: ...@@ -49,7 +49,7 @@ class Using__package__:
globals_ = {'__name__': 'pkg.fake', '__path__': []} globals_ = {'__name__': 'pkg.fake', '__path__': []}
if package_as_None: if package_as_None:
globals_['__package__'] = None globals_['__package__'] = None
with util.mock_modules('pkg.__init__', 'pkg.fake') as importer: with self.mock_modules('pkg.__init__', 'pkg.fake') as importer:
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
self.__import__('pkg.fake') self.__import__('pkg.fake')
module = self.__import__('', globals= globals_, module = self.__import__('', globals= globals_,
...@@ -70,11 +70,20 @@ class Using__package__: ...@@ -70,11 +70,20 @@ class Using__package__:
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
self.__import__('', globals, {}, ['relimport'], 1) self.__import__('', globals, {}, ['relimport'], 1)
Frozen_UsingPackage, Source_UsingPackage = util.test_both( class Using__package__PEP302(Using__package__):
Using__package__, __import__=import_util.__import__) mock_modules = util.mock_modules
Frozen_UsingPackagePEP302, Source_UsingPackagePEP302 = util.test_both(
Using__package__PEP302, __import__=import_util.__import__)
class Setting__package__(unittest.TestCase): class Using__package__PEP302(Using__package__):
mock_modules = util.mock_spec
Frozen_UsingPackagePEP451, Source_UsingPackagePEP451 = util.test_both(
Using__package__PEP302, __import__=import_util.__import__)
class Setting__package__:
"""Because __package__ is a new feature, it is not always set by a loader. """Because __package__ is a new feature, it is not always set by a loader.
Import will set it as needed to help with the transition to relying on Import will set it as needed to help with the transition to relying on
...@@ -90,7 +99,7 @@ class Setting__package__(unittest.TestCase): ...@@ -90,7 +99,7 @@ class Setting__package__(unittest.TestCase):
# [top-level] # [top-level]
def test_top_level(self): def test_top_level(self):
with util.mock_modules('top_level') as mock: with self.mock_modules('top_level') as mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
del mock['top_level'].__package__ del mock['top_level'].__package__
module = self.__import__('top_level') module = self.__import__('top_level')
...@@ -98,7 +107,7 @@ class Setting__package__(unittest.TestCase): ...@@ -98,7 +107,7 @@ class Setting__package__(unittest.TestCase):
# [package] # [package]
def test_package(self): def test_package(self):
with util.mock_modules('pkg.__init__') as mock: with self.mock_modules('pkg.__init__') as mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
del mock['pkg'].__package__ del mock['pkg'].__package__
module = self.__import__('pkg') module = self.__import__('pkg')
...@@ -106,13 +115,19 @@ class Setting__package__(unittest.TestCase): ...@@ -106,13 +115,19 @@ class Setting__package__(unittest.TestCase):
# [submodule] # [submodule]
def test_submodule(self): def test_submodule(self):
with util.mock_modules('pkg.__init__', 'pkg.mod') as mock: with self.mock_modules('pkg.__init__', 'pkg.mod') as mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
del mock['pkg.mod'].__package__ del mock['pkg.mod'].__package__
pkg = self.__import__('pkg.mod') pkg = self.__import__('pkg.mod')
module = getattr(pkg, 'mod') module = getattr(pkg, 'mod')
self.assertEqual(module.__package__, 'pkg') self.assertEqual(module.__package__, 'pkg')
class Setting__package__PEP302(Setting__package__, unittest.TestCase):
mock_modules = util.mock_modules
class Setting__package__PEP451(Setting__package__, unittest.TestCase):
mock_modules = util.mock_spec
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -39,6 +39,16 @@ class UseCache: ...@@ -39,6 +39,16 @@ class UseCache:
self.__import__(name) self.__import__(name)
self.assertEqual(cm.exception.name, name) self.assertEqual(cm.exception.name, name)
Frozen_UseCache, Source_UseCache = util.test_both(
UseCache, __import__=import_util.__import__)
class ImportlibUseCache(UseCache, unittest.TestCase):
# Pertinent only to PEP 302; exec_module() doesn't return a module.
__import__ = import_util.__import__[1]
def create_mock(self, *names, return_=None): def create_mock(self, *names, return_=None):
mock = util.mock_modules(*names) mock = util.mock_modules(*names)
original_load = mock.load_module original_load = mock.load_module
...@@ -48,14 +58,6 @@ class UseCache: ...@@ -48,14 +58,6 @@ class UseCache:
mock.load_module = MethodType(load_module, mock) mock.load_module = MethodType(load_module, mock)
return mock return mock
Frozen_UseCache, Source_UseCache = util.test_both(
UseCache, __import__=import_util.__import__)
class ImportlibUseCache(UseCache, unittest.TestCase):
__import__ = import_util.__import__[1]
# __import__ inconsistent between loaders and built-in import when it comes # __import__ inconsistent between loaders and built-in import when it comes
# to when to use the module in sys.modules and when not to. # to when to use the module in sys.modules and when not to.
def test_using_cache_after_loader(self): def test_using_cache_after_loader(self):
......
...@@ -17,7 +17,7 @@ class ReturnValue: ...@@ -17,7 +17,7 @@ class ReturnValue:
def test_return_from_import(self): def test_return_from_import(self):
# [import return] # [import return]
with util.mock_modules('pkg.__init__', 'pkg.module') as importer: with util.mock_spec('pkg.__init__', 'pkg.module') as importer:
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
module = self.__import__('pkg.module') module = self.__import__('pkg.module')
self.assertEqual(module.__name__, 'pkg') self.assertEqual(module.__name__, 'pkg')
......
...@@ -18,23 +18,18 @@ class CallingOrder: ...@@ -18,23 +18,18 @@ class CallingOrder:
def test_first_called(self): def test_first_called(self):
# [first called] # [first called]
mod = 'top_level' mod = 'top_level'
first = util.mock_modules(mod) with util.mock_spec(mod) as first, util.mock_spec(mod) as second:
second = util.mock_modules(mod)
with util.mock_modules(mod) as first, util.mock_modules(mod) as second:
first.modules[mod] = 42
second.modules[mod] = -13
with util.import_state(meta_path=[first, second]): with util.import_state(meta_path=[first, second]):
self.assertEqual(self.__import__(mod), 42) self.assertIs(self.__import__(mod), first.modules[mod])
def test_continuing(self): def test_continuing(self):
# [continuing] # [continuing]
mod_name = 'for_real' mod_name = 'for_real'
with util.mock_modules('nonexistent') as first, \ with util.mock_spec('nonexistent') as first, \
util.mock_modules(mod_name) as second: util.mock_spec(mod_name) as second:
first.find_module = lambda self, fullname, path=None: None first.find_spec = lambda self, fullname, path=None, parent=None: None
second.modules[mod_name] = 42
with util.import_state(meta_path=[first, second]): with util.import_state(meta_path=[first, second]):
self.assertEqual(self.__import__(mod_name), 42) self.assertIs(self.__import__(mod_name), second.modules[mod_name])
def test_empty(self): def test_empty(self):
# Raise an ImportWarning if sys.meta_path is empty. # Raise an ImportWarning if sys.meta_path is empty.
...@@ -61,29 +56,27 @@ class CallSignature: ...@@ -61,29 +56,27 @@ class CallSignature:
[no path]. Otherwise, the value for __path__ is passed in for the 'path' [no path]. Otherwise, the value for __path__ is passed in for the 'path'
argument [path set].""" argument [path set]."""
def log(self, fxn): def log_finder(self, importer):
fxn = getattr(importer, self.finder_name)
log = [] log = []
def wrapper(self, *args, **kwargs): def wrapper(self, *args, **kwargs):
log.append([args, kwargs]) log.append([args, kwargs])
return fxn(*args, **kwargs) return fxn(*args, **kwargs)
return log, wrapper return log, wrapper
def test_no_path(self): def test_no_path(self):
# [no path] # [no path]
mod_name = 'top_level' mod_name = 'top_level'
assert '.' not in mod_name assert '.' not in mod_name
with util.mock_modules(mod_name) as importer: with self.mock_modules(mod_name) as importer:
log, wrapped_call = self.log(importer.find_module) log, wrapped_call = self.log_finder(importer)
importer.find_module = MethodType(wrapped_call, importer) setattr(importer, self.finder_name, MethodType(wrapped_call, importer))
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
self.__import__(mod_name) self.__import__(mod_name)
assert len(log) == 1 assert len(log) == 1
args = log[0][0] args = log[0][0]
kwargs = log[0][1] kwargs = log[0][1]
# Assuming all arguments are positional. # Assuming all arguments are positional.
self.assertEqual(len(args), 2)
self.assertEqual(len(kwargs), 0)
self.assertEqual(args[0], mod_name) self.assertEqual(args[0], mod_name)
self.assertIsNone(args[1]) self.assertIsNone(args[1])
...@@ -93,10 +86,10 @@ class CallSignature: ...@@ -93,10 +86,10 @@ class CallSignature:
mod_name = pkg_name + '.module' mod_name = pkg_name + '.module'
path = [42] path = [42]
assert '.' in mod_name assert '.' in mod_name
with util.mock_modules(pkg_name+'.__init__', mod_name) as importer: with self.mock_modules(pkg_name+'.__init__', mod_name) as importer:
importer.modules[pkg_name].__path__ = path importer.modules[pkg_name].__path__ = path
log, wrapped_call = self.log(importer.find_module) log, wrapped_call = self.log_finder(importer)
importer.find_module = MethodType(wrapped_call, importer) setattr(importer, self.finder_name, MethodType(wrapped_call, importer))
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
self.__import__(mod_name) self.__import__(mod_name)
assert len(log) == 2 assert len(log) == 2
...@@ -107,8 +100,19 @@ class CallSignature: ...@@ -107,8 +100,19 @@ class CallSignature:
self.assertEqual(args[0], mod_name) self.assertEqual(args[0], mod_name)
self.assertIs(args[1], path) self.assertIs(args[1], path)
Frozen_CallSignature, Source_CallSignature = util.test_both( class CallSignaturePEP302(CallSignature):
CallSignature, __import__=import_util.__import__) mock_modules = util.mock_modules
finder_name = 'find_module'
Frozen_CallSignaturePEP302, Source_CallSignaturePEP302 = util.test_both(
CallSignaturePEP302, __import__=import_util.__import__)
class CallSignaturePEP451(CallSignature):
mock_modules = util.mock_spec
finder_name = 'find_spec'
Frozen_CallSignaturePEP451, Source_CallSignaturePEP451 = util.test_both(
CallSignaturePEP451, __import__=import_util.__import__)
if __name__ == '__main__': if __name__ == '__main__':
......
...@@ -11,13 +11,13 @@ class ParentModuleTests: ...@@ -11,13 +11,13 @@ class ParentModuleTests:
"""Importing a submodule should import the parent modules.""" """Importing a submodule should import the parent modules."""
def test_import_parent(self): def test_import_parent(self):
with util.mock_modules('pkg.__init__', 'pkg.module') as mock: with util.mock_spec('pkg.__init__', 'pkg.module') as mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
module = self.__import__('pkg.module') module = self.__import__('pkg.module')
self.assertIn('pkg', sys.modules) self.assertIn('pkg', sys.modules)
def test_bad_parent(self): def test_bad_parent(self):
with util.mock_modules('pkg.module') as mock: with util.mock_spec('pkg.module') as mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
with self.assertRaises(ImportError) as cm: with self.assertRaises(ImportError) as cm:
self.__import__('pkg.module') self.__import__('pkg.module')
...@@ -27,7 +27,7 @@ class ParentModuleTests: ...@@ -27,7 +27,7 @@ class ParentModuleTests:
def __init__(): def __init__():
import pkg.module import pkg.module
1/0 1/0
mock = util.mock_modules('pkg.__init__', 'pkg.module', mock = util.mock_spec('pkg.__init__', 'pkg.module',
module_code={'pkg': __init__}) module_code={'pkg': __init__})
with mock: with mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
...@@ -44,7 +44,7 @@ class ParentModuleTests: ...@@ -44,7 +44,7 @@ class ParentModuleTests:
def __init__(): def __init__():
from . import module from . import module
1/0 1/0
mock = util.mock_modules('pkg.__init__', 'pkg.module', mock = util.mock_spec('pkg.__init__', 'pkg.module',
module_code={'pkg': __init__}) module_code={'pkg': __init__})
with mock: with mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
...@@ -63,7 +63,7 @@ class ParentModuleTests: ...@@ -63,7 +63,7 @@ class ParentModuleTests:
def __init__(): def __init__():
from ..subpkg import module from ..subpkg import module
1/0 1/0
mock = util.mock_modules('pkg.__init__', 'pkg.subpkg.__init__', mock = util.mock_spec('pkg.__init__', 'pkg.subpkg.__init__',
'pkg.subpkg.module', 'pkg.subpkg.module',
module_code={'pkg.subpkg': __init__}) module_code={'pkg.subpkg': __init__})
with mock: with mock:
...@@ -93,9 +93,9 @@ class ParentModuleTests: ...@@ -93,9 +93,9 @@ class ParentModuleTests:
subname = name + '.b' subname = name + '.b'
def module_injection(): def module_injection():
sys.modules[subname] = 'total bunk' sys.modules[subname] = 'total bunk'
mock_modules = util.mock_modules('mod', mock_spec = util.mock_spec('mod',
module_code={'mod': module_injection}) module_code={'mod': module_injection})
with mock_modules as mock: with mock_spec as mock:
with util.import_state(meta_path=[mock]): with util.import_state(meta_path=[mock]):
try: try:
submodule = self.__import__(subname) submodule = self.__import__(subname)
......
...@@ -27,7 +27,7 @@ class FinderTests: ...@@ -27,7 +27,7 @@ class FinderTests:
# Implicitly tests that sys.path_importer_cache is used. # Implicitly tests that sys.path_importer_cache is used.
module = '<test module>' module = '<test module>'
path = '<test path>' path = '<test path>'
importer = util.mock_modules(module) importer = util.mock_spec(module)
with util.import_state(path_importer_cache={path: importer}, with util.import_state(path_importer_cache={path: importer},
path=[path]): path=[path]):
loader = self.machinery.PathFinder.find_module(module) loader = self.machinery.PathFinder.find_module(module)
...@@ -38,7 +38,7 @@ class FinderTests: ...@@ -38,7 +38,7 @@ class FinderTests:
# Implicitly tests that sys.path_importer_cache is used. # Implicitly tests that sys.path_importer_cache is used.
module = '<test module>' module = '<test module>'
path = '<test path>' path = '<test path>'
importer = util.mock_modules(module) importer = util.mock_spec(module)
with util.import_state(path_importer_cache={path: importer}): with util.import_state(path_importer_cache={path: importer}):
loader = self.machinery.PathFinder.find_module(module, [path]) loader = self.machinery.PathFinder.find_module(module, [path])
self.assertIs(loader, importer) self.assertIs(loader, importer)
...@@ -47,7 +47,7 @@ class FinderTests: ...@@ -47,7 +47,7 @@ class FinderTests:
# An empty list should not count as asking for sys.path. # An empty list should not count as asking for sys.path.
module = 'module' module = 'module'
path = '<test path>' path = '<test path>'
importer = util.mock_modules(module) importer = util.mock_spec(module)
with util.import_state(path_importer_cache={path: importer}, with util.import_state(path_importer_cache={path: importer},
path=[path]): path=[path]):
self.assertIsNone(self.machinery.PathFinder.find_module('module', [])) self.assertIsNone(self.machinery.PathFinder.find_module('module', []))
...@@ -57,7 +57,7 @@ class FinderTests: ...@@ -57,7 +57,7 @@ class FinderTests:
# Test that sys.path_importer_cache is set. # Test that sys.path_importer_cache is set.
module = '<test module>' module = '<test module>'
path = '<test path>' path = '<test path>'
importer = util.mock_modules(module) importer = util.mock_spec(module)
hook = import_util.mock_path_hook(path, importer=importer) hook = import_util.mock_path_hook(path, importer=importer)
with util.import_state(path_hooks=[hook]): with util.import_state(path_hooks=[hook]):
loader = self.machinery.PathFinder.find_module(module, [path]) loader = self.machinery.PathFinder.find_module(module, [path])
...@@ -82,7 +82,7 @@ class FinderTests: ...@@ -82,7 +82,7 @@ class FinderTests:
# The empty string should create a finder using the cwd. # The empty string should create a finder using the cwd.
path = '' path = ''
module = '<test module>' module = '<test module>'
importer = util.mock_modules(module) importer = util.mock_spec(module)
hook = import_util.mock_path_hook(os.getcwd(), importer=importer) hook = import_util.mock_path_hook(os.getcwd(), importer=importer)
with util.import_state(path=[path], path_hooks=[hook]): with util.import_state(path=[path], path_hooks=[hook]):
loader = self.machinery.PathFinder.find_module(module) loader = self.machinery.PathFinder.find_module(module)
......
...@@ -64,7 +64,7 @@ class RelativeImports: ...@@ -64,7 +64,7 @@ class RelativeImports:
uncache_names.append(name) uncache_names.append(name)
else: else:
uncache_names.append(name[:-len('.__init__')]) uncache_names.append(name[:-len('.__init__')])
with util.mock_modules(*create) as importer: with util.mock_spec(*create) as importer:
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
for global_ in globals_: for global_ in globals_:
with util.uncache(*uncache_names): with util.uncache(*uncache_names):
......
from contextlib import contextmanager from contextlib import contextmanager
from importlib import util
import os.path import os.path
from test import support from test import support
import unittest import unittest
...@@ -101,9 +102,9 @@ def import_state(**kwargs): ...@@ -101,9 +102,9 @@ def import_state(**kwargs):
setattr(sys, attr, value) setattr(sys, attr, value)
class mock_modules: class _ImporterMock:
"""A mock importer/loader.""" """Base class to help with creating importer mocks."""
def __init__(self, *names, module_code={}): def __init__(self, *names, module_code={}):
self.modules = {} self.modules = {}
...@@ -133,6 +134,19 @@ class mock_modules: ...@@ -133,6 +134,19 @@ class mock_modules:
def __getitem__(self, name): def __getitem__(self, name):
return self.modules[name] return self.modules[name]
def __enter__(self):
self._uncache = uncache(*self.modules.keys())
self._uncache.__enter__()
return self
def __exit__(self, *exc_info):
self._uncache.__exit__(None, None, None)
class mock_modules(_ImporterMock):
"""Importer mock using PEP 302 APIs."""
def find_module(self, fullname, path=None): def find_module(self, fullname, path=None):
if fullname not in self.modules: if fullname not in self.modules:
return None return None
...@@ -152,10 +166,28 @@ class mock_modules: ...@@ -152,10 +166,28 @@ class mock_modules:
raise raise
return self.modules[fullname] return self.modules[fullname]
def __enter__(self): class mock_spec(_ImporterMock):
self._uncache = uncache(*self.modules.keys())
self._uncache.__enter__()
return self
def __exit__(self, *exc_info): """Importer mock using PEP 451 APIs."""
self._uncache.__exit__(None, None, None)
def find_spec(self, fullname, path=None, parent=None):
try:
module = self.modules[fullname]
except KeyError:
return None
is_package = hasattr(module, '__path__')
spec = util.spec_from_file_location(
fullname, module.__file__, loader=self,
submodule_search_locations=getattr(module, '__path__', None))
return spec
def create_module(self, spec):
if spec.name not in self.modules:
raise ImportError
return self.modules[spec.name]
def exec_module(self, module):
try:
self.module_code[module.__spec__.name]()
except KeyError:
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment