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. * 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.

View file

@ -1,6 +1,7 @@
"""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):
"""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)

View file

@ -1,6 +1,7 @@
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):
""" """
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):
# [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):
# [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):
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)

View file

@ -1,6 +1,7 @@
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):
# [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):
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):
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):
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):
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):
# [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):
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):
# [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):
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):
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):
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):
# [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:

View file

@ -1,5 +1,5 @@
import importlib import importlib
from .. import support from . import util
import unittest import unittest
@ -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'))

View file

@ -1,5 +1,6 @@
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):
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):
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],

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 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):
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):
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):
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