summaryrefslogtreecommitdiff
path: root/Lib/importlib/test
diff options
context:
space:
mode:
authorMartin v. L?wis <martin@v.loewis.de>2012-06-03 12:00:48 +0200
committerMartin v. L?wis <martin@v.loewis.de>2012-06-03 12:00:48 +0200
commit183bc7b78cb50c73b3142710b3b8fbafde4a3833 (patch)
tree8a29bbfd852dccb5f14340c8d1c6309cf8fdfb72 /Lib/importlib/test
parent15670dc71126aabce6daca6c8d32f55ea146cc11 (diff)
parent9fe4e3d311149c5f07073f7c55509fcfd7dde47e (diff)
downloadcpython-183bc7b78cb50c73b3142710b3b8fbafde4a3833.tar.gz
Merge 3.2: issue #14937.
Diffstat (limited to 'Lib/importlib/test')
-rw-r--r--Lib/importlib/test/__init__.py25
-rw-r--r--Lib/importlib/test/__main__.py19
-rw-r--r--Lib/importlib/test/benchmark.py170
-rw-r--r--Lib/importlib/test/builtin/test_loader.py9
-rw-r--r--Lib/importlib/test/extension/test_case_sensitivity.py13
-rw-r--r--Lib/importlib/test/extension/test_finder.py7
-rw-r--r--Lib/importlib/test/extension/test_loader.py26
-rw-r--r--Lib/importlib/test/extension/test_path_hook.py3
-rw-r--r--Lib/importlib/test/extension/util.py5
-rw-r--r--Lib/importlib/test/frozen/test_loader.py34
-rw-r--r--Lib/importlib/test/import_/test___package__.py2
-rw-r--r--Lib/importlib/test/import_/test_api.py7
-rw-r--r--Lib/importlib/test/import_/test_caching.py3
-rw-r--r--Lib/importlib/test/import_/test_fromlist.py4
-rw-r--r--Lib/importlib/test/import_/test_meta_path.py18
-rw-r--r--Lib/importlib/test/import_/test_packages.py79
-rw-r--r--Lib/importlib/test/import_/test_path.py95
-rw-r--r--Lib/importlib/test/import_/test_relative_imports.py14
-rw-r--r--Lib/importlib/test/import_/util.py1
-rw-r--r--Lib/importlib/test/regrtest.py20
-rw-r--r--Lib/importlib/test/source/test_abc_loader.py28
-rw-r--r--Lib/importlib/test/source/test_case_sensitivity.py18
-rw-r--r--Lib/importlib/test/source/test_file_loader.py117
-rw-r--r--Lib/importlib/test/source/test_finder.py46
-rw-r--r--Lib/importlib/test/source/test_path_hook.py12
-rw-r--r--Lib/importlib/test/source/test_source_encoding.py8
-rw-r--r--Lib/importlib/test/test_abc.py9
-rw-r--r--Lib/importlib/test/test_api.py78
-rw-r--r--Lib/importlib/test/test_locks.py115
-rw-r--r--Lib/importlib/test/test_util.py94
-rw-r--r--Lib/importlib/test/util.py8
31 files changed, 837 insertions, 250 deletions
diff --git a/Lib/importlib/test/__init__.py b/Lib/importlib/test/__init__.py
index e69de29bb2..815a706c54 100644
--- a/Lib/importlib/test/__init__.py
+++ b/Lib/importlib/test/__init__.py
@@ -0,0 +1,25 @@
+import os
+import sys
+import unittest
+
+def test_suite(package=__package__, directory=os.path.dirname(__file__)):
+ suite = unittest.TestSuite()
+ for name in os.listdir(directory):
+ if name.startswith(('.', '__')):
+ continue
+ path = os.path.join(directory, name)
+ if (os.path.isfile(path) and name.startswith('test_') and
+ name.endswith('.py')):
+ submodule_name = os.path.splitext(name)[0]
+ module_name = "{0}.{1}".format(package, submodule_name)
+ __import__(module_name, level=0)
+ module_tests = unittest.findTestCases(sys.modules[module_name])
+ suite.addTest(module_tests)
+ elif os.path.isdir(path):
+ package_name = "{0}.{1}".format(package, name)
+ __import__(package_name, level=0)
+ package_tests = getattr(sys.modules[package_name], 'test_suite')()
+ suite.addTest(package_tests)
+ else:
+ continue
+ return suite
diff --git a/Lib/importlib/test/__main__.py b/Lib/importlib/test/__main__.py
index decc53d8c5..92171b25ca 100644
--- a/Lib/importlib/test/__main__.py
+++ b/Lib/importlib/test/__main__.py
@@ -4,26 +4,27 @@ Specifying the ``--builtin`` flag will run tests, where applicable, with
builtins.__import__ instead of importlib.__import__.
"""
-import importlib
from importlib.test.import_ import util
import os.path
from test.support import run_unittest
-import sys
import unittest
def test_main():
- if '__pycache__' in __file__:
- parts = __file__.split(os.path.sep)
- start_dir = sep.join(parts[:-2])
- else:
- start_dir = os.path.dirname(__file__)
+ start_dir = os.path.dirname(__file__)
top_dir = os.path.dirname(os.path.dirname(start_dir))
test_loader = unittest.TestLoader()
- if '--builtin' in sys.argv:
- util.using___import__ = True
run_unittest(test_loader.discover(start_dir, top_level_dir=top_dir))
if __name__ == '__main__':
+ import argparse
+
+ parser = argparse.ArgumentParser(description='Execute the importlib test '
+ 'suite')
+ parser.add_argument('-b', '--builtin', action='store_true', default=False,
+ help='use builtins.__import__() instead of importlib')
+ args = parser.parse_args()
+ if args.builtin:
+ util.using___import__ = True
test_main()
diff --git a/Lib/importlib/test/benchmark.py b/Lib/importlib/test/benchmark.py
index b5de6c6b01..183e8180c9 100644
--- a/Lib/importlib/test/benchmark.py
+++ b/Lib/importlib/test/benchmark.py
@@ -9,9 +9,12 @@ from .source import util as source_util
import decimal
import imp
import importlib
+import importlib.machinery
+import json
import os
import py_compile
import sys
+import tabnanny
import timeit
@@ -59,13 +62,17 @@ def builtin_mod(seconds, repeat):
def source_wo_bytecode(seconds, repeat):
- """Source w/o bytecode: simple"""
+ """Source w/o bytecode: small"""
sys.dont_write_bytecode = True
try:
name = '__importlib_test_benchmark__'
# Clears out sys.modules and puts an entry at the front of sys.path.
with source_util.create_modules(name) as mapping:
assert not os.path.exists(imp.cache_from_source(mapping[name]))
+ sys.meta_path.append(importlib.machinery.PathFinder)
+ loader = (importlib.machinery.SourceFileLoader,
+ importlib.machinery.SOURCE_SUFFIXES, True)
+ sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
seconds=seconds):
yield result
@@ -73,26 +80,37 @@ def source_wo_bytecode(seconds, repeat):
sys.dont_write_bytecode = False
-def decimal_wo_bytecode(seconds, repeat):
- """Source w/o bytecode: decimal"""
- name = 'decimal'
- decimal_bytecode = imp.cache_from_source(decimal.__file__)
- if os.path.exists(decimal_bytecode):
- os.unlink(decimal_bytecode)
- sys.dont_write_bytecode = True
- try:
- for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
- seconds=seconds):
- yield result
- finally:
- sys.dont_write_bytecode = False
+def _wo_bytecode(module):
+ name = module.__name__
+ def benchmark_wo_bytecode(seconds, repeat):
+ """Source w/o bytecode: {}"""
+ bytecode_path = imp.cache_from_source(module.__file__)
+ if os.path.exists(bytecode_path):
+ os.unlink(bytecode_path)
+ sys.dont_write_bytecode = True
+ try:
+ for result in bench(name, lambda: sys.modules.pop(name),
+ repeat=repeat, seconds=seconds):
+ yield result
+ finally:
+ sys.dont_write_bytecode = False
+
+ benchmark_wo_bytecode.__doc__ = benchmark_wo_bytecode.__doc__.format(name)
+ return benchmark_wo_bytecode
+
+tabnanny_wo_bytecode = _wo_bytecode(tabnanny)
+decimal_wo_bytecode = _wo_bytecode(decimal)
def source_writing_bytecode(seconds, repeat):
- """Source writing bytecode: simple"""
+ """Source writing bytecode: small"""
assert not sys.dont_write_bytecode
name = '__importlib_test_benchmark__'
with source_util.create_modules(name) as mapping:
+ sys.meta_path.append(importlib.machinery.PathFinder)
+ loader = (importlib.machinery.SourceFileLoader,
+ importlib.machinery.SOURCE_SUFFIXES, True)
+ sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
def cleanup():
sys.modules.pop(name)
os.unlink(imp.cache_from_source(mapping[name]))
@@ -101,21 +119,33 @@ def source_writing_bytecode(seconds, repeat):
yield result
-def decimal_writing_bytecode(seconds, repeat):
- """Source writing bytecode: decimal"""
- assert not sys.dont_write_bytecode
- name = 'decimal'
- def cleanup():
- sys.modules.pop(name)
- os.unlink(imp.cache_from_source(decimal.__file__))
- for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
- yield result
+def _writing_bytecode(module):
+ name = module.__name__
+ def writing_bytecode_benchmark(seconds, repeat):
+ """Source writing bytecode: {}"""
+ assert not sys.dont_write_bytecode
+ def cleanup():
+ sys.modules.pop(name)
+ os.unlink(imp.cache_from_source(module.__file__))
+ for result in bench(name, cleanup, repeat=repeat, seconds=seconds):
+ yield result
+
+ writing_bytecode_benchmark.__doc__ = (
+ writing_bytecode_benchmark.__doc__.format(name))
+ return writing_bytecode_benchmark
+
+tabnanny_writing_bytecode = _writing_bytecode(tabnanny)
+decimal_writing_bytecode = _writing_bytecode(decimal)
def source_using_bytecode(seconds, repeat):
- """Bytecode w/ source: simple"""
+ """Source w/ bytecode: small"""
name = '__importlib_test_benchmark__'
with source_util.create_modules(name) as mapping:
+ sys.meta_path.append(importlib.machinery.PathFinder)
+ loader = (importlib.machinery.SourceFileLoader,
+ importlib.machinery.SOURCE_SUFFIXES, True)
+ sys.path_hooks.append(importlib.machinery.FileFinder.path_hook(loader))
py_compile.compile(mapping[name])
assert os.path.exists(imp.cache_from_source(mapping[name]))
for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
@@ -123,27 +153,56 @@ def source_using_bytecode(seconds, repeat):
yield result
-def decimal_using_bytecode(seconds, repeat):
- """Bytecode w/ source: decimal"""
- name = 'decimal'
- py_compile.compile(decimal.__file__)
- for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
- seconds=seconds):
- yield result
+def _using_bytecode(module):
+ name = module.__name__
+ def using_bytecode_benchmark(seconds, repeat):
+ """Source w/ bytecode: {}"""
+ py_compile.compile(module.__file__)
+ for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat,
+ seconds=seconds):
+ yield result
+ using_bytecode_benchmark.__doc__ = (
+ using_bytecode_benchmark.__doc__.format(name))
+ return using_bytecode_benchmark
-def main(import_):
+tabnanny_using_bytecode = _using_bytecode(tabnanny)
+decimal_using_bytecode = _using_bytecode(decimal)
+
+
+def main(import_, options):
+ if options.source_file:
+ with options.source_file:
+ prev_results = json.load(options.source_file)
+ else:
+ prev_results = {}
__builtins__.__import__ = import_
benchmarks = (from_cache, builtin_mod,
- source_using_bytecode, source_wo_bytecode,
source_writing_bytecode,
- decimal_using_bytecode, decimal_writing_bytecode,
- decimal_wo_bytecode,)
+ source_wo_bytecode, source_using_bytecode,
+ tabnanny_writing_bytecode,
+ tabnanny_wo_bytecode, tabnanny_using_bytecode,
+ decimal_writing_bytecode,
+ decimal_wo_bytecode, decimal_using_bytecode,
+ )
+ if options.benchmark:
+ for b in benchmarks:
+ if b.__doc__ == options.benchmark:
+ benchmarks = [b]
+ break
+ else:
+ print('Unknown benchmark: {!r}'.format(options.benchmark,
+ file=sys.stderr))
+ sys.exit(1)
seconds = 1
seconds_plural = 's' if seconds > 1 else ''
repeat = 3
- header = "Measuring imports/second over {} second{}, best out of {}\n"
- print(header.format(seconds, seconds_plural, repeat))
+ header = ('Measuring imports/second over {} second{}, best out of {}\n'
+ 'Entire benchmark run should take about {} seconds\n'
+ 'Using {!r} as __import__\n')
+ print(header.format(seconds, seconds_plural, repeat,
+ len(benchmarks) * seconds * repeat, __import__))
+ new_results = {}
for benchmark in benchmarks:
print(benchmark.__doc__, "[", end=' ')
sys.stdout.flush()
@@ -154,19 +213,40 @@ def main(import_):
sys.stdout.flush()
assert not sys.dont_write_bytecode
print("]", "best is", format(max(results), ',d'))
+ new_results[benchmark.__doc__] = results
+ if prev_results:
+ print('\n\nComparing new vs. old\n')
+ for benchmark in benchmarks:
+ benchmark_name = benchmark.__doc__
+ old_result = max(prev_results[benchmark_name])
+ new_result = max(new_results[benchmark_name])
+ result = '{:,d} vs. {:,d} ({:%})'.format(new_result,
+ old_result,
+ new_result/old_result)
+ print(benchmark_name, ':', result)
+ if options.dest_file:
+ with options.dest_file:
+ json.dump(new_results, options.dest_file, indent=2)
if __name__ == '__main__':
- import optparse
+ import argparse
- parser = optparse.OptionParser()
- parser.add_option('-b', '--builtin', dest='builtin', action='store_true',
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-b', '--builtin', dest='builtin', action='store_true',
default=False, help="use the built-in __import__")
- options, args = parser.parse_args()
- if args:
- raise RuntimeError("unrecognized args: {}".format(args))
+ parser.add_argument('-r', '--read', dest='source_file',
+ type=argparse.FileType('r'),
+ help='file to read benchmark data from to compare '
+ 'against')
+ parser.add_argument('-w', '--write', dest='dest_file',
+ type=argparse.FileType('w'),
+ help='file to write benchmark data to')
+ parser.add_argument('--benchmark', dest='benchmark',
+ help='specific benchmark to run')
+ options = parser.parse_args()
import_ = __import__
if not options.builtin:
import_ = importlib.__import__
- main(import_)
+ main(import_, options)
diff --git a/Lib/importlib/test/builtin/test_loader.py b/Lib/importlib/test/builtin/test_loader.py
index 1a8539b1e8..ec126c9ccc 100644
--- a/Lib/importlib/test/builtin/test_loader.py
+++ b/Lib/importlib/test/builtin/test_loader.py
@@ -54,15 +54,17 @@ class LoaderTests(abc.LoaderTests):
def test_unloadable(self):
name = 'dssdsdfff'
assert name not in sys.builtin_module_names
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.load_module(name)
+ self.assertEqual(cm.exception.name, name)
def test_already_imported(self):
# Using the name of a module already imported but not a built-in should
# still fail.
assert hasattr(importlib, '__file__') # Not a built-in.
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.load_module('importlib')
+ self.assertEqual(cm.exception.name, 'importlib')
class InspectLoaderTests(unittest.TestCase):
@@ -88,8 +90,9 @@ class InspectLoaderTests(unittest.TestCase):
# Modules not built-in should raise ImportError.
for meth_name in ('get_code', 'get_source', 'is_package'):
method = getattr(machinery.BuiltinImporter, meth_name)
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
method(builtin_util.BAD_NAME)
+ self.assertRaises(builtin_util.BAD_NAME)
diff --git a/Lib/importlib/test/extension/test_case_sensitivity.py b/Lib/importlib/test/extension/test_case_sensitivity.py
index e062fb6597..bdc21e7f99 100644
--- a/Lib/importlib/test/extension/test_case_sensitivity.py
+++ b/Lib/importlib/test/extension/test_case_sensitivity.py
@@ -1,3 +1,4 @@
+import imp
import sys
from test import support
import unittest
@@ -13,19 +14,27 @@ class ExtensionModuleCaseSensitivityTest(unittest.TestCase):
good_name = ext_util.NAME
bad_name = good_name.upper()
assert good_name != bad_name
- finder = _bootstrap._FileFinder(ext_util.PATH,
- _bootstrap._ExtensionFinderDetails())
+ finder = _bootstrap.FileFinder(ext_util.PATH,
+ (_bootstrap.ExtensionFileLoader,
+ imp.extension_suffixes(),
+ False))
return finder.find_module(bad_name)
def test_case_sensitive(self):
with support.EnvironmentVarGuard() as env:
env.unset('PYTHONCASEOK')
+ if b'PYTHONCASEOK' in _bootstrap._os.environ:
+ self.skipTest('os.environ changes not reflected in '
+ '_os.environ')
loader = self.find_module()
self.assertIsNone(loader)
def test_case_insensitivity(self):
with support.EnvironmentVarGuard() as env:
env.set('PYTHONCASEOK', '1')
+ if b'PYTHONCASEOK' not in _bootstrap._os.environ:
+ self.skipTest('os.environ changes not reflected in '
+ '_os.environ')
loader = self.find_module()
self.assertTrue(hasattr(loader, 'load_module'))
diff --git a/Lib/importlib/test/extension/test_finder.py b/Lib/importlib/test/extension/test_finder.py
index ea97483317..804d8628e2 100644
--- a/Lib/importlib/test/extension/test_finder.py
+++ b/Lib/importlib/test/extension/test_finder.py
@@ -2,6 +2,7 @@ from importlib import _bootstrap
from .. import abc
from . import util
+import imp
import unittest
class FinderTests(abc.FinderTests):
@@ -9,8 +10,10 @@ class FinderTests(abc.FinderTests):
"""Test the finder for extension modules."""
def find_module(self, fullname):
- importer = _bootstrap._FileFinder(util.PATH,
- _bootstrap._ExtensionFinderDetails())
+ importer = _bootstrap.FileFinder(util.PATH,
+ (_bootstrap.ExtensionFileLoader,
+ imp.extension_suffixes(),
+ False))
return importer.find_module(fullname)
def test_module(self):
diff --git a/Lib/importlib/test/extension/test_loader.py b/Lib/importlib/test/extension/test_loader.py
index 4a783db8a5..4f486ce6af 100644
--- a/Lib/importlib/test/extension/test_loader.py
+++ b/Lib/importlib/test/extension/test_loader.py
@@ -1,4 +1,4 @@
-from importlib import _bootstrap
+from importlib import machinery
from . import util as ext_util
from .. import abc
from .. import util
@@ -11,10 +11,20 @@ class LoaderTests(abc.LoaderTests):
"""Test load_module() for extension modules."""
+ def setUp(self):
+ self.loader = machinery.ExtensionFileLoader(ext_util.NAME,
+ ext_util.FILEPATH)
+
def load_module(self, fullname):
- loader = _bootstrap._ExtensionFileLoader(ext_util.NAME,
- ext_util.FILEPATH)
- return loader.load_module(fullname)
+ return self.loader.load_module(fullname)
+
+ def test_load_module_API(self):
+ # Test the default argument for load_module().
+ self.loader.load_module()
+ self.loader.load_module(None)
+ with self.assertRaises(ImportError):
+ self.load_module('XXX')
+
def test_module(self):
with util.uncache(ext_util.NAME):
@@ -25,7 +35,7 @@ class LoaderTests(abc.LoaderTests):
self.assertEqual(getattr(module, attr), value)
self.assertTrue(ext_util.NAME in sys.modules)
self.assertTrue(isinstance(module.__loader__,
- _bootstrap._ExtensionFileLoader))
+ machinery.ExtensionFileLoader))
def test_package(self):
# Extensions are not found in packages.
@@ -46,8 +56,10 @@ class LoaderTests(abc.LoaderTests):
pass
def test_unloadable(self):
- with self.assertRaises(ImportError):
- self.load_module('asdfjkl;')
+ name = 'asdfjkl;'
+ with self.assertRaises(ImportError) as cm:
+ self.load_module(name)
+ self.assertEqual(cm.exception.name, name)
def test_main():
diff --git a/Lib/importlib/test/extension/test_path_hook.py b/Lib/importlib/test/extension/test_path_hook.py
index 4610420d29..129e6e2975 100644
--- a/Lib/importlib/test/extension/test_path_hook.py
+++ b/Lib/importlib/test/extension/test_path_hook.py
@@ -14,7 +14,8 @@ class PathHookTests(unittest.TestCase):
# XXX Should it only work for directories containing an extension module?
def hook(self, entry):
- return _bootstrap._file_path_hook(entry)
+ return _bootstrap.FileFinder.path_hook((_bootstrap.ExtensionFileLoader,
+ imp.extension_suffixes(), False))(entry)
def test_success(self):
# Path hook should handle a directory where a known extension module
diff --git a/Lib/importlib/test/extension/util.py b/Lib/importlib/test/extension/util.py
index d149169748..a266dd98c8 100644
--- a/Lib/importlib/test/extension/util.py
+++ b/Lib/importlib/test/extension/util.py
@@ -1,4 +1,5 @@
import imp
+from importlib import machinery
import os
import sys
@@ -6,10 +7,9 @@ PATH = None
EXT = None
FILENAME = None
NAME = '_testcapi'
-_file_exts = [x[0] for x in imp.get_suffixes() if x[2] == imp.C_EXTENSION]
try:
for PATH in sys.path:
- for EXT in _file_exts:
+ for EXT in machinery.EXTENSION_SUFFIXES:
FILENAME = NAME + EXT
FILEPATH = os.path.join(PATH, FILENAME)
if os.path.exists(os.path.join(PATH, FILENAME)):
@@ -18,4 +18,3 @@ try:
PATH = EXT = FILENAME = FILEPATH = None
except StopIteration:
pass
-del _file_exts
diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/importlib/test/frozen/test_loader.py
index b685ef5708..6819a09b87 100644
--- a/Lib/importlib/test/frozen/test_loader.py
+++ b/Lib/importlib/test/frozen/test_loader.py
@@ -10,38 +10,46 @@ class LoaderTests(abc.LoaderTests):
def test_module(self):
with util.uncache('__hello__'), captured_stdout() as stdout:
module = machinery.FrozenImporter.load_module('__hello__')
- check = {'__name__': '__hello__', '__file__': '<frozen>',
- '__package__': '', '__loader__': machinery.FrozenImporter}
+ check = {'__name__': '__hello__',
+ '__package__': '',
+ '__loader__': machinery.FrozenImporter,
+ }
for attr, value in check.items():
self.assertEqual(getattr(module, attr), value)
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
+ self.assertFalse(hasattr(module, '__file__'))
def test_package(self):
with util.uncache('__phello__'), captured_stdout() as stdout:
module = machinery.FrozenImporter.load_module('__phello__')
- check = {'__name__': '__phello__', '__file__': '<frozen>',
- '__package__': '__phello__', '__path__': ['__phello__'],
- '__loader__': machinery.FrozenImporter}
+ check = {'__name__': '__phello__',
+ '__package__': '__phello__',
+ '__path__': ['__phello__'],
+ '__loader__': machinery.FrozenImporter,
+ }
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
"for __phello__.%s, %r != %r" %
(attr, attr_value, value))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
+ self.assertFalse(hasattr(module, '__file__'))
def test_lacking_parent(self):
with util.uncache('__phello__', '__phello__.spam'), \
captured_stdout() as stdout:
module = machinery.FrozenImporter.load_module('__phello__.spam')
- check = {'__name__': '__phello__.spam', '__file__': '<frozen>',
+ check = {'__name__': '__phello__.spam',
'__package__': '__phello__',
- '__loader__': machinery.FrozenImporter}
+ '__loader__': machinery.FrozenImporter,
+ }
for attr, value in check.items():
attr_value = getattr(module, attr)
self.assertEqual(attr_value, value,
"for __phello__.spam.%s, %r != %r" %
(attr, attr_value, value))
self.assertEqual(stdout.getvalue(), 'Hello world!\n')
+ self.assertFalse(hasattr(module, '__file__'))
def test_module_reuse(self):
with util.uncache('__hello__'), captured_stdout() as stdout:
@@ -51,14 +59,21 @@ class LoaderTests(abc.LoaderTests):
self.assertEqual(stdout.getvalue(),
'Hello world!\nHello world!\n')
+ def test_module_repr(self):
+ with util.uncache('__hello__'), captured_stdout():
+ module = machinery.FrozenImporter.load_module('__hello__')
+ self.assertEqual(repr(module),
+ "<module '__hello__' (frozen)>")
+
def test_state_after_failure(self):
# No way to trigger an error in a frozen module.
pass
def test_unloadable(self):
assert machinery.FrozenImporter.find_module('_not_real') is None
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
machinery.FrozenImporter.load_module('_not_real')
+ self.assertEqual(cm.exception.name, '_not_real')
class InspectLoaderTests(unittest.TestCase):
@@ -92,8 +107,9 @@ class InspectLoaderTests(unittest.TestCase):
# Raise ImportError for modules that are not frozen.
for meth_name in ('get_code', 'get_source', 'is_package'):
method = getattr(machinery.FrozenImporter, meth_name)
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
method('importlib')
+ self.assertEqual(cm.exception.name, 'importlib')
def test_main():
diff --git a/Lib/importlib/test/import_/test___package__.py b/Lib/importlib/test/import_/test___package__.py
index 5056ae59cc..783cde1729 100644
--- a/Lib/importlib/test/import_/test___package__.py
+++ b/Lib/importlib/test/import_/test___package__.py
@@ -67,7 +67,7 @@ class Using__package__(unittest.TestCase):
def test_bunk__package__(self):
globals = {'__package__': 42}
- with self.assertRaises(ValueError):
+ with self.assertRaises(TypeError):
import_util.import_('', globals, {}, ['relimport'], 1)
diff --git a/Lib/importlib/test/import_/test_api.py b/Lib/importlib/test/import_/test_api.py
index 9075d42759..2fa1f90954 100644
--- a/Lib/importlib/test/import_/test_api.py
+++ b/Lib/importlib/test/import_/test_api.py
@@ -12,6 +12,13 @@ class APITest(unittest.TestCase):
with self.assertRaises(TypeError):
util.import_(42)
+ def test_negative_level(self):
+ # Raise ValueError when a negative level is specified.
+ # PEP 328 did away with sys.module None entries and the ambiguity of
+ # absolute/relative imports.
+ with self.assertRaises(ValueError):
+ util.import_('os', globals(), level=-1)
+
def test_main():
from test.support import run_unittest
diff --git a/Lib/importlib/test/import_/test_caching.py b/Lib/importlib/test/import_/test_caching.py
index 48dc64311a..3baff5501e 100644
--- a/Lib/importlib/test/import_/test_caching.py
+++ b/Lib/importlib/test/import_/test_caching.py
@@ -34,8 +34,9 @@ class UseCache(unittest.TestCase):
name = 'using_None'
with util.uncache(name):
sys.modules[name] = None
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
import_util.import_(name)
+ self.assertEqual(cm.exception.name, name)
def create_mock(self, *names, return_=None):
mock = util.mock_modules(*names)
diff --git a/Lib/importlib/test/import_/test_fromlist.py b/Lib/importlib/test/import_/test_fromlist.py
index b903e8e611..4ff5f5e825 100644
--- a/Lib/importlib/test/import_/test_fromlist.py
+++ b/Lib/importlib/test/import_/test_fromlist.py
@@ -1,6 +1,7 @@
"""Test that the semantics relating to the 'fromlist' argument are correct."""
from .. import util
from . import util as import_util
+import imp
import unittest
class ReturnValue(unittest.TestCase):
@@ -73,7 +74,8 @@ class HandlingFromlist(unittest.TestCase):
def test_no_module_from_package(self):
# [no module]
with util.mock_modules('pkg.__init__') as importer:
- with util.import_state(meta_path=[importer]):
+ with util.import_state(meta_path=[importer],
+ path_hooks=[imp.NullImporter]):
module = import_util.import_('pkg', fromlist='non_existent')
self.assertEqual(module.__name__, 'pkg')
self.assertTrue(not hasattr(module, 'non_existent'))
diff --git a/Lib/importlib/test/import_/test_meta_path.py b/Lib/importlib/test/import_/test_meta_path.py
index 3b130c9a13..2f65af99a9 100644
--- a/Lib/importlib/test/import_/test_meta_path.py
+++ b/Lib/importlib/test/import_/test_meta_path.py
@@ -1,7 +1,10 @@
from .. import util
from . import util as import_util
+import importlib._bootstrap
+import sys
from types import MethodType
import unittest
+import warnings
class CallingOrder(unittest.TestCase):
@@ -33,6 +36,21 @@ class CallingOrder(unittest.TestCase):
with util.import_state(meta_path=[first, second]):
self.assertEqual(import_util.import_(mod_name), 42)
+ def test_empty(self):
+ # Raise an ImportWarning if sys.meta_path is empty.
+ module_name = 'nothing'
+ try:
+ del sys.modules[module_name]
+ except KeyError:
+ pass
+ with util.import_state(meta_path=[]):
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ self.assertIsNone(importlib._bootstrap._find_module('nothing',
+ None))
+ self.assertEqual(len(w), 1)
+ self.assertTrue(issubclass(w[-1].category, ImportWarning))
+
class CallSignature(unittest.TestCase):
diff --git a/Lib/importlib/test/import_/test_packages.py b/Lib/importlib/test/import_/test_packages.py
index faadc32172..931494d6f7 100644
--- a/Lib/importlib/test/import_/test_packages.py
+++ b/Lib/importlib/test/import_/test_packages.py
@@ -3,6 +3,7 @@ from . import util as import_util
import sys
import unittest
import importlib
+from test import support
class ParentModuleTests(unittest.TestCase):
@@ -18,14 +19,88 @@ class ParentModuleTests(unittest.TestCase):
def test_bad_parent(self):
with util.mock_modules('pkg.module') as mock:
with util.import_state(meta_path=[mock]):
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
import_util.import_('pkg.module')
+ self.assertEqual(cm.exception.name, 'pkg')
+
+ def test_raising_parent_after_importing_child(self):
+ def __init__():
+ import pkg.module
+ 1/0
+ mock = util.mock_modules('pkg.__init__', 'pkg.module',
+ module_code={'pkg': __init__})
+ with mock:
+ with util.import_state(meta_path=[mock]):
+ with self.assertRaises(ZeroDivisionError):
+ import_util.import_('pkg')
+ self.assertFalse('pkg' in sys.modules)
+ self.assertTrue('pkg.module' in sys.modules)
+ with self.assertRaises(ZeroDivisionError):
+ import_util.import_('pkg.module')
+ self.assertFalse('pkg' in sys.modules)
+ self.assertTrue('pkg.module' in sys.modules)
+
+ def test_raising_parent_after_relative_importing_child(self):
+ def __init__():
+ from . import module
+ 1/0
+ mock = util.mock_modules('pkg.__init__', 'pkg.module',
+ module_code={'pkg': __init__})
+ with mock:
+ with util.import_state(meta_path=[mock]):
+ with self.assertRaises((ZeroDivisionError, ImportError)):
+ # This raises ImportError on the "from . import module"
+ # line, not sure why.
+ import_util.import_('pkg')
+ self.assertFalse('pkg' in sys.modules)
+ with self.assertRaises((ZeroDivisionError, ImportError)):
+ import_util.import_('pkg.module')
+ self.assertFalse('pkg' in sys.modules)
+ # XXX False
+ #self.assertTrue('pkg.module' in sys.modules)
+
+ def test_raising_parent_after_double_relative_importing_child(self):
+ def __init__():
+ from ..subpkg import module
+ 1/0
+ mock = util.mock_modules('pkg.__init__', 'pkg.subpkg.__init__',
+ 'pkg.subpkg.module',
+ module_code={'pkg.subpkg': __init__})
+ with mock:
+ with util.import_state(meta_path=[mock]):
+ with self.assertRaises((ZeroDivisionError, ImportError)):
+ # This raises ImportError on the "from ..subpkg import module"
+ # line, not sure why.
+ import_util.import_('pkg.subpkg')
+ self.assertFalse('pkg.subpkg' in sys.modules)
+ with self.assertRaises((ZeroDivisionError, ImportError)):
+ import_util.import_('pkg.subpkg.module')
+ self.assertFalse('pkg.subpkg' in sys.modules)
+ # XXX False
+ #self.assertTrue('pkg.subpkg.module' in sys.modules)
def test_module_not_package(self):
# Try to import a submodule from a non-package should raise ImportError.
assert not hasattr(sys, '__path__')
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
import_util.import_('sys.no_submodules_here')
+ self.assertEqual(cm.exception.name, 'sys.no_submodules_here')
+
+ def test_module_not_package_but_side_effects(self):
+ # If a module injects something into sys.modules as a side-effect, then
+ # pick up on that fact.
+ name = 'mod'
+ subname = name + '.b'
+ def module_injection():
+ sys.modules[subname] = 'total bunk'
+ mock_modules = util.mock_modules('mod',
+ module_code={'mod': module_injection})
+ with mock_modules as mock:
+ with util.import_state(meta_path=[mock]):
+ try:
+ submodule = import_util.import_(subname)
+ finally:
+ support.unload(subname)
def test_main():
diff --git a/Lib/importlib/test/import_/test_path.py b/Lib/importlib/test/import_/test_path.py
index 2faa23174b..723f5b57a8 100644
--- a/Lib/importlib/test/import_/test_path.py
+++ b/Lib/importlib/test/import_/test_path.py
@@ -9,6 +9,7 @@ import tempfile
from test import support
from types import MethodType
import unittest
+import warnings
class FinderTests(unittest.TestCase):
@@ -42,6 +43,15 @@ class FinderTests(unittest.TestCase):
loader = machinery.PathFinder.find_module(module, [path])
self.assertTrue(loader is importer)
+ def test_empty_list(self):
+ # An empty list should not count as asking for sys.path.
+ module = 'module'
+ path = '<test path>'
+ importer = util.mock_modules(module)
+ with util.import_state(path_importer_cache={path: importer},
+ path=[path]):
+ self.assertIsNone(machinery.PathFinder.find_module('module', []))
+
def test_path_hooks(self):
# Test that sys.path_hooks is used.
# Test that sys.path_importer_cache is set.
@@ -55,77 +65,34 @@ class FinderTests(unittest.TestCase):
self.assertTrue(path in sys.path_importer_cache)
self.assertTrue(sys.path_importer_cache[path] is importer)
- def test_path_importer_cache_has_None(self):
- # Test that if sys.path_importer_cache has None that None is returned.
- clear_cache = {path: None for path in sys.path}
- with util.import_state(path_importer_cache=clear_cache):
- for name in ('asynchat', 'sys', '<test module>'):
- self.assertTrue(machinery.PathFinder.find_module(name) is None)
-
- def test_path_importer_cache_has_None_continues(self):
- # Test that having None in sys.path_importer_cache causes the search to
- # continue.
- path = '<test path>'
+ def test_empty_path_hooks(self):
+ # Test that if sys.path_hooks is empty a warning is raised,
+ # sys.path_importer_cache gets None set, and PathFinder returns None.
+ path_entry = 'bogus_path'
+ with util.import_state(path_importer_cache={}, path_hooks=[],
+ path=[path_entry]):
+ with warnings.catch_warnings(record=True) as w:
+ warnings.simplefilter('always')
+ self.assertIsNone(machinery.PathFinder.find_module('os'))
+ self.assertIsNone(sys.path_importer_cache[path_entry])
+ self.assertEqual(len(w), 1)
+ self.assertTrue(issubclass(w[-1].category, ImportWarning))
+
+ def test_path_importer_cache_empty_string(self):
+ # The empty string should create a finder using the cwd.
+ path = ''
module = '<test module>'
importer = util.mock_modules(module)
- with util.import_state(path=['1', '2'],
- path_importer_cache={'1': None, '2': importer}):
+ hook = import_util.mock_path_hook(os.curdir, importer=importer)
+ with util.import_state(path=[path], path_hooks=[hook]):
loader = machinery.PathFinder.find_module(module)
- self.assertTrue(loader is importer)
-
-
-
-class DefaultPathFinderTests(unittest.TestCase):
-
- """Test importlib._bootstrap._DefaultPathFinder."""
-
- def test_implicit_hooks(self):
- # Test that the implicit path hooks are used.
- bad_path = '<path>'
- module = '<module>'
- assert not os.path.exists(bad_path)
- existing_path = tempfile.mkdtemp()
- try:
- with util.import_state():
- nothing = _bootstrap._DefaultPathFinder.find_module(module,
- path=[existing_path])
- self.assertTrue(nothing is None)
- self.assertTrue(existing_path in sys.path_importer_cache)
- result = isinstance(sys.path_importer_cache[existing_path],
- imp.NullImporter)
- self.assertFalse(result)
- nothing = _bootstrap._DefaultPathFinder.find_module(module,
- path=[bad_path])
- self.assertTrue(nothing is None)
- self.assertTrue(bad_path in sys.path_importer_cache)
- self.assertTrue(isinstance(sys.path_importer_cache[bad_path],
- imp.NullImporter))
- finally:
- os.rmdir(existing_path)
-
-
- def test_path_importer_cache_has_None(self):
- # Test that the default hook is used when sys.path_importer_cache
- # contains None for a path.
- module = '<test module>'
- importer = util.mock_modules(module)
- path = '<test path>'
- # XXX Not blackbox.
- original_hook = _bootstrap._DEFAULT_PATH_HOOK
- mock_hook = import_util.mock_path_hook(path, importer=importer)
- _bootstrap._DEFAULT_PATH_HOOK = mock_hook
- try:
- with util.import_state(path_importer_cache={path: None}):
- loader = _bootstrap._DefaultPathFinder.find_module(module,
- path=[path])
- self.assertTrue(loader is importer)
- finally:
- _bootstrap._DEFAULT_PATH_HOOK = original_hook
+ self.assertIs(loader, importer)
+ self.assertIn(os.curdir, sys.path_importer_cache)
def test_main():
from test.support import run_unittest
- run_unittest(FinderTests, DefaultPathFinderTests)
+ run_unittest(FinderTests)
if __name__ == '__main__':
test_main()
diff --git a/Lib/importlib/test/import_/test_relative_imports.py b/Lib/importlib/test/import_/test_relative_imports.py
index a0f6b2d827..4569c26424 100644
--- a/Lib/importlib/test/import_/test_relative_imports.py
+++ b/Lib/importlib/test/import_/test_relative_imports.py
@@ -193,6 +193,20 @@ class RelativeImports(unittest.TestCase):
self.assertEqual(module.__name__, '__runpy_pkg__.uncle.cousin')
self.relative_import_test(create, globals_, callback)
+ def test_import_relative_import_no_fromlist(self):
+ # Import a relative module w/ no fromlist.
+ create = ['crash.__init__', 'crash.mod']
+ globals_ = [{'__package__': 'crash', '__name__': 'crash'}]
+ def callback(global_):
+ import_util.import_('crash')
+ mod = import_util.import_('mod', global_, {}, [], 1)
+ self.assertEqual(mod.__name__, 'crash.mod')
+ self.relative_import_test(create, globals_, callback)
+
+ def test_relative_import_no_globals(self):
+ # No globals for a relative import is an error.
+ with self.assertRaises(KeyError):
+ import_util.import_('sys', level=1)
def test_main():
diff --git a/Lib/importlib/test/import_/util.py b/Lib/importlib/test/import_/util.py
index 649c5ed27c..86ac065e64 100644
--- a/Lib/importlib/test/import_/util.py
+++ b/Lib/importlib/test/import_/util.py
@@ -1,6 +1,5 @@
import functools
import importlib
-import importlib._bootstrap
import unittest
diff --git a/Lib/importlib/test/regrtest.py b/Lib/importlib/test/regrtest.py
index b103ae7d0e..a5be11fd4e 100644
--- a/Lib/importlib/test/regrtest.py
+++ b/Lib/importlib/test/regrtest.py
@@ -5,13 +5,6 @@ invalidates are automatically skipped if the entire test suite is run.
Otherwise all command-line options valid for test.regrtest are also valid for
this script.
-XXX FAILING
- * test_import
- - test_incorrect_code_name
- file name differing between __file__ and co_filename (r68360 on trunk)
- - test_import_by_filename
- exception for trying to import by file name does not match
-
"""
import importlib
import sys
@@ -19,17 +12,6 @@ from test import regrtest
if __name__ == '__main__':
__builtins__.__import__ = importlib.__import__
-
- exclude = ['--exclude',
- 'test_frozen', # Does not expect __loader__ attribute
- 'test_pkg', # Does not expect __loader__ attribute
- 'test_pydoc', # Does not expect __loader__ attribute
- ]
-
- # Switching on --exclude implies running all test but the ones listed, so
- # only use it when one is not running an explicit test
- if len(sys.argv) == 1:
- # No programmatic way to specify tests to exclude
- sys.argv.extend(exclude)
+ sys.path_importer_cache.clear()
regrtest.main(quiet=True, verbose2=True)
diff --git a/Lib/importlib/test/source/test_abc_loader.py b/Lib/importlib/test/source/test_abc_loader.py
index 32459074a0..b1b1204197 100644
--- a/Lib/importlib/test/source/test_abc_loader.py
+++ b/Lib/importlib/test/source/test_abc_loader.py
@@ -40,8 +40,10 @@ class SourceLoaderMock(SourceOnlyLoaderMock):
def __init__(self, path, magic=imp.get_magic()):
super().__init__(path)
self.bytecode_path = imp.cache_from_source(self.path)
+ self.source_size = len(self.source)
data = bytearray(magic)
- data.extend(marshal._w_long(self.source_mtime))
+ data.extend(importlib._w_long(self.source_mtime))
+ data.extend(importlib._w_long(self.source_size))
code_object = compile(self.source, self.path, 'exec',
dont_inherit=True)
data.extend(marshal.dumps(code_object))
@@ -56,9 +58,9 @@ class SourceLoaderMock(SourceOnlyLoaderMock):
else:
raise IOError
- def path_mtime(self, path):
+ def path_stats(self, path):
assert path == self.path
- return self.source_mtime
+ return {'mtime': self.source_mtime, 'size': self.source_size}
def set_data(self, path, data):
self.written[path] = bytes(data)
@@ -102,7 +104,7 @@ class PyLoaderMock(abc.PyLoader):
warnings.simplefilter("always")
path = super().get_filename(name)
assert len(w) == 1
- assert issubclass(w[0].category, PendingDeprecationWarning)
+ assert issubclass(w[0].category, DeprecationWarning)
return path
@@ -198,7 +200,7 @@ class PyPycLoaderMock(abc.PyPycLoader, PyLoaderMock):
warnings.simplefilter("always")
code_object = super().get_code(name)
assert len(w) == 1
- assert issubclass(w[0].category, PendingDeprecationWarning)
+ assert issubclass(w[0].category, DeprecationWarning)
return code_object
class PyLoaderTests(testing_abc.LoaderTests):
@@ -469,8 +471,9 @@ class BadBytecodeFailureTests(unittest.TestCase):
{'path': os.path.join('path', 'to', 'mod'),
'magic': bad_magic}}
mock = PyPycLoaderMock({name: None}, bc)
- with util.uncache(name), self.assertRaises(ImportError):
+ with util.uncache(name), self.assertRaises(ImportError) as cm:
mock.load_module(name)
+ self.assertEqual(cm.exception.name, name)
def test_no_bytecode(self):
# Missing code object bytecode should lead to an EOFError.
@@ -514,8 +517,9 @@ class MissingPathsTests(unittest.TestCase):
# If all *_path methods return None, raise ImportError.
name = 'mod'
mock = PyPycLoaderMock({name: None})
- with util.uncache(name), self.assertRaises(ImportError):
+ with util.uncache(name), self.assertRaises(ImportError) as cm:
mock.load_module(name)
+ self.assertEqual(cm.exception.name, name)
def test_source_path_ImportError(self):
# An ImportError from source_path should trigger an ImportError.
@@ -531,7 +535,7 @@ class MissingPathsTests(unittest.TestCase):
mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')})
bad_meth = types.MethodType(raise_ImportError, mock)
mock.bytecode_path = bad_meth
- with util.uncache(name), self.assertRaises(ImportError):
+ with util.uncache(name), self.assertRaises(ImportError) as cm:
mock.load_module(name)
@@ -592,8 +596,9 @@ class SourceOnlyLoaderTests(SourceLoaderTestHarness):
def raise_IOError(path):
raise IOError
self.loader.get_data = raise_IOError
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.loader.get_source(self.name)
+ self.assertEqual(cm.exception.name, self.name)
def test_is_package(self):
# Properly detect when loading a package.
@@ -656,7 +661,8 @@ class SourceLoaderBytecodeTests(SourceLoaderTestHarness):
if bytecode_written:
self.assertIn(self.cached, self.loader.written)
data = bytearray(imp.get_magic())
- data.extend(marshal._w_long(self.loader.source_mtime))
+ data.extend(importlib._w_long(self.loader.source_mtime))
+ data.extend(importlib._w_long(self.loader.source_size))
data.extend(marshal.dumps(code_object))
self.assertEqual(self.loader.written[self.cached], bytes(data))
@@ -847,7 +853,7 @@ class AbstractMethodImplTests(unittest.TestCase):
# Required abstractmethods.
self.raises_NotImplementedError(ins, 'get_filename', 'get_data')
# Optional abstractmethods.
- self.raises_NotImplementedError(ins,'path_mtime', 'set_data')
+ self.raises_NotImplementedError(ins,'path_stats', 'set_data')
def test_PyLoader(self):
self.raises_NotImplementedError(self.PyLoader(), 'source_path',
diff --git a/Lib/importlib/test/source/test_case_sensitivity.py b/Lib/importlib/test/source/test_case_sensitivity.py
index 73777de4ba..21a4378ce9 100644
--- a/Lib/importlib/test/source/test_case_sensitivity.py
+++ b/Lib/importlib/test/source/test_case_sensitivity.py
@@ -1,7 +1,9 @@
"""Test case-sensitivity (PEP 235)."""
from importlib import _bootstrap
+from importlib import machinery
from .. import util
from . import util as source_util
+import imp
import os
import sys
from test import support as test_support
@@ -19,9 +21,13 @@ class CaseSensitivityTest(unittest.TestCase):
assert name != name.lower()
def find(self, path):
- finder = _bootstrap._FileFinder(path,
- _bootstrap._SourceFinderDetails(),
- _bootstrap._SourcelessFinderDetails())
+ finder = machinery.FileFinder(path,
+ (machinery.SourceFileLoader,
+ machinery.SOURCE_SUFFIXES,
+ True),
+ (machinery.SourcelessFileLoader,
+ machinery.BYTECODE_SUFFIXES,
+ True))
return finder.find_module(self.name)
def sensitivity_test(self):
@@ -37,6 +43,9 @@ class CaseSensitivityTest(unittest.TestCase):
def test_sensitive(self):
with test_support.EnvironmentVarGuard() as env:
env.unset('PYTHONCASEOK')
+ if b'PYTHONCASEOK' in _bootstrap._os.environ:
+ self.skipTest('os.environ changes not reflected in '
+ '_os.environ')
sensitive, insensitive = self.sensitivity_test()
self.assertTrue(hasattr(sensitive, 'load_module'))
self.assertIn(self.name, sensitive.get_filename(self.name))
@@ -45,6 +54,9 @@ class CaseSensitivityTest(unittest.TestCase):
def test_insensitive(self):
with test_support.EnvironmentVarGuard() as env:
env.set('PYTHONCASEOK', '1')
+ if b'PYTHONCASEOK' not in _bootstrap._os.environ:
+ self.skipTest('os.environ changes not reflected in '
+ '_os.environ')
sensitive, insensitive = self.sensitivity_test()
self.assertTrue(hasattr(sensitive, 'load_module'))
self.assertIn(self.name, sensitive.get_filename(self.name))
diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py
index c7a7d8fbca..ffa0c24e09 100644
--- a/Lib/importlib/test/source/test_file_loader.py
+++ b/Lib/importlib/test/source/test_file_loader.py
@@ -1,5 +1,6 @@
+from ... import _bootstrap
import importlib
-from importlib import _bootstrap
+import importlib.abc
from .. import abc
from .. import util
from . import util as source_util
@@ -24,10 +25,44 @@ class SimpleTest(unittest.TestCase):
"""
+ def test_load_module_API(self):
+ # If fullname is not specified that assume self.name is desired.
+ class TesterMixin(importlib.abc.Loader):
+ def load_module(self, fullname): return fullname
+
+ class Tester(importlib.abc.FileLoader, TesterMixin):
+ def get_code(self, _): pass
+ def get_source(self, _): pass
+ def is_package(self, _): pass
+
+ name = 'mod_name'
+ loader = Tester(name, 'some_path')
+ self.assertEqual(name, loader.load_module())
+ self.assertEqual(name, loader.load_module(None))
+ self.assertEqual(name, loader.load_module(name))
+ with self.assertRaises(ImportError):
+ loader.load_module(loader.name + 'XXX')
+
+ def test_get_filename_API(self):
+ # If fullname is not set then assume self.path is desired.
+ class Tester(importlib.abc.FileLoader):
+ def get_code(self, _): pass
+ def get_source(self, _): pass
+ def is_package(self, _): pass
+
+ path = 'some_path'
+ name = 'some_name'
+ loader = Tester(name, path)
+ self.assertEqual(path, loader.get_filename(name))
+ self.assertEqual(path, loader.get_filename())
+ self.assertEqual(path, loader.get_filename(None))
+ with self.assertRaises(ImportError):
+ loader.get_filename(name + 'XXX')
+
# [basic]
def test_module(self):
with source_util.create_modules('_temp') as mapping:
- loader = _bootstrap._SourceFileLoader('_temp', mapping['_temp'])
+ loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp'])
module = loader.load_module('_temp')
self.assertTrue('_temp' in sys.modules)
check = {'__name__': '_temp', '__file__': mapping['_temp'],
@@ -37,7 +72,7 @@ class SimpleTest(unittest.TestCase):
def test_package(self):
with source_util.create_modules('_pkg.__init__') as mapping:
- loader = _bootstrap._SourceFileLoader('_pkg',
+ loader = _bootstrap.SourceFileLoader('_pkg',
mapping['_pkg.__init__'])
module = loader.load_module('_pkg')
self.assertTrue('_pkg' in sys.modules)
@@ -50,7 +85,7 @@ class SimpleTest(unittest.TestCase):
def test_lacking_parent(self):
with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping:
- loader = _bootstrap._SourceFileLoader('_pkg.mod',
+ loader = _bootstrap.SourceFileLoader('_pkg.mod',
mapping['_pkg.mod'])
module = loader.load_module('_pkg.mod')
self.assertTrue('_pkg.mod' in sys.modules)
@@ -65,17 +100,12 @@ class SimpleTest(unittest.TestCase):
def test_module_reuse(self):
with source_util.create_modules('_temp') as mapping:
- loader = _bootstrap._SourceFileLoader('_temp', mapping['_temp'])
+ loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp'])
module = loader.load_module('_temp')
module_id = id(module)
module_dict_id = id(module.__dict__)
with open(mapping['_temp'], 'w') as file:
file.write("testing_var = 42\n")
- # For filesystems where the mtime is only to a second granularity,
- # everything that has happened above can be too fast;
- # force an mtime on the source that is guaranteed to be different
- # than the original mtime.
- loader.path_mtime = self.fake_mtime(loader.path_mtime)
module = loader.load_module('_temp')
self.assertTrue('testing_var' in module.__dict__,
"'testing_var' not in "
@@ -95,7 +125,7 @@ class SimpleTest(unittest.TestCase):
setattr(orig_module, attr, value)
with open(mapping[name], 'w') as file:
file.write('+++ bad syntax +++')
- loader = _bootstrap._SourceFileLoader('_temp', mapping['_temp'])
+ loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp'])
with self.assertRaises(SyntaxError):
loader.load_module(name)
for attr in attributes:
@@ -106,7 +136,7 @@ class SimpleTest(unittest.TestCase):
with source_util.create_modules('_temp') as mapping:
with open(mapping['_temp'], 'w') as file:
file.write('=')
- loader = _bootstrap._SourceFileLoader('_temp', mapping['_temp'])
+ loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp'])
with self.assertRaises(SyntaxError):
loader.load_module('_temp')
self.assertTrue('_temp' not in sys.modules)
@@ -119,7 +149,7 @@ class SimpleTest(unittest.TestCase):
file.write("# test file for importlib")
try:
with util.uncache('_temp'):
- loader = _bootstrap._SourceFileLoader('_temp', file_path)
+ loader = _bootstrap.SourceFileLoader('_temp', file_path)
mod = loader.load_module('_temp')
self.assertEqual(file_path, mod.__file__)
self.assertEqual(imp.cache_from_source(file_path),
@@ -145,7 +175,7 @@ class SimpleTest(unittest.TestCase):
if e.errno != getattr(errno, 'EOVERFLOW', None):
raise
self.skipTest("cannot set modification time to large integer ({})".format(e))
- loader = _bootstrap._SourceFileLoader('_temp', mapping['_temp'])
+ loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp'])
mod = loader.load_module('_temp')
# Sanity checks.
self.assertEqual(mod.__cached__, compiled)
@@ -215,10 +245,17 @@ class BadBytecodeTest(unittest.TestCase):
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:
+ 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:
bc_path = self.manipulate_bytecode('_temp', mapping,
- lambda bc: bc[:8],
+ lambda bc: bc[:12],
del_source=del_source)
file_path = mapping['_temp'] if not del_source else bc_path
with self.assertRaises(EOFError):
@@ -227,16 +264,18 @@ class BadBytecodeTest(unittest.TestCase):
def _test_non_code_marshal(self, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
bytecode_path = self.manipulate_bytecode('_temp', mapping,
- lambda bc: bc[:8] + marshal.dumps(b'abcd'),
+ lambda bc: bc[:12] + marshal.dumps(b'abcd'),
del_source=del_source)
file_path = mapping['_temp'] if not del_source else bytecode_path
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.import_(file_path, '_temp')
+ self.assertEqual(cm.exception.name, '_temp')
+ self.assertEqual(cm.exception.path, bytecode_path)
def _test_bad_marshal(self, *, del_source=False):
with source_util.create_modules('_temp') as mapping:
bytecode_path = self.manipulate_bytecode('_temp', mapping,
- lambda bc: bc[:8] + b'<test>',
+ lambda bc: bc[:12] + b'<test>',
del_source=del_source)
file_path = mapping['_temp'] if not del_source else bytecode_path
with self.assertRaises(EOFError):
@@ -251,7 +290,7 @@ class BadBytecodeTest(unittest.TestCase):
class SourceLoaderBadBytecodeTest(BadBytecodeTest):
- loader = _bootstrap._SourceFileLoader
+ loader = _bootstrap.SourceFileLoader
@source_util.writes_bytecode_files
def test_empty_file(self):
@@ -260,7 +299,7 @@ class SourceLoaderBadBytecodeTest(BadBytecodeTest):
def test(name, mapping, bytecode_path):
self.import_(mapping[name], name)
with open(bytecode_path, 'rb') as file:
- self.assertGreater(len(file.read()), 8)
+ self.assertGreater(len(file.read()), 12)
self._test_empty_file(test)
@@ -268,7 +307,7 @@ class SourceLoaderBadBytecodeTest(BadBytecodeTest):
def test(name, mapping, bytecode_path):
self.import_(mapping[name], name)
with open(bytecode_path, 'rb') as file:
- self.assertGreater(len(file.read()), 8)
+ self.assertGreater(len(file.read()), 12)
self._test_partial_magic(test)
@@ -279,7 +318,7 @@ class SourceLoaderBadBytecodeTest(BadBytecodeTest):
def test(name, mapping, bytecode_path):
self.import_(mapping[name], name)
with open(bytecode_path, 'rb') as file:
- self.assertGreater(len(file.read()), 8)
+ self.assertGreater(len(file.read()), 12)
self._test_magic_only(test)
@@ -301,11 +340,22 @@ class SourceLoaderBadBytecodeTest(BadBytecodeTest):
def test(name, mapping, bc_path):
self.import_(mapping[name], name)
with open(bc_path, 'rb') as file:
- self.assertGreater(len(file.read()), 8)
+ self.assertGreater(len(file.read()), 12)
self._test_partial_timestamp(test)
@source_util.writes_bytecode_files
+ def test_partial_size(self):
+ # When the size is partial, regenerate the .pyc, else
+ # raise EOFError.
+ def test(name, mapping, bc_path):
+ self.import_(mapping[name], name)
+ with open(bc_path, 'rb') as file:
+ self.assertGreater(len(file.read()), 12)
+
+ self._test_partial_size(test)
+
+ @source_util.writes_bytecode_files
def test_no_marshal(self):
# When there is only the magic number and timestamp, raise EOFError.
self._test_no_marshal()
@@ -364,19 +414,23 @@ class SourceLoaderBadBytecodeTest(BadBytecodeTest):
class SourcelessLoaderBadBytecodeTest(BadBytecodeTest):
- loader = _bootstrap._SourcelessFileLoader
+ loader = _bootstrap.SourcelessFileLoader
def test_empty_file(self):
def test(name, mapping, bytecode_path):
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.import_(bytecode_path, name)
+ self.assertEqual(cm.exception.name, name)
+ self.assertEqual(cm.exception.path, bytecode_path)
self._test_empty_file(test, del_source=True)
def test_partial_magic(self):
def test(name, mapping, bytecode_path):
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.import_(bytecode_path, name)
+ self.assertEqual(cm.exception.name, name)
+ self.assertEqual(cm.exception.path, bytecode_path)
self._test_partial_magic(test, del_source=True)
def test_magic_only(self):
@@ -388,8 +442,10 @@ class SourcelessLoaderBadBytecodeTest(BadBytecodeTest):
def test_bad_magic(self):
def test(name, mapping, bytecode_path):
- with self.assertRaises(ImportError):
+ with self.assertRaises(ImportError) as cm:
self.import_(bytecode_path, name)
+ self.assertEqual(cm.exception.name, name)
+ self.assertEqual(cm.exception.path, bytecode_path)
self._test_bad_magic(test, del_source=True)
@@ -400,6 +456,13 @@ class SourcelessLoaderBadBytecodeTest(BadBytecodeTest):
self._test_partial_timestamp(test, del_source=True)
+ def test_partial_size(self):
+ def test(name, mapping, bytecode_path):
+ with self.assertRaises(EOFError):
+ self.import_(bytecode_path, name)
+
+ self._test_partial_size(test, del_source=True)
+
def test_no_marshal(self):
self._test_no_marshal(del_source=True)
diff --git a/Lib/importlib/test/source/test_finder.py b/Lib/importlib/test/source/test_finder.py
index 7b9088da0c..a3fa21d65e 100644
--- a/Lib/importlib/test/source/test_finder.py
+++ b/Lib/importlib/test/source/test_finder.py
@@ -1,10 +1,12 @@
-from importlib import _bootstrap
from .. import abc
from . import util as source_util
-from test.support import make_legacy_pyc
-import os
+
+from importlib import machinery
import errno
+import imp
+import os
import py_compile
+from test.support import make_legacy_pyc
import unittest
import warnings
@@ -34,9 +36,11 @@ class FinderTests(abc.FinderTests):
"""
def import_(self, root, module):
- finder = _bootstrap._FileFinder(root,
- _bootstrap._SourceFinderDetails(),
- _bootstrap._SourcelessFinderDetails())
+ loader_details = [(machinery.SourceFileLoader,
+ machinery.SOURCE_SUFFIXES, True),
+ (machinery.SourcelessFileLoader,
+ machinery.BYTECODE_SUFFIXES, True)]
+ finder = machinery.FileFinder(root, *loader_details)
return finder.find_module(module)
def run_test(self, test, create=None, *, compile_=None, unlink=None):
@@ -102,39 +106,21 @@ class FinderTests(abc.FinderTests):
loader = self.import_(pkg_dir, 'pkg.sub')
self.assertTrue(hasattr(loader, 'load_module'))
- # [sub empty]
- def test_empty_sub_directory(self):
- context = source_util.create_modules('pkg.__init__', 'pkg.sub.__init__')
- with warnings.catch_warnings():
- warnings.simplefilter("error", ImportWarning)
- with context as mapping:
- os.unlink(mapping['pkg.sub.__init__'])
- pkg_dir = os.path.dirname(mapping['pkg.__init__'])
- with self.assertRaises(ImportWarning):
- self.import_(pkg_dir, 'pkg.sub')
-
# [package over modules]
def test_package_over_module(self):
name = '_temp'
loader = self.run_test(name, {'{0}.__init__'.format(name), name})
self.assertTrue('__init__' in loader.get_filename(name))
-
def test_failure(self):
with source_util.create_modules('blah') as mapping:
nothing = self.import_(mapping['.root'], 'sdfsadsadf')
self.assertTrue(nothing is None)
- # [empty dir]
- def test_empty_dir(self):
- with warnings.catch_warnings():
- warnings.simplefilter("error", ImportWarning)
- with self.assertRaises(ImportWarning):
- self.run_test('pkg', {'pkg.__init__'}, unlink={'pkg.__init__'})
-
def test_empty_string_for_dir(self):
# The empty string from sys.path means to search in the cwd.
- finder = _bootstrap._FileFinder('', _bootstrap._SourceFinderDetails())
+ finder = machinery.FileFinder('', (machinery.SourceFileLoader,
+ machinery.SOURCE_SUFFIXES, True))
with open('mod.py', 'w') as file:
file.write("# test file for importlib")
try:
@@ -143,6 +129,14 @@ class FinderTests(abc.FinderTests):
finally:
os.unlink('mod.py')
+ def test_invalidate_caches(self):
+ # invalidate_caches() should reset the mtime.
+ finder = machinery.FileFinder('', (machinery.SourceFileLoader,
+ machinery.SOURCE_SUFFIXES, True))
+ finder._path_mtime = 42
+ finder.invalidate_caches()
+ self.assertEqual(finder._path_mtime, -1)
+
def test_main():
from test.support import run_unittest
diff --git a/Lib/importlib/test/source/test_path_hook.py b/Lib/importlib/test/source/test_path_hook.py
index 374f7b6ad3..54c0699501 100644
--- a/Lib/importlib/test/source/test_path_hook.py
+++ b/Lib/importlib/test/source/test_path_hook.py
@@ -1,5 +1,7 @@
-from importlib import _bootstrap
from . import util as source_util
+
+from importlib import machinery
+import imp
import unittest
@@ -7,14 +9,18 @@ class PathHookTest(unittest.TestCase):
"""Test the path hook for source."""
+ def path_hook(self):
+ return machinery.FileFinder.path_hook((machinery.SourceFileLoader,
+ machinery.SOURCE_SUFFIXES, True))
+
def test_success(self):
with source_util.create_modules('dummy') as mapping:
- self.assertTrue(hasattr(_bootstrap._file_path_hook(mapping['.root']),
+ self.assertTrue(hasattr(self.path_hook()(mapping['.root']),
'find_module'))
def test_empty_string(self):
# The empty string represents the cwd.
- self.assertTrue(hasattr(_bootstrap._file_path_hook(''), 'find_module'))
+ self.assertTrue(hasattr(self.path_hook()(''), 'find_module'))
def test_main():
diff --git a/Lib/importlib/test/source/test_source_encoding.py b/Lib/importlib/test/source/test_source_encoding.py
index 794a3df246..0ca5195439 100644
--- a/Lib/importlib/test/source/test_source_encoding.py
+++ b/Lib/importlib/test/source/test_source_encoding.py
@@ -1,6 +1,6 @@
-from importlib import _bootstrap
from . import util as source_util
+from importlib import _bootstrap
import codecs
import re
import sys
@@ -35,8 +35,8 @@ class EncodingTest(unittest.TestCase):
with source_util.create_modules(self.module_name) as mapping:
with open(mapping[self.module_name], 'wb') as file:
file.write(source)
- loader = _bootstrap._SourceFileLoader(self.module_name,
- mapping[self.module_name])
+ loader = _bootstrap.SourceFileLoader(self.module_name,
+ mapping[self.module_name])
return loader.load_module(self.module_name)
def create_source(self, encoding):
@@ -97,7 +97,7 @@ class LineEndingTest(unittest.TestCase):
with source_util.create_modules(module_name) as mapping:
with open(mapping[module_name], 'wb') as file:
file.write(source)
- loader = _bootstrap._SourceFileLoader(module_name,
+ loader = _bootstrap.SourceFileLoader(module_name,
mapping[module_name])
return loader.load_module(module_name)
diff --git a/Lib/importlib/test/test_abc.py b/Lib/importlib/test/test_abc.py
index 0ecbe390ad..008bd21ff8 100644
--- a/Lib/importlib/test/test_abc.py
+++ b/Lib/importlib/test/test_abc.py
@@ -50,7 +50,7 @@ class InspectLoader(InheritanceTests, unittest.TestCase):
superclasses = [abc.Loader]
subclasses = [abc.PyLoader, machinery.BuiltinImporter,
- machinery.FrozenImporter]
+ machinery.FrozenImporter, machinery.ExtensionFileLoader]
class ExecutionLoader(InheritanceTests, unittest.TestCase):
@@ -59,9 +59,16 @@ class ExecutionLoader(InheritanceTests, unittest.TestCase):
subclasses = [abc.PyLoader]
+class FileLoader(InheritanceTests, unittest.TestCase):
+
+ superclasses = [abc.ResourceLoader, abc.ExecutionLoader]
+ subclasses = [machinery.SourceFileLoader, machinery.SourcelessFileLoader]
+
+
class SourceLoader(InheritanceTests, unittest.TestCase):
superclasses = [abc.ResourceLoader, abc.ExecutionLoader]
+ subclasses = [machinery.SourceFileLoader]
class PyLoader(InheritanceTests, unittest.TestCase):
diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py
index a151626de7..b7d6cb4eff 100644
--- a/Lib/importlib/test/test_api.py
+++ b/Lib/importlib/test/test_api.py
@@ -84,9 +84,85 @@ class ImportModuleTests(unittest.TestCase):
importlib.import_module('a.b')
self.assertEqual(b_load_count, 1)
+
+class FindLoaderTests(unittest.TestCase):
+
+ class FakeMetaFinder:
+ @staticmethod
+ def find_module(name, path=None): return name, path
+
+ def test_sys_modules(self):
+ # If a module with __loader__ is in sys.modules, then return it.
+ name = 'some_mod'
+ with util.uncache(name):
+ module = imp.new_module(name)
+ loader = 'a loader!'
+ module.__loader__ = loader
+ sys.modules[name] = module
+ found = importlib.find_loader(name)
+ self.assertEqual(loader, found)
+
+ def test_sys_modules_loader_is_None(self):
+ # If sys.modules[name].__loader__ is None, raise ValueError.
+ name = 'some_mod'
+ with util.uncache(name):
+ module = imp.new_module(name)
+ module.__loader__ = None
+ sys.modules[name] = module
+ with self.assertRaises(ValueError):
+ importlib.find_loader(name)
+
+ def test_success(self):
+ # Return the loader found on sys.meta_path.
+ name = 'some_mod'
+ with util.uncache(name):
+ with util.import_state(meta_path=[self.FakeMetaFinder]):
+ self.assertEqual((name, None), importlib.find_loader(name))
+
+ def test_success_path(self):
+ # Searching on a path should work.
+ name = 'some_mod'
+ path = 'path to some place'
+ with util.uncache(name):
+ with util.import_state(meta_path=[self.FakeMetaFinder]):
+ self.assertEqual((name, path),
+ importlib.find_loader(name, path))
+
+ def test_nothing(self):
+ # None is returned upon failure to find a loader.
+ self.assertIsNone(importlib.find_loader('nevergoingtofindthismodule'))
+
+
+class InvalidateCacheTests(unittest.TestCase):
+
+ def test_method_called(self):
+ # If defined the method should be called.
+ class InvalidatingNullFinder:
+ def __init__(self, *ignored):
+ self.called = False
+ def find_module(self, *args):
+ return None
+ def invalidate_caches(self):
+ self.called = True
+
+ key = 'gobledeegook'
+ ins = InvalidatingNullFinder()
+ sys.path_importer_cache[key] = ins
+ self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key))
+ importlib.invalidate_caches()
+ self.assertTrue(ins.called)
+
+ def test_method_lacking(self):
+ # There should be no issues if the method is not defined.
+ key = 'gobbledeegook'
+ sys.path_importer_cache[key] = imp.NullImporter('abc')
+ self.addCleanup(lambda: sys.path_importer_cache.__delitem__(key))
+ importlib.invalidate_caches() # Shouldn't trigger an exception.
+
+
def test_main():
from test.support import run_unittest
- run_unittest(ImportModuleTests)
+ run_unittest(ImportModuleTests, FindLoaderTests, InvalidateCacheTests)
if __name__ == '__main__':
diff --git a/Lib/importlib/test/test_locks.py b/Lib/importlib/test/test_locks.py
new file mode 100644
index 0000000000..35a72d4cad
--- /dev/null
+++ b/Lib/importlib/test/test_locks.py
@@ -0,0 +1,115 @@
+from importlib import _bootstrap
+import time
+import unittest
+import weakref
+
+from test import support
+
+try:
+ import threading
+except ImportError:
+ threading = None
+else:
+ from test import lock_tests
+
+
+LockType = _bootstrap._ModuleLock
+DeadlockError = _bootstrap._DeadlockError
+
+
+if threading is not None:
+ class ModuleLockAsRLockTests(lock_tests.RLockTests):
+ locktype = staticmethod(lambda: LockType("some_lock"))
+
+ # _is_owned() unsupported
+ test__is_owned = None
+ # acquire(blocking=False) unsupported
+ test_try_acquire = None
+ test_try_acquire_contended = None
+ # `with` unsupported
+ test_with = None
+ # acquire(timeout=...) unsupported
+ test_timeout = None
+ # _release_save() unsupported
+ test_release_save_unacquired = None
+
+else:
+ class ModuleLockAsRLockTests(unittest.TestCase):
+ pass
+
+
+@unittest.skipUnless(threading, "threads needed for this test")
+class DeadlockAvoidanceTests(unittest.TestCase):
+
+ def run_deadlock_avoidance_test(self, create_deadlock):
+ NLOCKS = 10
+ locks = [LockType(str(i)) for i in range(NLOCKS)]
+ pairs = [(locks[i], locks[(i+1)%NLOCKS]) for i in range(NLOCKS)]
+ if create_deadlock:
+ NTHREADS = NLOCKS
+ else:
+ NTHREADS = NLOCKS - 1
+ barrier = threading.Barrier(NTHREADS)
+ results = []
+ def _acquire(lock):
+ """Try to acquire the lock. Return True on success, False on deadlock."""
+ try:
+ lock.acquire()
+ except DeadlockError:
+ return False
+ else:
+ return True
+ def f():
+ a, b = pairs.pop()
+ ra = _acquire(a)
+ barrier.wait()
+ rb = _acquire(b)
+ results.append((ra, rb))
+ if rb:
+ b.release()
+ if ra:
+ a.release()
+ lock_tests.Bunch(f, NTHREADS).wait_for_finished()
+ self.assertEqual(len(results), NTHREADS)
+ return results
+
+ def test_deadlock(self):
+ results = self.run_deadlock_avoidance_test(True)
+ # One of the threads detected a potential deadlock on its second
+ # acquire() call.
+ self.assertEqual(results.count((True, False)), 1)
+ self.assertEqual(results.count((True, True)), len(results) - 1)
+
+ def test_no_deadlock(self):
+ results = self.run_deadlock_avoidance_test(False)
+ self.assertEqual(results.count((True, False)), 0)
+ self.assertEqual(results.count((True, True)), len(results))
+
+
+class LifetimeTests(unittest.TestCase):
+
+ def test_lock_lifetime(self):
+ name = "xyzzy"
+ self.assertNotIn(name, _bootstrap._module_locks)
+ lock = _bootstrap._get_module_lock(name)
+ self.assertIn(name, _bootstrap._module_locks)
+ wr = weakref.ref(lock)
+ del lock
+ support.gc_collect()
+ self.assertNotIn(name, _bootstrap._module_locks)
+ self.assertIs(wr(), None)
+
+ def test_all_locks(self):
+ support.gc_collect()
+ self.assertEqual(0, len(_bootstrap._module_locks))
+
+
+@support.reap_threads
+def test_main():
+ support.run_unittest(ModuleLockAsRLockTests,
+ DeadlockAvoidanceTests,
+ LifetimeTests)
+
+
+if __name__ == '__main__':
+ test_main()
diff --git a/Lib/importlib/test/test_util.py b/Lib/importlib/test/test_util.py
index 602447f09e..e477f171f0 100644
--- a/Lib/importlib/test/test_util.py
+++ b/Lib/importlib/test/test_util.py
@@ -59,10 +59,57 @@ class ModuleForLoaderTests(unittest.TestCase):
self.raise_exception(name)
self.assertIs(module, sys.modules[name])
+ def test_decorator_attrs(self):
+ def fxn(self, module): pass
+ wrapped = util.module_for_loader(fxn)
+ self.assertEqual(wrapped.__name__, fxn.__name__)
+ self.assertEqual(wrapped.__qualname__, fxn.__qualname__)
+
+ def test_false_module(self):
+ # If for some odd reason a module is considered false, still return it
+ # from sys.modules.
+ class FalseModule(types.ModuleType):
+ def __bool__(self): return False
+
+ name = 'mod'
+ module = FalseModule(name)
+ with test_util.uncache(name):
+ self.assertFalse(module)
+ sys.modules[name] = module
+ given = self.return_module(name)
+ self.assertTrue(given is module)
+
+ def test_attributes_set(self):
+ # __name__, __loader__, and __package__ should be set (when
+ # is_package() is defined; undefined implicitly tested elsewhere).
+ class FakeLoader:
+ def __init__(self, is_package):
+ self._pkg = is_package
+ def is_package(self, name):
+ return self._pkg
+ @util.module_for_loader
+ def load_module(self, module):
+ return module
+
+ name = 'pkg.mod'
+ with test_util.uncache(name):
+ loader = FakeLoader(False)
+ module = loader.load_module(name)
+ self.assertEqual(module.__name__, name)
+ self.assertIs(module.__loader__, loader)
+ self.assertEqual(module.__package__, 'pkg')
-class SetPackageTests(unittest.TestCase):
+ name = 'pkg.sub'
+ with test_util.uncache(name):
+ loader = FakeLoader(True)
+ module = loader.load_module(name)
+ self.assertEqual(module.__name__, name)
+ self.assertIs(module.__loader__, loader)
+ self.assertEqual(module.__package__, name)
+class SetPackageTests(unittest.TestCase):
+
"""Tests for importlib.util.set_package."""
def verify(self, module, expect):
@@ -108,10 +155,53 @@ class SetPackageTests(unittest.TestCase):
module.__package__ = value
self.verify(module, value)
+ def test_decorator_attrs(self):
+ def fxn(module): pass
+ wrapped = util.set_package(fxn)
+ self.assertEqual(wrapped.__name__, fxn.__name__)
+ self.assertEqual(wrapped.__qualname__, fxn.__qualname__)
+
+
+class ResolveNameTests(unittest.TestCase):
+
+ """Tests importlib.util.resolve_name()."""
+
+ def test_absolute(self):
+ # bacon
+ self.assertEqual('bacon', util.resolve_name('bacon', None))
+
+ def test_aboslute_within_package(self):
+ # bacon in spam
+ self.assertEqual('bacon', util.resolve_name('bacon', 'spam'))
+
+ def test_no_package(self):
+ # .bacon in ''
+ with self.assertRaises(ValueError):
+ util.resolve_name('.bacon', '')
+
+ def test_in_package(self):
+ # .bacon in spam
+ self.assertEqual('spam.eggs.bacon',
+ util.resolve_name('.bacon', 'spam.eggs'))
+
+ def test_other_package(self):
+ # ..bacon in spam.bacon
+ self.assertEqual('spam.bacon',
+ util.resolve_name('..bacon', 'spam.eggs'))
+
+ def test_escape(self):
+ # ..bacon in spam
+ with self.assertRaises(ValueError):
+ util.resolve_name('..bacon', 'spam')
+
def test_main():
from test import support
- support.run_unittest(ModuleForLoaderTests, SetPackageTests)
+ support.run_unittest(
+ ModuleForLoaderTests,
+ SetPackageTests,
+ ResolveNameTests
+ )
if __name__ == '__main__':
diff --git a/Lib/importlib/test/util.py b/Lib/importlib/test/util.py
index 93b7cd2861..ef32f7d690 100644
--- a/Lib/importlib/test/util.py
+++ b/Lib/importlib/test/util.py
@@ -35,7 +35,7 @@ def uncache(*names):
for name in names:
if name in ('sys', 'marshal', 'imp'):
raise ValueError(
- "cannot uncache {0} as it will break _importlib".format(name))
+ "cannot uncache {0}".format(name))
try:
del sys.modules[name]
except KeyError:
@@ -124,7 +124,11 @@ class mock_modules:
else:
sys.modules[fullname] = self.modules[fullname]
if fullname in self.module_code:
- self.module_code[fullname]()
+ try:
+ self.module_code[fullname]()
+ except Exception:
+ del sys.modules[fullname]
+ raise
return self.modules[fullname]
def __enter__(self):