Issue #19721: Consolidate test_importlib utility code into a single

module.
This commit is contained in:
Brett Cannon 2014-05-09 14:32:57 -04:00
parent 91795c8e34
commit 732ac654c8
25 changed files with 249 additions and 270 deletions

View file

@ -1,6 +1,5 @@
from .. import abc
from .. import util
from . import util as builtin_util
frozen_machinery, source_machinery = util.import_importlib('importlib.machinery')
@ -8,14 +7,15 @@
import unittest
@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module')
class FindSpecTests(abc.FinderTests):
"""Test find_spec() for built-in modules."""
def test_module(self):
# Common case.
with util.uncache(builtin_util.NAME):
found = self.machinery.BuiltinImporter.find_spec(builtin_util.NAME)
with util.uncache(util.BUILTINS.good_name):
found = self.machinery.BuiltinImporter.find_spec(util.BUILTINS.good_name)
self.assertTrue(found)
self.assertEqual(found.origin, 'built-in')
@ -39,8 +39,8 @@ def test_failure(self):
def test_ignore_path(self):
# The value for 'path' should always trigger a failed import.
with util.uncache(builtin_util.NAME):
spec = self.machinery.BuiltinImporter.find_spec(builtin_util.NAME,
with util.uncache(util.BUILTINS.good_name):
spec = self.machinery.BuiltinImporter.find_spec(util.BUILTINS.good_name,
['pkg'])
self.assertIsNone(spec)
@ -48,14 +48,15 @@ def test_ignore_path(self):
machinery=[frozen_machinery, source_machinery])
@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module')
class FinderTests(abc.FinderTests):
"""Test find_module() for built-in modules."""
def test_module(self):
# Common case.
with util.uncache(builtin_util.NAME):
found = self.machinery.BuiltinImporter.find_module(builtin_util.NAME)
with util.uncache(util.BUILTINS.good_name):
found = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name)
self.assertTrue(found)
self.assertTrue(hasattr(found, 'load_module'))
@ -72,8 +73,8 @@ def test_failure(self):
def test_ignore_path(self):
# The value for 'path' should always trigger a failed import.
with util.uncache(builtin_util.NAME):
loader = self.machinery.BuiltinImporter.find_module(builtin_util.NAME,
with util.uncache(util.BUILTINS.good_name):
loader = self.machinery.BuiltinImporter.find_module(util.BUILTINS.good_name,
['pkg'])
self.assertIsNone(loader)

View file

@ -1,6 +1,5 @@
from .. import abc
from .. import util
from . import util as builtin_util
frozen_machinery, source_machinery = util.import_importlib('importlib.machinery')
@ -8,7 +7,7 @@
import types
import unittest
@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module')
class LoaderTests(abc.LoaderTests):
"""Test load_module() for built-in modules."""
@ -29,8 +28,8 @@ def load_module(self, name):
def test_module(self):
# Common case.
with util.uncache(builtin_util.NAME):
module = self.load_module(builtin_util.NAME)
with util.uncache(util.BUILTINS.good_name):
module = self.load_module(util.BUILTINS.good_name)
self.verify(module)
# Built-in modules cannot be a package.
@ -41,9 +40,9 @@ def test_module(self):
def test_module_reuse(self):
# Test that the same module is used in a reload.
with util.uncache(builtin_util.NAME):
module1 = self.load_module(builtin_util.NAME)
module2 = self.load_module(builtin_util.NAME)
with util.uncache(util.BUILTINS.good_name):
module1 = self.load_module(util.BUILTINS.good_name)
module2 = self.load_module(util.BUILTINS.good_name)
self.assertIs(module1, module2)
def test_unloadable(self):
@ -70,32 +69,34 @@ def test_already_imported(self):
machinery=[frozen_machinery, source_machinery])
@unittest.skipIf(util.BUILTINS.good_name is None, 'no reasonable builtin module')
class InspectLoaderTests:
"""Tests for InspectLoader methods for BuiltinImporter."""
def test_get_code(self):
# There is no code object.
result = self.machinery.BuiltinImporter.get_code(builtin_util.NAME)
result = self.machinery.BuiltinImporter.get_code(util.BUILTINS.good_name)
self.assertIsNone(result)
def test_get_source(self):
# There is no source.
result = self.machinery.BuiltinImporter.get_source(builtin_util.NAME)
result = self.machinery.BuiltinImporter.get_source(util.BUILTINS.good_name)
self.assertIsNone(result)
def test_is_package(self):
# Cannot be a package.
result = self.machinery.BuiltinImporter.is_package(builtin_util.NAME)
result = self.machinery.BuiltinImporter.is_package(util.BUILTINS.good_name)
self.assertTrue(not result)
@unittest.skipIf(util.BUILTINS.bad_name is None, 'all modules are built in')
def test_not_builtin(self):
# Modules not built-in should raise ImportError.
for meth_name in ('get_code', 'get_source', 'is_package'):
method = getattr(self.machinery.BuiltinImporter, meth_name)
with self.assertRaises(ImportError) as cm:
method(builtin_util.BAD_NAME)
self.assertRaises(builtin_util.BAD_NAME)
method(util.BUILTINS.bad_name)
self.assertRaises(util.BUILTINS.bad_name)
Frozen_InspectLoaderTests, Source_InspectLoaderTests = util.test_both(
InspectLoaderTests,

View file

@ -1,7 +0,0 @@
import sys
assert 'errno' in sys.builtin_module_names
NAME = 'errno'
assert 'importlib' not in sys.builtin_module_names
BAD_NAME = 'importlib'

View file

@ -4,22 +4,21 @@
import unittest
from .. import util
from . import util as ext_util
frozen_machinery, source_machinery = util.import_importlib('importlib.machinery')
# XXX find_spec tests
@unittest.skipIf(ext_util.FILENAME is None, '_testcapi not available')
@unittest.skipIf(util.EXTENSIONS.filename is None, '_testcapi not available')
@util.case_insensitive_tests
class ExtensionModuleCaseSensitivityTest:
def find_module(self):
good_name = ext_util.NAME
good_name = util.EXTENSIONS.name
bad_name = good_name.upper()
assert good_name != bad_name
finder = self.machinery.FileFinder(ext_util.PATH,
finder = self.machinery.FileFinder(util.EXTENSIONS.path,
(self.machinery.ExtensionFileLoader,
self.machinery.EXTENSION_SUFFIXES))
return finder.find_module(bad_name)

View file

@ -1,8 +1,7 @@
from .. import abc
from .. import util as test_util
from . import util
from .. import util
machinery = test_util.import_importlib('importlib.machinery')
machinery = util.import_importlib('importlib.machinery')
import unittest
import warnings
@ -14,7 +13,7 @@ class FinderTests(abc.FinderTests):
"""Test the finder for extension modules."""
def find_module(self, fullname):
importer = self.machinery.FileFinder(util.PATH,
importer = self.machinery.FileFinder(util.EXTENSIONS.path,
(self.machinery.ExtensionFileLoader,
self.machinery.EXTENSION_SUFFIXES))
with warnings.catch_warnings():
@ -22,7 +21,7 @@ def find_module(self, fullname):
return importer.find_module(fullname)
def test_module(self):
self.assertTrue(self.find_module(util.NAME))
self.assertTrue(self.find_module(util.EXTENSIONS.name))
# No extension module as an __init__ available for testing.
test_package = test_package_in_package = None
@ -36,7 +35,7 @@ def test_module(self):
def test_failure(self):
self.assertIsNone(self.find_module('asdfjkl;'))
Frozen_FinderTests, Source_FinderTests = test_util.test_both(
Frozen_FinderTests, Source_FinderTests = util.test_both(
FinderTests, machinery=machinery)

View file

@ -1,4 +1,3 @@
from . import util as ext_util
from .. import abc
from .. import util
@ -15,8 +14,8 @@ class LoaderTests(abc.LoaderTests):
"""Test load_module() for extension modules."""
def setUp(self):
self.loader = self.machinery.ExtensionFileLoader(ext_util.NAME,
ext_util.FILEPATH)
self.loader = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
util.EXTENSIONS.file_path)
def load_module(self, fullname):
return self.loader.load_module(fullname)
@ -29,23 +28,23 @@ def test_load_module_API(self):
self.load_module('XXX')
def test_equality(self):
other = self.machinery.ExtensionFileLoader(ext_util.NAME,
ext_util.FILEPATH)
other = self.machinery.ExtensionFileLoader(util.EXTENSIONS.name,
util.EXTENSIONS.file_path)
self.assertEqual(self.loader, other)
def test_inequality(self):
other = self.machinery.ExtensionFileLoader('_' + ext_util.NAME,
ext_util.FILEPATH)
other = self.machinery.ExtensionFileLoader('_' + util.EXTENSIONS.name,
util.EXTENSIONS.file_path)
self.assertNotEqual(self.loader, other)
def test_module(self):
with util.uncache(ext_util.NAME):
module = self.load_module(ext_util.NAME)
for attr, value in [('__name__', ext_util.NAME),
('__file__', ext_util.FILEPATH),
with util.uncache(util.EXTENSIONS.name):
module = self.load_module(util.EXTENSIONS.name)
for attr, value in [('__name__', util.EXTENSIONS.name),
('__file__', util.EXTENSIONS.file_path),
('__package__', '')]:
self.assertEqual(getattr(module, attr), value)
self.assertIn(ext_util.NAME, sys.modules)
self.assertIn(util.EXTENSIONS.name, sys.modules)
self.assertIsInstance(module.__loader__,
self.machinery.ExtensionFileLoader)
@ -56,9 +55,9 @@ def test_module(self):
test_lacking_parent = None
def test_module_reuse(self):
with util.uncache(ext_util.NAME):
module1 = self.load_module(ext_util.NAME)
module2 = self.load_module(ext_util.NAME)
with util.uncache(util.EXTENSIONS.name):
module1 = self.load_module(util.EXTENSIONS.name)
module2 = self.load_module(util.EXTENSIONS.name)
self.assertIs(module1, module2)
# No easy way to trigger a failure after a successful import.
@ -71,7 +70,7 @@ def test_unloadable(self):
self.assertEqual(cm.exception.name, name)
def test_is_package(self):
self.assertFalse(self.loader.is_package(ext_util.NAME))
self.assertFalse(self.loader.is_package(util.EXTENSIONS.name))
for suffix in self.machinery.EXTENSION_SUFFIXES:
path = os.path.join('some', 'path', 'pkg', '__init__' + suffix)
loader = self.machinery.ExtensionFileLoader('pkg', path)

View file

@ -1,7 +1,6 @@
from .. import util as test_util
from . import util
from .. import util
machinery = test_util.import_importlib('importlib.machinery')
machinery = util.import_importlib('importlib.machinery')
import collections
import sys
@ -22,9 +21,9 @@ def hook(self, entry):
def test_success(self):
# Path hook should handle a directory where a known extension module
# exists.
self.assertTrue(hasattr(self.hook(util.PATH), 'find_module'))
self.assertTrue(hasattr(self.hook(util.EXTENSIONS.path), 'find_module'))
Frozen_PathHooksTests, Source_PathHooksTests = test_util.test_both(
Frozen_PathHooksTests, Source_PathHooksTests = util.test_both(
PathHookTests, machinery=machinery)

View file

@ -1,19 +0,0 @@
from importlib import machinery
import os
import sys
PATH = None
EXT = None
FILENAME = None
NAME = '_testcapi'
try:
for PATH in sys.path:
for EXT in machinery.EXTENSION_SUFFIXES:
FILENAME = NAME + EXT
FILEPATH = os.path.join(PATH, FILENAME)
if os.path.exists(os.path.join(PATH, FILENAME)):
raise StopIteration
else:
PATH = EXT = FILENAME = FILEPATH = None
except StopIteration:
pass

View file

@ -4,7 +4,6 @@
import unittest
from .. import util
from . import util as import_util
class SpecLoaderMock:
@ -25,7 +24,7 @@ def test___loader__(self):
self.assertEqual(loader, module.__loader__)
Frozen_SpecTests, Source_SpecTests = util.test_both(
SpecLoaderAttributeTests, __import__=import_util.__import__)
SpecLoaderAttributeTests, __import__=util.__import__)
class LoaderMock:
@ -63,7 +62,7 @@ def test___loader___is_None(self):
Frozen_Tests, Source_Tests = util.test_both(LoaderAttributeTests,
__import__=import_util.__import__)
__import__=util.__import__)
if __name__ == '__main__':

View file

@ -6,7 +6,6 @@
"""
import unittest
from .. import util
from . import util as import_util
class Using__package__:
@ -74,13 +73,13 @@ class Using__package__PEP302(Using__package__):
mock_modules = util.mock_modules
Frozen_UsingPackagePEP302, Source_UsingPackagePEP302 = util.test_both(
Using__package__PEP302, __import__=import_util.__import__)
Using__package__PEP302, __import__=util.__import__)
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__)
Using__package__PEP302, __import__=util.__import__)
class Setting__package__:
@ -95,7 +94,7 @@ class Setting__package__:
"""
__import__ = import_util.__import__[1]
__import__ = util.__import__[1]
# [top-level]
def test_top_level(self):

View file

@ -1,5 +1,4 @@
from .. import util
from . import util as import_util
from importlib import machinery
import sys
@ -80,14 +79,14 @@ class OldAPITests(APITest):
bad_finder_loader = BadLoaderFinder
Frozen_OldAPITests, Source_OldAPITests = util.test_both(
OldAPITests, __import__=import_util.__import__)
OldAPITests, __import__=util.__import__)
class SpecAPITests(APITest):
bad_finder_loader = BadSpecFinderLoader
Frozen_SpecAPITests, Source_SpecAPITests = util.test_both(
SpecAPITests, __import__=import_util.__import__)
SpecAPITests, __import__=util.__import__)
if __name__ == '__main__':

View file

@ -1,6 +1,5 @@
"""Test that sys.modules is used properly by import."""
from .. import util
from . import util as import_util
import sys
from types import MethodType
import unittest
@ -40,14 +39,14 @@ def test_None_in_cache(self):
self.assertEqual(cm.exception.name, name)
Frozen_UseCache, Source_UseCache = util.test_both(
UseCache, __import__=import_util.__import__)
UseCache, __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]
__import__ = util.__import__[1]
def create_mock(self, *names, return_=None):
mock = util.mock_modules(*names)

