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

importlib.test.support to importlib.test.source.util.
This commit is contained in:
Brett Cannon 2009-02-01 03:08:31 +00:00
parent 30b047dc35
commit 4ee2cdaf65
8 changed files with 123 additions and 113 deletions

View File

@ -3,9 +3,6 @@ to do
* 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.
- Use in source/test_reload.
- Use in source/test_load_module_mixed.

View File

@ -1,6 +1,7 @@
"""Test case-sensitivity (PEP 235)."""
import importlib
from .. import support
from . import util as source_util
import os
import sys
from test import support as test_support
@ -25,7 +26,8 @@ class CaseSensitivityTest(unittest.TestCase):
"""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())
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')
insensitive_path = os.path.join(mapping['.root'], 'insensitive')
return self.find(sensitive_path), self.find(insensitive_path)

View File

@ -1,6 +1,7 @@
import importlib
from .. import abc
from .. import support
from . import util as source_util
import os
import py_compile
import unittest
@ -45,7 +46,7 @@ class FinderTests(abc.FinderTests):
"""
if create is None:
create = {test}
with support.create_modules(*create) as mapping:
with source_util.create_modules(*create) as mapping:
if compile_:
for name in compile_:
py_compile.compile(mapping[name])
@ -76,14 +77,14 @@ class FinderTests(abc.FinderTests):
# [sub module]
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__'])
loader = self.import_(pkg_dir, 'pkg.sub')
self.assert_(hasattr(loader, 'load_module'))
# [sub package]
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:
pkg_dir = os.path.dirname(mapping['pkg.__init__'])
loader = self.import_(pkg_dir, 'pkg.sub')
@ -91,7 +92,7 @@ class FinderTests(abc.FinderTests):
# [sub empty]
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():
warnings.simplefilter("error", ImportWarning)
with context as mapping:
@ -109,7 +110,7 @@ class FinderTests(abc.FinderTests):
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')
self.assert_(nothing is None)

View File

@ -1,6 +1,7 @@
import importlib
from .. import abc
from .. import support
from . import util as source_util
import imp
import os
@ -18,7 +19,7 @@ class SimpleTest(unittest.TestCase):
# [basic]
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)
module = loader.load_module('_temp')
self.assert_('_temp' in sys.modules)
@ -28,7 +29,7 @@ class SimpleTest(unittest.TestCase):
self.assertEqual(getattr(module, attr), value)
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__'],
True)
module = loader.load_module('_pkg')
@ -41,7 +42,7 @@ class SimpleTest(unittest.TestCase):
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'],
False)
module = loader.load_module('_pkg.mod')
@ -56,7 +57,7 @@ class SimpleTest(unittest.TestCase):
return lambda name: fxn(name) + 1
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)
module = loader.load_module('_temp')
module_id = id(module)
@ -81,7 +82,7 @@ class SimpleTest(unittest.TestCase):
attributes = ('__file__', '__path__', '__package__')
value = '<test>'
name = '_temp'
with support.create_modules(name) as mapping:
with source_util.create_modules(name) as mapping:
orig_module = imp.new_module(name)
for attr in attributes:
setattr(orig_module, attr, value)
@ -94,7 +95,7 @@ class SimpleTest(unittest.TestCase):
# [syntax error]
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:
file.write('=')
loader = importlib._PyFileLoader('_temp', mapping['_temp'], False)
@ -109,12 +110,12 @@ class DontWriteBytecodeTest(unittest.TestCase):
def tearDown(self):
sys.dont_write_bytecode = False
@support.writes_bytecode
@source_util.writes_bytecode
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.load_module('_temp')
bytecode_path = support.bytecode_path(mapping['_temp'])
bytecode_path = source_util.bytecode_path(mapping['_temp'])
assertion(bytecode_path)
def test_bytecode_written(self):
@ -137,10 +138,10 @@ class BadDataTest(unittest.TestCase):
# [bad magic]
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'])
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:
file.seek(0)
file.write(b'\x00\x00\x00\x00')
@ -164,7 +165,7 @@ class SourceBytecodeInteraction(unittest.TestCase):
def run_test(self, test, *create, pkg=False):
create += (test,)
with support.create_modules(*create) as mapping:
with source_util.create_modules(*create) as mapping:
for name in create:
py_compile.compile(mapping[name])
if pkg:
@ -217,11 +218,11 @@ class BadBytecodeTest(unittest.TestCase):
self.assert_(module_name in sys.modules)
# [bad magic]
@support.writes_bytecode
@source_util.writes_bytecode
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'])
bytecode_path = support.bytecode_path(mapping['_temp'])
bytecode_path = source_util.bytecode_path(mapping['_temp'])
with open(bytecode_path, 'r+b') as bytecode_file:
bytecode_file.seek(0)
bytecode_file.write(b'\x00\x00\x00\x00')
@ -230,12 +231,12 @@ class BadBytecodeTest(unittest.TestCase):
self.assertEqual(bytecode_file.read(4), imp.get_magic())
# [bad timestamp]
@support.writes_bytecode
@source_util.writes_bytecode
def test_bad_bytecode(self):
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'])
bytecode_path = support.bytecode_path(mapping['_temp'])
bytecode_path = source_util.bytecode_path(mapping['_temp'])
with open(bytecode_path, 'r+b') as bytecode_file:
bytecode_file.seek(4)
bytecode_file.write(zeros)
@ -248,8 +249,8 @@ class BadBytecodeTest(unittest.TestCase):
# [bad marshal]
def test_bad_marshal(self):
with support.create_modules('_temp') as mapping:
bytecode_path = support.bytecode_path(mapping['_temp'])
with source_util.create_modules('_temp') as mapping:
bytecode_path = source_util.bytecode_path(mapping['_temp'])
source_mtime = os.path.getmtime(mapping['_temp'])
source_timestamp = importlib._w_long(source_mtime)
with open(bytecode_path, 'wb') as bytecode_file:

View File

@ -1,5 +1,5 @@
import importlib
from .. import support
from . import util
import unittest
@ -9,7 +9,7 @@ class PathHookTest(unittest.TestCase):
def test_success(self):
# 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']),
'find_module'))

View File

@ -1,5 +1,6 @@
import importlib
from .. import support
from . import util as source_util
import codecs
import re
@ -32,7 +33,7 @@ class EncodingTest(unittest.TestCase):
module_name = '_temp'
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:
file.write(source)
loader = importlib._PyFileLoader(self.module_name,
@ -93,7 +94,7 @@ class LineEndingTest(unittest.TestCase):
module_name = '_temp'
source_lines = [b"a = 42", b"b = -13", b'']
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:
file.write(source)
loader = importlib._PyFileLoader(module_name, mapping[module_name],

View File

@ -0,0 +1,88 @@
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)

View File

@ -6,7 +6,6 @@ import imp
import os.path
from test.support import unlink
import sys
from tempfile import gettempdir
using___import__ = False
@ -28,14 +27,6 @@ def importlib_only(fxn):
update_wrapper(inner, fxn)
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_):
"""Class decorator that nullifies tests that require a case-insensitive
@ -102,67 +93,6 @@ def import_state(**kwargs):
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:
"""A mock importer/loader."""
@ -221,13 +151,3 @@ def mock_path_hook(*entries, importer):
raise ImportError
return importer
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