Commit 4ee2cdaf authored by Brett Cannon's avatar Brett Cannon

Split out support code that is specific to source tests out of

importlib.test.support to importlib.test.source.util.
parent 30b047dc
...@@ -3,9 +3,6 @@ to do ...@@ -3,9 +3,6 @@ to do
* Reorganize support code. * Reorganize support code.
+ Separate general support code and importer-specific (e.g. source) support
code.
- Create support modules for each subdirectory (as needed).
+ Add a file loader mock that returns monotonically increasing mtime. + Add a file loader mock that returns monotonically increasing mtime.
- Use in source/test_reload. - Use in source/test_reload.
- Use in source/test_load_module_mixed. - Use in source/test_load_module_mixed.
......
"""Test case-sensitivity (PEP 235).""" """Test case-sensitivity (PEP 235)."""
import importlib import importlib
from .. import support from .. import support
from . import util as source_util
import os import os
import sys import sys
from test import support as test_support from test import support as test_support
...@@ -25,7 +26,8 @@ class CaseSensitivityTest(unittest.TestCase): ...@@ -25,7 +26,8 @@ class CaseSensitivityTest(unittest.TestCase):
"""Look for a module with matching and non-matching sensitivity.""" """Look for a module with matching and non-matching sensitivity."""
sensitive_pkg = 'sensitive.{0}'.format(self.name) sensitive_pkg = 'sensitive.{0}'.format(self.name)
insensitive_pkg = 'insensitive.{0}'.format(self.name.lower()) insensitive_pkg = 'insensitive.{0}'.format(self.name.lower())
with support.create_modules(insensitive_pkg, sensitive_pkg) as mapping: context = source_util.create_modules(insensitive_pkg, sensitive_pkg)
with context as mapping:
sensitive_path = os.path.join(mapping['.root'], 'sensitive') sensitive_path = os.path.join(mapping['.root'], 'sensitive')
insensitive_path = os.path.join(mapping['.root'], 'insensitive') insensitive_path = os.path.join(mapping['.root'], 'insensitive')
return self.find(sensitive_path), self.find(insensitive_path) return self.find(sensitive_path), self.find(insensitive_path)
......
import importlib import importlib
from .. import abc from .. import abc
from .. import support from .. import support
from . import util as source_util
import os import os
import py_compile import py_compile
import unittest import unittest
...@@ -45,7 +46,7 @@ class FinderTests(abc.FinderTests): ...@@ -45,7 +46,7 @@ class FinderTests(abc.FinderTests):
""" """
if create is None: if create is None:
create = {test} create = {test}
with support.create_modules(*create) as mapping: with source_util.create_modules(*create) as mapping:
if compile_: if compile_:
for name in compile_: for name in compile_:
py_compile.compile(mapping[name]) py_compile.compile(mapping[name])
...@@ -76,14 +77,14 @@ class FinderTests(abc.FinderTests): ...@@ -76,14 +77,14 @@ class FinderTests(abc.FinderTests):
# [sub module] # [sub module]
def test_module_in_package(self): def test_module_in_package(self):
with support.create_modules('pkg.__init__', 'pkg.sub') as mapping: with source_util.create_modules('pkg.__init__', 'pkg.sub') as mapping:
pkg_dir = os.path.dirname(mapping['pkg.__init__']) pkg_dir = os.path.dirname(mapping['pkg.__init__'])
loader = self.import_(pkg_dir, 'pkg.sub') loader = self.import_(pkg_dir, 'pkg.sub')
self.assert_(hasattr(loader, 'load_module')) self.assert_(hasattr(loader, 'load_module'))
# [sub package] # [sub package]
def test_package_in_package(self): def test_package_in_package(self):
context = support.create_modules('pkg.__init__', 'pkg.sub.__init__') context = source_util.create_modules('pkg.__init__', 'pkg.sub.__init__')
with context as mapping: with context as mapping:
pkg_dir = os.path.dirname(mapping['pkg.__init__']) pkg_dir = os.path.dirname(mapping['pkg.__init__'])
loader = self.import_(pkg_dir, 'pkg.sub') loader = self.import_(pkg_dir, 'pkg.sub')
...@@ -91,7 +92,7 @@ class FinderTests(abc.FinderTests): ...@@ -91,7 +92,7 @@ class FinderTests(abc.FinderTests):
# [sub empty] # [sub empty]
def test_empty_sub_directory(self): def test_empty_sub_directory(self):
context = support.create_modules('pkg.__init__', 'pkg.sub.__init__') context = source_util.create_modules('pkg.__init__', 'pkg.sub.__init__')
with warnings.catch_warnings(): with warnings.catch_warnings():
warnings.simplefilter("error", ImportWarning) warnings.simplefilter("error", ImportWarning)
with context as mapping: with context as mapping:
...@@ -109,7 +110,7 @@ class FinderTests(abc.FinderTests): ...@@ -109,7 +110,7 @@ class FinderTests(abc.FinderTests):
def test_failure(self): def test_failure(self):
with support.create_modules('blah') as mapping: with source_util.create_modules('blah') as mapping:
nothing = self.import_(mapping['.root'], 'sdfsadsadf') nothing = self.import_(mapping['.root'], 'sdfsadsadf')
self.assert_(nothing is None) self.assert_(nothing is None)
......
import importlib import importlib
from .. import abc from .. import abc
from .. import support from .. import support
from . import util as source_util
import imp import imp
import os import os
...@@ -18,7 +19,7 @@ class SimpleTest(unittest.TestCase): ...@@ -18,7 +19,7 @@ class SimpleTest(unittest.TestCase):
# [basic] # [basic]
def test_module(self): def test_module(self):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
loader = importlib._PyFileLoader('_temp', mapping['_temp'], False) loader = importlib._PyFileLoader('_temp', mapping['_temp'], False)
module = loader.load_module('_temp') module = loader.load_module('_temp')
self.assert_('_temp' in sys.modules) self.assert_('_temp' in sys.modules)
...@@ -28,7 +29,7 @@ class SimpleTest(unittest.TestCase): ...@@ -28,7 +29,7 @@ class SimpleTest(unittest.TestCase):
self.assertEqual(getattr(module, attr), value) self.assertEqual(getattr(module, attr), value)
def test_package(self): def test_package(self):
with support.create_modules('_pkg.__init__') as mapping: with source_util.create_modules('_pkg.__init__') as mapping:
loader = importlib._PyFileLoader('_pkg', mapping['_pkg.__init__'], loader = importlib._PyFileLoader('_pkg', mapping['_pkg.__init__'],
True) True)
module = loader.load_module('_pkg') module = loader.load_module('_pkg')
...@@ -41,7 +42,7 @@ class SimpleTest(unittest.TestCase): ...@@ -41,7 +42,7 @@ class SimpleTest(unittest.TestCase):
def test_lacking_parent(self): def test_lacking_parent(self):
with support.create_modules('_pkg.__init__', '_pkg.mod')as mapping: with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping:
loader = importlib._PyFileLoader('_pkg.mod', mapping['_pkg.mod'], loader = importlib._PyFileLoader('_pkg.mod', mapping['_pkg.mod'],
False) False)
module = loader.load_module('_pkg.mod') module = loader.load_module('_pkg.mod')
...@@ -56,7 +57,7 @@ class SimpleTest(unittest.TestCase): ...@@ -56,7 +57,7 @@ class SimpleTest(unittest.TestCase):
return lambda name: fxn(name) + 1 return lambda name: fxn(name) + 1
def test_module_reuse(self): def test_module_reuse(self):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
loader = importlib._PyFileLoader('_temp', mapping['_temp'], False) loader = importlib._PyFileLoader('_temp', mapping['_temp'], False)
module = loader.load_module('_temp') module = loader.load_module('_temp')
module_id = id(module) module_id = id(module)
...@@ -81,7 +82,7 @@ class SimpleTest(unittest.TestCase): ...@@ -81,7 +82,7 @@ class SimpleTest(unittest.TestCase):
attributes = ('__file__', '__path__', '__package__') attributes = ('__file__', '__path__', '__package__')
value = '<test>' value = '<test>'
name = '_temp' name = '_temp'
with support.create_modules(name) as mapping: with source_util.create_modules(name) as mapping:
orig_module = imp.new_module(name) orig_module = imp.new_module(name)
for attr in attributes: for attr in attributes:
setattr(orig_module, attr, value) setattr(orig_module, attr, value)
...@@ -94,7 +95,7 @@ class SimpleTest(unittest.TestCase): ...@@ -94,7 +95,7 @@ class SimpleTest(unittest.TestCase):
# [syntax error] # [syntax error]
def test_bad_syntax(self): def test_bad_syntax(self):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
with open(mapping['_temp'], 'w') as file: with open(mapping['_temp'], 'w') as file:
file.write('=') file.write('=')
loader = importlib._PyFileLoader('_temp', mapping['_temp'], False) loader = importlib._PyFileLoader('_temp', mapping['_temp'], False)
...@@ -109,12 +110,12 @@ class DontWriteBytecodeTest(unittest.TestCase): ...@@ -109,12 +110,12 @@ class DontWriteBytecodeTest(unittest.TestCase):
def tearDown(self): def tearDown(self):
sys.dont_write_bytecode = False sys.dont_write_bytecode = False
@support.writes_bytecode @source_util.writes_bytecode
def run_test(self, assertion): def run_test(self, assertion):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
loader = importlib._PyFileLoader('_temp', mapping['_temp'], False) loader = importlib._PyFileLoader('_temp', mapping['_temp'], False)
loader.load_module('_temp') loader.load_module('_temp')
bytecode_path = support.bytecode_path(mapping['_temp']) bytecode_path = source_util.bytecode_path(mapping['_temp'])
assertion(bytecode_path) assertion(bytecode_path)
def test_bytecode_written(self): def test_bytecode_written(self):
...@@ -137,10 +138,10 @@ class BadDataTest(unittest.TestCase): ...@@ -137,10 +138,10 @@ class BadDataTest(unittest.TestCase):
# [bad magic] # [bad magic]
def test_bad_magic(self): def test_bad_magic(self):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
py_compile.compile(mapping['_temp']) py_compile.compile(mapping['_temp'])
os.unlink(mapping['_temp']) os.unlink(mapping['_temp'])
bytecode_path = support.bytecode_path(mapping['_temp']) bytecode_path = source_util.bytecode_path(mapping['_temp'])
with open(bytecode_path, 'r+b') as file: with open(bytecode_path, 'r+b') as file:
file.seek(0) file.seek(0)
file.write(b'\x00\x00\x00\x00') file.write(b'\x00\x00\x00\x00')
...@@ -164,7 +165,7 @@ class SourceBytecodeInteraction(unittest.TestCase): ...@@ -164,7 +165,7 @@ class SourceBytecodeInteraction(unittest.TestCase):
def run_test(self, test, *create, pkg=False): def run_test(self, test, *create, pkg=False):
create += (test,) create += (test,)
with support.create_modules(*create) as mapping: with source_util.create_modules(*create) as mapping:
for name in create: for name in create:
py_compile.compile(mapping[name]) py_compile.compile(mapping[name])
if pkg: if pkg:
...@@ -217,11 +218,11 @@ class BadBytecodeTest(unittest.TestCase): ...@@ -217,11 +218,11 @@ class BadBytecodeTest(unittest.TestCase):
self.assert_(module_name in sys.modules) self.assert_(module_name in sys.modules)
# [bad magic] # [bad magic]
@support.writes_bytecode @source_util.writes_bytecode
def test_bad_magic(self): def test_bad_magic(self):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
py_compile.compile(mapping['_temp']) py_compile.compile(mapping['_temp'])
bytecode_path = support.bytecode_path(mapping['_temp']) bytecode_path = source_util.bytecode_path(mapping['_temp'])
with open(bytecode_path, 'r+b') as bytecode_file: with open(bytecode_path, 'r+b') as bytecode_file:
bytecode_file.seek(0) bytecode_file.seek(0)
bytecode_file.write(b'\x00\x00\x00\x00') bytecode_file.write(b'\x00\x00\x00\x00')
...@@ -230,12 +231,12 @@ class BadBytecodeTest(unittest.TestCase): ...@@ -230,12 +231,12 @@ class BadBytecodeTest(unittest.TestCase):
self.assertEqual(bytecode_file.read(4), imp.get_magic()) self.assertEqual(bytecode_file.read(4), imp.get_magic())
# [bad timestamp] # [bad timestamp]
@support.writes_bytecode @source_util.writes_bytecode
def test_bad_bytecode(self): def test_bad_bytecode(self):
zeros = b'\x00\x00\x00\x00' zeros = b'\x00\x00\x00\x00'
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
py_compile.compile(mapping['_temp']) py_compile.compile(mapping['_temp'])
bytecode_path = support.bytecode_path(mapping['_temp']) bytecode_path = source_util.bytecode_path(mapping['_temp'])
with open(bytecode_path, 'r+b') as bytecode_file: with open(bytecode_path, 'r+b') as bytecode_file:
bytecode_file.seek(4) bytecode_file.seek(4)
bytecode_file.write(zeros) bytecode_file.write(zeros)
...@@ -248,8 +249,8 @@ class BadBytecodeTest(unittest.TestCase): ...@@ -248,8 +249,8 @@ class BadBytecodeTest(unittest.TestCase):
# [bad marshal] # [bad marshal]
def test_bad_marshal(self): def test_bad_marshal(self):
with support.create_modules('_temp') as mapping: with source_util.create_modules('_temp') as mapping:
bytecode_path = support.bytecode_path(mapping['_temp']) bytecode_path = source_util.bytecode_path(mapping['_temp'])
source_mtime = os.path.getmtime(mapping['_temp']) source_mtime = os.path.getmtime(mapping['_temp'])
source_timestamp = importlib._w_long(source_mtime) source_timestamp = importlib._w_long(source_mtime)
with open(bytecode_path, 'wb') as bytecode_file: with open(bytecode_path, 'wb') as bytecode_file:
......
import importlib import importlib
from .. import support from . import util
import unittest import unittest
...@@ -9,7 +9,7 @@ class PathHookTest(unittest.TestCase): ...@@ -9,7 +9,7 @@ class PathHookTest(unittest.TestCase):
def test_success(self): def test_success(self):
# XXX Only work on existing directories? # XXX Only work on existing directories?
with support.create_modules('dummy') as mapping: with util.create_modules('dummy') as mapping:
self.assert_(hasattr(importlib.FileImporter(mapping['.root']), self.assert_(hasattr(importlib.FileImporter(mapping['.root']),
'find_module')) 'find_module'))
......
import importlib import importlib
from .. import support from .. import support
from . import util as source_util
import codecs import codecs
import re import re
...@@ -32,7 +33,7 @@ class EncodingTest(unittest.TestCase): ...@@ -32,7 +33,7 @@ class EncodingTest(unittest.TestCase):
module_name = '_temp' module_name = '_temp'
def run_test(self, source): def run_test(self, source):
with support.create_modules(self.module_name) as mapping: with source_util.create_modules(self.module_name) as mapping:
with open(mapping[self.module_name], 'wb')as file: with open(mapping[self.module_name], 'wb')as file:
file.write(source) file.write(source)
loader = importlib._PyFileLoader(self.module_name, loader = importlib._PyFileLoader(self.module_name,
...@@ -93,7 +94,7 @@ class LineEndingTest(unittest.TestCase): ...@@ -93,7 +94,7 @@ class LineEndingTest(unittest.TestCase):
module_name = '_temp' module_name = '_temp'
source_lines = [b"a = 42", b"b = -13", b''] source_lines = [b"a = 42", b"b = -13", b'']
source = line_ending.join(source_lines) source = line_ending.join(source_lines)
with support.create_modules(module_name) as mapping: with source_util.create_modules(module_name) as mapping:
with open(mapping[module_name], 'wb') as file: with open(mapping[module_name], 'wb') as file:
file.write(source) file.write(source)
loader = importlib._PyFileLoader(module_name, mapping[module_name], loader = importlib._PyFileLoader(module_name, mapping[module_name],
......
from .. import support as util
import contextlib
import imp
import os
import os.path
import sys
import tempfile
from test import support as support
def writes_bytecode(fxn):
"""Decorator that returns the function if writing bytecode is enabled, else
a stub function that accepts anything and simply returns None."""
if sys.dont_write_bytecode:
return lambda *args, **kwargs: None
else:
return fxn
def bytecode_path(source_path):
for suffix, _, type_ in imp.get_suffixes():
if type_ == imp.PY_COMPILED:
bc_suffix = suffix
break
else:
raise ValueError("no bytecode suffix is defined")
return os.path.splitext(source_path)[0] + bc_suffix
@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 specified by
tempfile.gettempdir(). 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 = {}
try:
temp_dir = tempfile.gettempdir()
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:
state_manager.__exit__(None, None, None)
uncache_manager.__exit__(None, None, None)
# Reverse the order for path removal to unroll directory creation.
for path in reversed(created_paths):
if file_path.endswith('.py'):
support.unlink(path)
support.unlink(path + 'c')
support.unlink(path + 'o')
else:
os.rmdir(path)
...@@ -6,7 +6,6 @@ import imp ...@@ -6,7 +6,6 @@ import imp
import os.path import os.path
from test.support import unlink from test.support import unlink
import sys import sys
from tempfile import gettempdir
using___import__ = False using___import__ = False
...@@ -28,14 +27,6 @@ def importlib_only(fxn): ...@@ -28,14 +27,6 @@ def importlib_only(fxn):
update_wrapper(inner, fxn) update_wrapper(inner, fxn)
return inner return inner
def writes_bytecode(fxn):
"""Decorator that returns the function if writing bytecode is enabled, else
a stub function that accepts anything and simply returns None."""
if sys.dont_write_bytecode:
return lambda *args, **kwargs: None
else:
return fxn
def case_insensitive_tests(class_): def case_insensitive_tests(class_):
"""Class decorator that nullifies tests that require a case-insensitive """Class decorator that nullifies tests that require a case-insensitive
...@@ -102,67 +93,6 @@ def import_state(**kwargs): ...@@ -102,67 +93,6 @@ def import_state(**kwargs):
setattr(sys, attr, value) setattr(sys, attr, value)
@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 specified by
tempfile.gettempdir(). 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 = {}
try:
temp_dir = gettempdir()
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:
state_manager.__exit__(None, None, None)
uncache_manager.__exit__(None, None, None)
# Reverse the order for path removal to unroll directory creation.
for path in reversed(created_paths):
if file_path.endswith('.py'):
unlink(path)
unlink(path + 'c')
unlink(path + 'o')
else:
os.rmdir(path)
class mock_modules: class mock_modules:
"""A mock importer/loader.""" """A mock importer/loader."""
...@@ -221,13 +151,3 @@ def mock_path_hook(*entries, importer): ...@@ -221,13 +151,3 @@ def mock_path_hook(*entries, importer):
raise ImportError raise ImportError
return importer return importer
return hook return hook
def bytecode_path(source_path):
for suffix, _, type_ in imp.get_suffixes():
if type_ == imp.PY_COMPILED:
bc_suffix = suffix
break
else:
raise ValueError("no bytecode suffix is defined")
return os.path.splitext(source_path)[0] + bc_suffix
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