View file

@ -1,6 +1,5 @@
"""Test that the semantics relating to the 'fromlist' argument are correct."""
from .. import util
from . import util as import_util
import unittest
@ -30,7 +29,7 @@ def test_return_from_from_import(self):
self.assertEqual(module.__name__, 'pkg.module')
Frozen_ReturnValue, Source_ReturnValue = util.test_both(
ReturnValue, __import__=import_util.__import__)
ReturnValue, __import__=util.__import__)
class HandlingFromlist:
@ -122,7 +121,7 @@ def test_star_with_others(self):
self.assertEqual(module.module2.__name__, 'pkg.module2')
Frozen_FromList, Source_FromList = util.test_both(
HandlingFromlist, __import__=import_util.__import__)
HandlingFromlist, __import__=util.__import__)
if __name__ == '__main__':

View file

@ -1,5 +1,4 @@
from .. import util
from . import util as import_util
import importlib._bootstrap
import sys
from types import MethodType
@ -47,7 +46,7 @@ def test_empty(self):
self.assertTrue(issubclass(w[-1].category, ImportWarning))
Frozen_CallingOrder, Source_CallingOrder = util.test_both(
CallingOrder, __import__=import_util.__import__)
CallingOrder, __import__=util.__import__)
class CallSignature:
@ -105,14 +104,14 @@ class CallSignaturePEP302(CallSignature):
finder_name = 'find_module'
Frozen_CallSignaturePEP302, Source_CallSignaturePEP302 = util.test_both(
CallSignaturePEP302, __import__=import_util.__import__)
CallSignaturePEP302, __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__)
CallSignaturePEP451, __import__=util.__import__)
if __name__ == '__main__':

View file

@ -1,5 +1,4 @@
from .. import util
from . import util as import_util
import sys
import unittest
import importlib
@ -103,7 +102,7 @@ def module_injection():
support.unload(subname)
Frozen_ParentTests, Source_ParentTests = util.test_both(
ParentModuleTests, __import__=import_util.__import__)
ParentModuleTests, __import__=util.__import__)
if __name__ == '__main__':

View file

@ -1,5 +1,4 @@
from .. import util
from . import util as import_util
importlib = util.import_importlib('importlib')
machinery = util.import_importlib('importlib.machinery')
@ -58,7 +57,7 @@ def test_path_hooks(self):
module = '<test module>'
path = '<test path>'
importer = util.mock_spec(module)
hook = import_util.mock_path_hook(path, importer=importer)
hook = util.mock_path_hook(path, importer=importer)
with util.import_state(path_hooks=[hook]):
loader = self.machinery.PathFinder.find_module(module, [path])
self.assertIs(loader, importer)
@ -83,7 +82,7 @@ def test_path_importer_cache_empty_string(self):
path = ''
module = '<test module>'
importer = util.mock_spec(module)
hook = import_util.mock_path_hook(os.getcwd(), importer=importer)
hook = util.mock_path_hook(os.getcwd(), importer=importer)
with util.import_state(path=[path], path_hooks=[hook]):
loader = self.machinery.PathFinder.find_module(module)
self.assertIs(loader, importer)

View file

@ -1,6 +1,5 @@
"""Test relative imports (PEP 328)."""
from .. import util
from . import util as import_util
import sys
import unittest
@ -209,7 +208,7 @@ def test_relative_import_no_globals(self):
self.__import__('sys', level=1)
Frozen_RelativeImports, Source_RelativeImports = util.test_both(
RelativeImports, __import__=import_util.__import__)
RelativeImports, __import__=util.__import__)
if __name__ == '__main__':

View file

@ -1,20 +0,0 @@
from .. import util
frozen_importlib, source_importlib = util.import_importlib('importlib')
import builtins
import functools
import importlib
import unittest
__import__ = staticmethod(builtins.__import__), staticmethod(source_importlib.__import__)
def mock_path_hook(*entries, importer):
"""A mock sys.path_hooks entry."""
def hook(entry):
if entry not in entries:
raise ImportError
return importer
return hook

View file

@ -1,6 +1,5 @@
"""Test case-sensitivity (PEP 235)."""
from .. import util
from . import util as source_util
importlib = util.import_importlib('importlib')
machinery = util.import_importlib('importlib.machinery')
@ -32,7 +31,7 @@ def sensitivity_test(self):
"""Look for a module with matching and non-matching sensitivity."""
sensitive_pkg = 'sensitive.{0}'.format(self.name)
insensitive_pkg = 'insensitive.{0}'.format(self.name.lower())
context = source_util.create_modules(insensitive_pkg, sensitive_pkg)
context = util.create_modules(insensitive_pkg, sensitive_pkg)
with context as mapping:
sensitive_path = os.path.join(mapping['.root'], 'sensitive')
insensitive_path = os.path.join(mapping['.root'], 'insensitive')

View file

@ -1,6 +1,5 @@
from .. import abc
from .. import util
from . import util as source_util
importlib = util.import_importlib('importlib')
importlib_abc = util.import_importlib('importlib.abc')
@ -71,7 +70,7 @@ def test_inequality(self):
# [basic]
def test_module(self):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
loader = self.machinery.SourceFileLoader('_temp', mapping['_temp'])
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
@ -83,7 +82,7 @@ def test_module(self):
self.assertEqual(getattr(module, attr), value)
def test_package(self):
with source_util.create_modules('_pkg.__init__') as mapping:
with util.create_modules('_pkg.__init__') as mapping:
loader = self.machinery.SourceFileLoader('_pkg',
mapping['_pkg.__init__'])
with warnings.catch_warnings():
@ -98,7 +97,7 @@ def test_package(self):
def test_lacking_parent(self):
with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping:
with util.create_modules('_pkg.__init__', '_pkg.mod')as mapping:
loader = self.machinery.SourceFileLoader('_pkg.mod',
mapping['_pkg.mod'])
with warnings.catch_warnings():
@ -115,7 +114,7 @@ def fake_mtime(self, fxn):
return lambda name: fxn(name) + 1
def test_module_reuse(self):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
loader = self.machinery.SourceFileLoader('_temp', mapping['_temp'])
with warnings.catch_warnings():
warnings.simplefilter('ignore', DeprecationWarning)
@ -139,7 +138,7 @@ def test_state_after_failure(self):
attributes = ('__file__', '__path__', '__package__')
value = '<test>'
name = '_temp'
with source_util.create_modules(name) as mapping:
with util.create_modules(name) as mapping:
orig_module = types.ModuleType(name)
for attr in attributes:
setattr(orig_module, attr, value)
@ -159,7 +158,7 @@ def test_state_after_failure(self):
# [syntax error]
def test_bad_syntax(self):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
with open(mapping['_temp'], 'w') as file:
file.write('=')
loader = self.machinery.SourceFileLoader('_temp', mapping['_temp'])
@ -190,11 +189,11 @@ def test_file_from_empty_string_dir(self):
if os.path.exists(pycache):
shutil.rmtree(pycache)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_timestamp_overflow(self):
# When a modification timestamp is larger than 2**32, it should be
# truncated rather than raise an OverflowError.
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
source = mapping['_temp']
compiled = self.util.cache_from_source(source)
with open(source, 'w') as f:
@ -275,45 +274,45 @@ def manipulate_bytecode(self, name, mapping, manipulator, *,
return bytecode_path
def _test_empty_file(self, test, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: b'',
del_source=del_source)
test('_temp', mapping, bc_path)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def _test_partial_magic(self, test, *, del_source=False):
# When their are less than 4 bytes to a .pyc, regenerate it if
# possible, else raise ImportError.
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:3],
del_source=del_source)
test('_temp', mapping, bc_path)
def _test_magic_only(self, test, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:4],
del_source=del_source)
test('_temp', mapping, bc_path)
def _test_partial_timestamp(self, test, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:7],
del_source=del_source)
test('_temp', mapping, bc_path)
def _test_partial_size(self, test, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:11],
del_source=del_source)
test('_temp', mapping, bc_path)
def _test_no_marshal(self, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:12],
del_source=del_source)
@ -322,7 +321,7 @@ def _test_no_marshal(self, *, del_source=False):
self.import_(file_path, '_temp')
def _test_non_code_marshal(self, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bytecode_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:12] + marshal.dumps(b'abcd'),
del_source=del_source)
@ -333,7 +332,7 @@ def _test_non_code_marshal(self, *, del_source=False):
self.assertEqual(cm.exception.path, bytecode_path)
def _test_bad_marshal(self, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bytecode_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: bc[:12] + b'<test>',
del_source=del_source)
@ -342,7 +341,7 @@ def _test_bad_marshal(self, *, del_source=False):
self.import_(file_path, '_temp')
def _test_bad_magic(self, test, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
bc_path = self.manipulate_bytecode('_temp', mapping,
lambda bc: b'\x00\x00\x00\x00' + bc[4:])
test('_temp', mapping, bc_path)
@ -371,7 +370,7 @@ class SourceLoaderBadBytecodeTest:
def setUpClass(cls):
cls.loader = cls.machinery.SourceFileLoader
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_empty_file(self):
# When a .pyc is empty, regenerate it if possible, else raise
# ImportError.
@ -390,7 +389,7 @@ def test(name, mapping, bytecode_path):
self._test_partial_magic(test)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_magic_only(self):
# When there is only the magic number, regenerate the .pyc if possible,
# else raise EOFError.
@ -401,7 +400,7 @@ def test(name, mapping, bytecode_path):
self._test_magic_only(test)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_bad_magic(self):
# When the magic number is different, the bytecode should be
# regenerated.
@ -413,7 +412,7 @@ def test(name, mapping, bytecode_path):
self._test_bad_magic(test)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_partial_timestamp(self):
# When the timestamp is partial, regenerate the .pyc, else
# raise EOFError.
@ -424,7 +423,7 @@ def test(name, mapping, bc_path):
self._test_partial_timestamp(test)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_partial_size(self):
# When the size is partial, regenerate the .pyc, else
# raise EOFError.
@ -435,29 +434,29 @@ def test(name, mapping, bc_path):
self._test_partial_size(test)
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_no_marshal(self):
# When there is only the magic number and timestamp, raise EOFError.
self._test_no_marshal()
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_non_code_marshal(self):
self._test_non_code_marshal()
# XXX ImportError when sourceless
# [bad marshal]
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_bad_marshal(self):
# Bad marshal data should raise a ValueError.
self._test_bad_marshal()
# [bad timestamp]
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_old_timestamp(self):
# When the timestamp is older than the source, bytecode should be
# regenerated.
zeros = b'\x00\x00\x00\x00'
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
py_compile.compile(mapping['_temp'])
bytecode_path = self.util.cache_from_source(mapping['_temp'])
with open(bytecode_path, 'r+b') as bytecode_file:
@ -471,10 +470,10 @@ def test_old_timestamp(self):
self.assertEqual(bytecode_file.read(4), source_timestamp)
# [bytecode read-only]
@source_util.writes_bytecode_files
@util.writes_bytecode_files
def test_read_only_bytecode(self):
# When bytecode is read-only but should be rewritten, fail silently.
with source_util.create_modules('_temp') as mapping:
with util.create_modules('_temp') as mapping:
# Create bytecode that will need to be re-created.
py_compile.compile(mapping['_temp'])
bytecode_path = self.util.cache_from_source(mapping['_temp'])

View file

@ -1,6 +1,5 @@
from .. import abc
from .. import util
from . import util as source_util
machinery = util.import_importlib('importlib.machinery')
@ -60,7 +59,7 @@ def run_test(self, test, create=None, *, compile_=None, unlink=None):
"""
if create is None:
create = {test}
with source_util.create_modules(*create) as mapping:
with util.create_modules(*create) as mapping:
if compile_:
for name in compile_:
py_compile.compile(mapping[name])
@ -100,14 +99,14 @@ def test_package(self):
# [sub module]
def test_module_in_package(self):
with source_util.create_modules('pkg.__init__', 'pkg.sub') as mapping:
with util.create_modules('pkg.__init__', 'pkg.sub') as mapping:
pkg_dir = os.path.dirname(mapping['pkg.__init__'])
loader = self.import_(pkg_dir, 'pkg.sub')
self.assertTrue(hasattr(loader, 'load_module'))
# [sub package]
def test_package_in_package(self):
context = source_util.create_modules('pkg.__init__', 'pkg.sub.__init__')
context = util.create_modules('pkg.__init__', 'pkg.sub.__init__')
with context as mapping:
pkg_dir = os.path.dirname(mapping['pkg.__init__'])
loader = self.import_(pkg_dir, 'pkg.sub')
@ -120,7 +119,7 @@ def test_package_over_module(self):
self.assertIn('__init__', loader.get_filename(name))
def test_failure(self):
with source_util.create_modules('blah') as mapping:
with util.create_modules('blah') as mapping:
nothing = self.import_(mapping['.root'], 'sdfsadsadf')
self.assertIsNone(nothing)
@ -147,7 +146,7 @@ def test_invalidate_caches(self):
# Regression test for http://bugs.python.org/issue14846
def test_dir_removal_handling(self):
mod = 'mod'
with source_util.create_modules(mod) as mapping:
with util.create_modules(mod) as mapping:
finder = self.get_finder(mapping['.root'])
found = self._find(finder, 'mod', loader_only=True)
self.assertIsNotNone(found)

View file

@ -1,5 +1,4 @@
from .. import util
from . import util as source_util
machinery = util.import_importlib('importlib.machinery')
@ -15,7 +14,7 @@ def path_hook(self):
self.machinery.SOURCE_SUFFIXES))
def test_success(self):
with source_util.create_modules('dummy') as mapping:
with util.create_modules('dummy') as mapping:
self.assertTrue(hasattr(self.path_hook()(mapping['.root']),
'find_module'))

View file

@ -1,5 +1,4 @@
from .. import util
from . import util as source_util
machinery = util.import_importlib('importlib.machinery')
@ -37,7 +36,7 @@ class EncodingTest:
module_name = '_temp'
def run_test(self, source):
with source_util.create_modules(self.module_name) as mapping:
with util.create_modules(self.module_name) as mapping:
with open(mapping[self.module_name], 'wb') as file:
file.write(source)
loader = self.machinery.SourceFileLoader(self.module_name,
@ -120,7 +119,7 @@ def run_test(self, line_ending):
module_name = '_temp'
source_lines = [b"a = 42", b"b = -13", b'']
source = line_ending.join(source_lines)
with source_util.create_modules(module_name) as mapping:
with util.create_modules(module_name) as mapping:
with open(mapping[module_name], 'wb') as file:
file.write(source)
loader = self.machinery.SourceFileLoader(module_name,

View file

@ -1,96 +0,0 @@
from .. import util
import contextlib
import errno
import functools
import os
import os.path
import sys
import tempfile
from test import support
def writes_bytecode_files(fxn):
"""Decorator to protect sys.dont_write_bytecode from mutation and to skip
tests that require it to be set to False."""
if sys.dont_write_bytecode:
return lambda *args, **kwargs: None
@functools.wraps(fxn)
def wrapper(*args, **kwargs):
original = sys.dont_write_bytecode
sys.dont_write_bytecode = False
try:
to_return = fxn(*args, **kwargs)
finally:
sys.dont_write_bytecode = original
return to_return
return wrapper
def ensure_bytecode_path(bytecode_path):
"""Ensure that the __pycache__ directory for PEP 3147 pyc file exists.
:param bytecode_path: File system path to PEP 3147 pyc file.
"""
try:
os.mkdir(os.path.dirname(bytecode_path))
except OSError as error:
if error.errno != errno.EEXIST:
raise
@contextlib.contextmanager
def create_modules(*names):
"""Temporarily create each named module with an attribute (named 'attr')
that contains the name passed into the context manager that caused the
creation of the module.
All files are created in a temporary directory returned by
tempfile.mkdtemp(). This directory is inserted at the beginning of
sys.path. When the context manager exits all created files (source and
bytecode) are explicitly deleted.
No magic is performed when creating packages! This means that if you create
a module within a package you must also create the package's __init__ as
well.
"""
source = 'attr = {0!r}'
created_paths = []
mapping = {}
state_manager = None
uncache_manager = None
try:
temp_dir = tempfile.mkdtemp()
mapping['.root'] = temp_dir
import_names = set()
for name in names:
if not name.endswith('__init__'):
import_name = name
else:
import_name = name[:-len('.__init__')]
import_names.add(import_name)
if import_name in sys.modules:
del sys.modules[import_name]
name_parts = name.split('.')
file_path = temp_dir
for directory in name_parts[:-1]:
file_path = os.path.join(file_path, directory)
if not os.path.exists(file_path):
os.mkdir(file_path)
created_paths.append(file_path)
file_path = os.path.join(file_path, name_parts[-1] + '.py')
with open(file_path, 'w') as file:
file.write(source.format(name))
created_paths.append(file_path)
mapping[name] = file_path
uncache_manager = util.uncache(*import_names)
uncache_manager.__enter__()
state_manager = util.import_state(path=[temp_dir])
state_manager.__enter__()
yield mapping
finally:
if state_manager is not None:
state_manager.__exit__(None, None, None)
if uncache_manager is not None:
uncache_manager.__exit__(None, None, None)
support.rmtree(temp_dir)

View file

@ -1,12 +1,49 @@
from contextlib import contextmanager
from importlib import util, invalidate_caches
import builtins
import contextlib
import errno
import functools
import importlib
from importlib import machinery, util, invalidate_caches
import os
import os.path
from test import support
import unittest
import sys
import tempfile
import types
BUILTINS = types.SimpleNamespace()
BUILTINS.good_name = None
BUILTINS.bad_name = None
if 'errno' in sys.builtin_module_names:
BUILTINS.good_name = 'errno'
if 'importlib' not in sys.builtin_module_names:
BUILTINS.bad_name = 'importlib'
EXTENSIONS = types.SimpleNamespace()
EXTENSIONS.path = None
EXTENSIONS.ext = None
EXTENSIONS.filename = None
EXTENSIONS.file_path = None
EXTENSIONS.name = '_testcapi'
def _extension_details():
global EXTENSIONS
for path in sys.path:
for ext in machinery.EXTENSION_SUFFIXES:
filename = EXTENSIONS.name + ext
file_path = os.path.join(path, filename)
if os.path.exists(file_path):
EXTENSIONS.path = path
EXTENSIONS.ext = ext
EXTENSIONS.filename = filename
EXTENSIONS.file_path = file_path
return
_extension_details()
def import_importlib(module_name):
"""Import a module from importlib both w/ and w/o _frozen_importlib."""
fresh = ('importlib',) if '.' in module_name else ()
@ -38,6 +75,9 @@ def test_both(test_class, **kwargs):
if not os.path.exists(changed_name):
CASE_INSENSITIVE_FS = False
_, source_importlib = import_importlib('importlib')
__import__ = staticmethod(builtins.__import__), staticmethod(source_importlib.__import__)
def case_insensitive_tests(test):
"""Class decorator that nullifies tests requiring a case-insensitive
@ -53,7 +93,7 @@ def submodule(parent, name, pkg_dir, content=''):
return '{}.{}'.format(parent, name), path
@contextmanager
@contextlib.contextmanager
def uncache(*names):
"""Uncache a module from sys.modules.
@ -79,7 +119,7 @@ def uncache(*names):
pass
@contextmanager
@contextlib.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:
@ -103,7 +143,7 @@ def temp_module(name, content='', *, pkg=False):
yield location
@contextmanager
@contextlib.contextmanager
def import_state(**kwargs):
"""Context manager to manage the various importers and stored state in the
sys module.
@ -198,6 +238,7 @@ def load_module(self, fullname):
raise
return self.modules[fullname]
class mock_spec(_ImporterMock):
"""Importer mock using PEP 451 APIs."""
@ -223,3 +264,99 @@ def exec_module(self, module):
self.module_code[module.__spec__.name]()
except KeyError:
pass
def writes_bytecode_files(fxn):
"""Decorator to protect sys.dont_write_bytecode from mutation and to skip
tests that require it to be set to False."""
if sys.dont_write_bytecode:
return lambda *args, **kwargs: None
@functools.wraps(fxn)
def wrapper(*args, **kwargs):
original = sys.dont_write_bytecode
sys.dont_write_bytecode = False
try:
to_return = fxn(*args, **kwargs)
finally:
sys.dont_write_bytecode = original
return to_return
return wrapper
def ensure_bytecode_path(bytecode_path):
"""Ensure that the __pycache__ directory for PEP 3147 pyc file exists.
:param bytecode_path: File system path to PEP 3147 pyc file.
"""
try:
os.mkdir(os.path.dirname(bytecode_path))
except OSError as error:
if error.errno != errno.EEXIST:
raise
@contextlib.contextmanager
def create_modules(*names):
"""Temporarily create each named module with an attribute (named 'attr')
that contains the name passed into the context manager that caused the
creation of the module.
All files are created in a temporary directory returned by
tempfile.mkdtemp(). This directory is inserted at the beginning of
sys.path. When the context manager exits all created files (source and
bytecode) are explicitly deleted.
No magic is performed when creating packages! This means that if you create
a module within a package you must also create the package's __init__ as
well.
"""
source = 'attr = {0!r}'
created_paths = []
mapping = {}
state_manager = None
uncache_manager = None
try:
temp_dir = tempfile.mkdtemp()
mapping['.root'] = temp_dir
import_names = set()
for name in names:
if not name.endswith('__init__'):
import_name = name
else:
import_name = name[:-len('.__init__')]
import_names.add(import_name)
if import_name in sys.modules:
del sys.modules[import_name]
name_parts = name.split('.')
file_path = temp_dir
for directory in name_parts[:-1]:
file_path = os.path.join(file_path, directory)
if not os.path.exists(file_path):
os.mkdir(file_path)
created_paths.append(file_path)
file_path = os.path.join(file_path, name_parts[-1] + '.py')
with open(file_path, 'w') as file:
file.write(source.format(name))
created_paths.append(file_path)
mapping[name] = file_path
uncache_manager = uncache(*import_names)
uncache_manager.__enter__()
state_manager = import_state(path=[temp_dir])
state_manager.__enter__()
yield mapping
finally:
if state_manager is not None:
state_manager.__exit__(None, None, None)
if uncache_manager is not None:
uncache_manager.__exit__(None, None, None)
support.rmtree(temp_dir)
def mock_path_hook(*entries, importer):
"""A mock sys.path_hooks entry."""
def hook(entry):
if entry not in entries:
raise ImportError
return importer
return hook