From 45a5e3afe52ed89f298242143c5f7e2bb992ac63 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Fri, 20 Jul 2012 14:48:53 -0400 Subject: Issue #15168: Move importlb.test to test.test_importlib. This should make the Linux distros happy as it is now easier to leave importlib's tests out of their base Python distribution. --- Lib/importlib/test/__init__.py | 25 - Lib/importlib/test/__main__.py | 30 - Lib/importlib/test/abc.py | 99 --- Lib/importlib/test/benchmark.py | 252 ------ Lib/importlib/test/builtin/__init__.py | 12 - Lib/importlib/test/builtin/test_finder.py | 55 -- Lib/importlib/test/builtin/test_loader.py | 105 --- Lib/importlib/test/builtin/util.py | 7 - Lib/importlib/test/extension/__init__.py | 13 - .../test/extension/test_case_sensitivity.py | 51 -- Lib/importlib/test/extension/test_finder.py | 50 -- Lib/importlib/test/extension/test_loader.py | 71 -- Lib/importlib/test/extension/test_path_hook.py | 32 - Lib/importlib/test/extension/util.py | 20 - Lib/importlib/test/frozen/__init__.py | 13 - Lib/importlib/test/frozen/test_finder.py | 47 -- Lib/importlib/test/frozen/test_loader.py | 121 --- Lib/importlib/test/import_/__init__.py | 13 - Lib/importlib/test/import_/test___package__.py | 119 --- Lib/importlib/test/import_/test_api.py | 29 - Lib/importlib/test/import_/test_caching.py | 88 -- Lib/importlib/test/import_/test_fromlist.py | 114 --- Lib/importlib/test/import_/test_meta_path.py | 115 --- Lib/importlib/test/import_/test_packages.py | 112 --- Lib/importlib/test/import_/test_path.py | 98 --- .../test/import_/test_relative_imports.py | 217 ----- Lib/importlib/test/import_/util.py | 28 - Lib/importlib/test/regrtest.py | 17 - Lib/importlib/test/source/__init__.py | 13 - Lib/importlib/test/source/test_abc_loader.py | 886 --------------------- Lib/importlib/test/source/test_case_sensitivity.py | 72 -- Lib/importlib/test/source/test_file_loader.py | 482 ----------- Lib/importlib/test/source/test_finder.py | 147 ---- Lib/importlib/test/source/test_path_hook.py | 32 - Lib/importlib/test/source/test_source_encoding.py | 123 --- Lib/importlib/test/source/util.py | 97 --- Lib/importlib/test/test_abc.py | 96 --- Lib/importlib/test/test_api.py | 183 ----- Lib/importlib/test/test_locks.py | 115 --- Lib/importlib/test/test_util.py | 208 ----- Lib/importlib/test/util.py | 140 ---- Lib/test/test_importlib.py | 5 - Lib/test/test_importlib/__init__.py | 33 + Lib/test/test_importlib/__main__.py | 20 + Lib/test/test_importlib/abc.py | 99 +++ Lib/test/test_importlib/benchmark.py | 252 ++++++ Lib/test/test_importlib/builtin/__init__.py | 12 + Lib/test/test_importlib/builtin/test_finder.py | 55 ++ Lib/test/test_importlib/builtin/test_loader.py | 105 +++ Lib/test/test_importlib/builtin/util.py | 7 + Lib/test/test_importlib/extension/__init__.py | 13 + .../extension/test_case_sensitivity.py | 51 ++ Lib/test/test_importlib/extension/test_finder.py | 50 ++ Lib/test/test_importlib/extension/test_loader.py | 71 ++ .../test_importlib/extension/test_path_hook.py | 32 + Lib/test/test_importlib/extension/util.py | 20 + Lib/test/test_importlib/frozen/__init__.py | 13 + Lib/test/test_importlib/frozen/test_finder.py | 47 ++ Lib/test/test_importlib/frozen/test_loader.py | 121 +++ Lib/test/test_importlib/import_/__init__.py | 13 + .../test_importlib/import_/test___package__.py | 119 +++ Lib/test/test_importlib/import_/test_api.py | 29 + Lib/test/test_importlib/import_/test_caching.py | 88 ++ Lib/test/test_importlib/import_/test_fromlist.py | 114 +++ Lib/test/test_importlib/import_/test_meta_path.py | 115 +++ Lib/test/test_importlib/import_/test_packages.py | 112 +++ Lib/test/test_importlib/import_/test_path.py | 98 +++ .../import_/test_relative_imports.py | 217 +++++ Lib/test/test_importlib/import_/util.py | 28 + Lib/test/test_importlib/regrtest.py | 17 + Lib/test/test_importlib/source/__init__.py | 13 + Lib/test/test_importlib/source/test_abc_loader.py | 886 +++++++++++++++++++++ .../test_importlib/source/test_case_sensitivity.py | 72 ++ Lib/test/test_importlib/source/test_file_loader.py | 482 +++++++++++ Lib/test/test_importlib/source/test_finder.py | 147 ++++ Lib/test/test_importlib/source/test_path_hook.py | 32 + .../test_importlib/source/test_source_encoding.py | 123 +++ Lib/test/test_importlib/source/util.py | 97 +++ Lib/test/test_importlib/test_abc.py | 96 +++ Lib/test/test_importlib/test_api.py | 183 +++++ Lib/test/test_importlib/test_locks.py | 115 +++ Lib/test/test_importlib/test_util.py | 208 +++++ Lib/test/test_importlib/util.py | 140 ++++ Misc/NEWS | 2 + 84 files changed, 4547 insertions(+), 4552 deletions(-) delete mode 100644 Lib/importlib/test/__init__.py delete mode 100644 Lib/importlib/test/__main__.py delete mode 100644 Lib/importlib/test/abc.py delete mode 100644 Lib/importlib/test/benchmark.py delete mode 100644 Lib/importlib/test/builtin/__init__.py delete mode 100644 Lib/importlib/test/builtin/test_finder.py delete mode 100644 Lib/importlib/test/builtin/test_loader.py delete mode 100644 Lib/importlib/test/builtin/util.py delete mode 100644 Lib/importlib/test/extension/__init__.py delete mode 100644 Lib/importlib/test/extension/test_case_sensitivity.py delete mode 100644 Lib/importlib/test/extension/test_finder.py delete mode 100644 Lib/importlib/test/extension/test_loader.py delete mode 100644 Lib/importlib/test/extension/test_path_hook.py delete mode 100644 Lib/importlib/test/extension/util.py delete mode 100644 Lib/importlib/test/frozen/__init__.py delete mode 100644 Lib/importlib/test/frozen/test_finder.py delete mode 100644 Lib/importlib/test/frozen/test_loader.py delete mode 100644 Lib/importlib/test/import_/__init__.py delete mode 100644 Lib/importlib/test/import_/test___package__.py delete mode 100644 Lib/importlib/test/import_/test_api.py delete mode 100644 Lib/importlib/test/import_/test_caching.py delete mode 100644 Lib/importlib/test/import_/test_fromlist.py delete mode 100644 Lib/importlib/test/import_/test_meta_path.py delete mode 100644 Lib/importlib/test/import_/test_packages.py delete mode 100644 Lib/importlib/test/import_/test_path.py delete mode 100644 Lib/importlib/test/import_/test_relative_imports.py delete mode 100644 Lib/importlib/test/import_/util.py delete mode 100644 Lib/importlib/test/regrtest.py delete mode 100644 Lib/importlib/test/source/__init__.py delete mode 100644 Lib/importlib/test/source/test_abc_loader.py delete mode 100644 Lib/importlib/test/source/test_case_sensitivity.py delete mode 100644 Lib/importlib/test/source/test_file_loader.py delete mode 100644 Lib/importlib/test/source/test_finder.py delete mode 100644 Lib/importlib/test/source/test_path_hook.py delete mode 100644 Lib/importlib/test/source/test_source_encoding.py delete mode 100644 Lib/importlib/test/source/util.py delete mode 100644 Lib/importlib/test/test_abc.py delete mode 100644 Lib/importlib/test/test_api.py delete mode 100644 Lib/importlib/test/test_locks.py delete mode 100644 Lib/importlib/test/test_util.py delete mode 100644 Lib/importlib/test/util.py delete mode 100644 Lib/test/test_importlib.py create mode 100644 Lib/test/test_importlib/__init__.py create mode 100644 Lib/test/test_importlib/__main__.py create mode 100644 Lib/test/test_importlib/abc.py create mode 100644 Lib/test/test_importlib/benchmark.py create mode 100644 Lib/test/test_importlib/builtin/__init__.py create mode 100644 Lib/test/test_importlib/builtin/test_finder.py create mode 100644 Lib/test/test_importlib/builtin/test_loader.py create mode 100644 Lib/test/test_importlib/builtin/util.py create mode 100644 Lib/test/test_importlib/extension/__init__.py create mode 100644 Lib/test/test_importlib/extension/test_case_sensitivity.py create mode 100644 Lib/test/test_importlib/extension/test_finder.py create mode 100644 Lib/test/test_importlib/extension/test_loader.py create mode 100644 Lib/test/test_importlib/extension/test_path_hook.py create mode 100644 Lib/test/test_importlib/extension/util.py create mode 100644 Lib/test/test_importlib/frozen/__init__.py create mode 100644 Lib/test/test_importlib/frozen/test_finder.py create mode 100644 Lib/test/test_importlib/frozen/test_loader.py create mode 100644 Lib/test/test_importlib/import_/__init__.py create mode 100644 Lib/test/test_importlib/import_/test___package__.py create mode 100644 Lib/test/test_importlib/import_/test_api.py create mode 100644 Lib/test/test_importlib/import_/test_caching.py create mode 100644 Lib/test/test_importlib/import_/test_fromlist.py create mode 100644 Lib/test/test_importlib/import_/test_meta_path.py create mode 100644 Lib/test/test_importlib/import_/test_packages.py create mode 100644 Lib/test/test_importlib/import_/test_path.py create mode 100644 Lib/test/test_importlib/import_/test_relative_imports.py create mode 100644 Lib/test/test_importlib/import_/util.py create mode 100644 Lib/test/test_importlib/regrtest.py create mode 100644 Lib/test/test_importlib/source/__init__.py create mode 100644 Lib/test/test_importlib/source/test_abc_loader.py create mode 100644 Lib/test/test_importlib/source/test_case_sensitivity.py create mode 100644 Lib/test/test_importlib/source/test_file_loader.py create mode 100644 Lib/test/test_importlib/source/test_finder.py create mode 100644 Lib/test/test_importlib/source/test_path_hook.py create mode 100644 Lib/test/test_importlib/source/test_source_encoding.py create mode 100644 Lib/test/test_importlib/source/util.py create mode 100644 Lib/test/test_importlib/test_abc.py create mode 100644 Lib/test/test_importlib/test_api.py create mode 100644 Lib/test/test_importlib/test_locks.py create mode 100644 Lib/test/test_importlib/test_util.py create mode 100644 Lib/test/test_importlib/util.py diff --git a/Lib/importlib/test/__init__.py b/Lib/importlib/test/__init__.py deleted file mode 100644 index 815a706..0000000 --- a/Lib/importlib/test/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -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 deleted file mode 100644 index 92171b2..0000000 --- a/Lib/importlib/test/__main__.py +++ /dev/null @@ -1,30 +0,0 @@ -"""Run importlib's test suite. - -Specifying the ``--builtin`` flag will run tests, where applicable, with -builtins.__import__ instead of importlib.__import__. - -""" -from importlib.test.import_ import util -import os.path -from test.support import run_unittest -import unittest - - -def test_main(): - start_dir = os.path.dirname(__file__) - top_dir = os.path.dirname(os.path.dirname(start_dir)) - test_loader = unittest.TestLoader() - 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/abc.py b/Lib/importlib/test/abc.py deleted file mode 100644 index 2c17ac3..0000000 --- a/Lib/importlib/test/abc.py +++ /dev/null @@ -1,99 +0,0 @@ -import abc -import unittest - - -class FinderTests(unittest.TestCase, metaclass=abc.ABCMeta): - - """Basic tests for a finder to pass.""" - - @abc.abstractmethod - def test_module(self): - # Test importing a top-level module. - pass - - @abc.abstractmethod - def test_package(self): - # Test importing a package. - pass - - @abc.abstractmethod - def test_module_in_package(self): - # Test importing a module contained within a package. - # A value for 'path' should be used if for a meta_path finder. - pass - - @abc.abstractmethod - def test_package_in_package(self): - # Test importing a subpackage. - # A value for 'path' should be used if for a meta_path finder. - pass - - @abc.abstractmethod - def test_package_over_module(self): - # Test that packages are chosen over modules. - pass - - @abc.abstractmethod - def test_failure(self): - # Test trying to find a module that cannot be handled. - pass - - -class LoaderTests(unittest.TestCase, metaclass=abc.ABCMeta): - - @abc.abstractmethod - def test_module(self): - """A module should load without issue. - - After the loader returns the module should be in sys.modules. - - Attributes to verify: - - * __file__ - * __loader__ - * __name__ - * No __path__ - - """ - pass - - @abc.abstractmethod - def test_package(self): - """Loading a package should work. - - After the loader returns the module should be in sys.modules. - - Attributes to verify: - - * __name__ - * __file__ - * __package__ - * __path__ - * __loader__ - - """ - pass - - @abc.abstractmethod - def test_lacking_parent(self): - """A loader should not be dependent on it's parent package being - imported.""" - pass - - @abc.abstractmethod - def test_module_reuse(self): - """If a module is already in sys.modules, it should be reused.""" - pass - - @abc.abstractmethod - def test_state_after_failure(self): - """If a module is already in sys.modules and a reload fails - (e.g. a SyntaxError), the module should be in the state it was before - the reload began.""" - pass - - @abc.abstractmethod - def test_unloadable(self): - """Test ImportError is raised when the loader is asked to load a module - it can't.""" - pass diff --git a/Lib/importlib/test/benchmark.py b/Lib/importlib/test/benchmark.py deleted file mode 100644 index 183e818..0000000 --- a/Lib/importlib/test/benchmark.py +++ /dev/null @@ -1,252 +0,0 @@ -"""Benchmark some basic import use-cases. - -The assumption is made that this benchmark is run in a fresh interpreter and -thus has no external changes made to import-related attributes in sys. - -""" -from . import util -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 - - -def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): - """Bench the given statement as many times as necessary until total - executions take one second.""" - stmt = "__import__({!r})".format(name) - timer = timeit.Timer(stmt) - for x in range(repeat): - total_time = 0 - count = 0 - while total_time < seconds: - try: - total_time += timer.timeit(1) - finally: - cleanup() - count += 1 - else: - # One execution too far - if total_time > seconds: - count -= 1 - yield count // seconds - -def from_cache(seconds, repeat): - """sys.modules""" - name = '' - module = imp.new_module(name) - module.__file__ = '' - module.__package__ = '' - with util.uncache(name): - sys.modules[name] = module - for result in bench(name, repeat=repeat, seconds=seconds): - yield result - - -def builtin_mod(seconds, repeat): - """Built-in module""" - name = 'errno' - if name in sys.modules: - del sys.modules[name] - # Relying on built-in importer being implicit. - for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, - seconds=seconds): - yield result - - -def source_wo_bytecode(seconds, repeat): - """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 - 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: 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])) - for result in bench(name, cleanup, repeat=repeat, seconds=seconds): - assert not os.path.exists(imp.cache_from_source(mapping[name])) - 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): - """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, - 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 - -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_writing_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' - '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() - results = [] - for result in benchmark(seconds=seconds, repeat=repeat): - results.append(result) - print(result, end=' ') - 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 argparse - - parser = argparse.ArgumentParser() - parser.add_argument('-b', '--builtin', dest='builtin', action='store_true', - default=False, help="use the built-in __import__") - 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_, options) diff --git a/Lib/importlib/test/builtin/__init__.py b/Lib/importlib/test/builtin/__init__.py deleted file mode 100644 index 31a3b5f..0000000 --- a/Lib/importlib/test/builtin/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -import importlib.test -import os - - -def test_suite(): - directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.builtin', directory) - - -if __name__ == '__main__': - from test.support import run_unittest - run_unittest(test_suite()) diff --git a/Lib/importlib/test/builtin/test_finder.py b/Lib/importlib/test/builtin/test_finder.py deleted file mode 100644 index 146538d..0000000 --- a/Lib/importlib/test/builtin/test_finder.py +++ /dev/null @@ -1,55 +0,0 @@ -from importlib import machinery -from .. import abc -from .. import util -from . import util as builtin_util - -import sys -import unittest - -class FinderTests(abc.FinderTests): - - """Test find_module() for built-in modules.""" - - def test_module(self): - # Common case. - with util.uncache(builtin_util.NAME): - found = machinery.BuiltinImporter.find_module(builtin_util.NAME) - self.assertTrue(found) - - def test_package(self): - # Built-in modules cannot be a package. - pass - - def test_module_in_package(self): - # Built-in modules cannobt be in a package. - pass - - def test_package_in_package(self): - # Built-in modules cannot be a package. - pass - - def test_package_over_module(self): - # Built-in modules cannot be a package. - pass - - def test_failure(self): - assert 'importlib' not in sys.builtin_module_names - loader = machinery.BuiltinImporter.find_module('importlib') - self.assertIsNone(loader) - - def test_ignore_path(self): - # The value for 'path' should always trigger a failed import. - with util.uncache(builtin_util.NAME): - loader = machinery.BuiltinImporter.find_module(builtin_util.NAME, - ['pkg']) - self.assertIsNone(loader) - - - -def test_main(): - from test.support import run_unittest - run_unittest(FinderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/builtin/test_loader.py b/Lib/importlib/test/builtin/test_loader.py deleted file mode 100644 index 8e186e7..0000000 --- a/Lib/importlib/test/builtin/test_loader.py +++ /dev/null @@ -1,105 +0,0 @@ -import importlib -from importlib import machinery -from .. import abc -from .. import util -from . import util as builtin_util - -import sys -import types -import unittest - - -class LoaderTests(abc.LoaderTests): - - """Test load_module() for built-in modules.""" - - verification = {'__name__': 'errno', '__package__': '', - '__loader__': machinery.BuiltinImporter} - - def verify(self, module): - """Verify that the module matches against what it should have.""" - self.assertIsInstance(module, types.ModuleType) - for attr, value in self.verification.items(): - self.assertEqual(getattr(module, attr), value) - self.assertIn(module.__name__, sys.modules) - - load_module = staticmethod(lambda name: - machinery.BuiltinImporter.load_module(name)) - - def test_module(self): - # Common case. - with util.uncache(builtin_util.NAME): - module = self.load_module(builtin_util.NAME) - self.verify(module) - - def test_package(self): - # Built-in modules cannot be a package. - pass - - def test_lacking_parent(self): - # Built-in modules cannot be a package. - pass - - def test_state_after_failure(self): - # Not way to force an imoprt failure. - pass - - def test_module_reuse(self): - # Test that the same module is used in a reload. - with util.uncache(builtin_util.NAME): - module1 = self.load_module(builtin_util.NAME) - module2 = self.load_module(builtin_util.NAME) - self.assertIs(module1, module2) - - def test_unloadable(self): - name = 'dssdsdfff' - assert name not in sys.builtin_module_names - 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) as cm: - self.load_module('importlib') - self.assertEqual(cm.exception.name, 'importlib') - - -class InspectLoaderTests(unittest.TestCase): - - """Tests for InspectLoader methods for BuiltinImporter.""" - - def test_get_code(self): - # There is no code object. - result = machinery.BuiltinImporter.get_code(builtin_util.NAME) - self.assertIsNone(result) - - def test_get_source(self): - # There is no source. - result = machinery.BuiltinImporter.get_source(builtin_util.NAME) - self.assertIsNone(result) - - def test_is_package(self): - # Cannot be a package. - result = machinery.BuiltinImporter.is_package(builtin_util.NAME) - self.assertTrue(not result) - - def test_not_builtin(self): - # 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) as cm: - method(builtin_util.BAD_NAME) - self.assertRaises(builtin_util.BAD_NAME) - - - -def test_main(): - from test.support import run_unittest - run_unittest(LoaderTests, InspectLoaderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/builtin/util.py b/Lib/importlib/test/builtin/util.py deleted file mode 100644 index 5704699..0000000 --- a/Lib/importlib/test/builtin/util.py +++ /dev/null @@ -1,7 +0,0 @@ -import sys - -assert 'errno' in sys.builtin_module_names -NAME = 'errno' - -assert 'importlib' not in sys.builtin_module_names -BAD_NAME = 'importlib' diff --git a/Lib/importlib/test/extension/__init__.py b/Lib/importlib/test/extension/__init__.py deleted file mode 100644 index 2ec5840..0000000 --- a/Lib/importlib/test/extension/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import importlib.test -import os.path -import unittest - - -def test_suite(): - directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.extension', directory) - - -if __name__ == '__main__': - from test.support import run_unittest - run_unittest(test_suite()) diff --git a/Lib/importlib/test/extension/test_case_sensitivity.py b/Lib/importlib/test/extension/test_case_sensitivity.py deleted file mode 100644 index bdc21e7..0000000 --- a/Lib/importlib/test/extension/test_case_sensitivity.py +++ /dev/null @@ -1,51 +0,0 @@ -import imp -import sys -from test import support -import unittest -from importlib import _bootstrap -from .. import util -from . import util as ext_util - - -@util.case_insensitive_tests -class ExtensionModuleCaseSensitivityTest(unittest.TestCase): - - def find_module(self): - good_name = ext_util.NAME - bad_name = good_name.upper() - assert good_name != bad_name - 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')) - - - - -def test_main(): - if ext_util.FILENAME is None: - return - support.run_unittest(ExtensionModuleCaseSensitivityTest) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/extension/test_finder.py b/Lib/importlib/test/extension/test_finder.py deleted file mode 100644 index 1c60292..0000000 --- a/Lib/importlib/test/extension/test_finder.py +++ /dev/null @@ -1,50 +0,0 @@ -from importlib import _bootstrap -from .. import abc -from . import util - -import imp -import unittest - -class FinderTests(abc.FinderTests): - - """Test the finder for extension modules.""" - - def find_module(self, fullname): - importer = _bootstrap.FileFinder(util.PATH, - (_bootstrap.ExtensionFileLoader, - imp.extension_suffixes(), - False)) - return importer.find_module(fullname) - - def test_module(self): - self.assertTrue(self.find_module(util.NAME)) - - def test_package(self): - # Extension modules cannot be an __init__ for a package. - pass - - def test_module_in_package(self): - # No extension module in a package available for testing. - pass - - def test_package_in_package(self): - # Extension modules cannot be an __init__ for a package. - pass - - def test_package_over_module(self): - # Extension modules cannot be an __init__ for a package. - pass - - def test_failure(self): - self.assertIsNone(self.find_module('asdfjkl;')) - - # XXX Raise an exception if someone tries to use the 'path' argument? - - -def test_main(): - from test.support import run_unittest - run_unittest(FinderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/extension/test_loader.py b/Lib/importlib/test/extension/test_loader.py deleted file mode 100644 index 917843f..0000000 --- a/Lib/importlib/test/extension/test_loader.py +++ /dev/null @@ -1,71 +0,0 @@ -from importlib import machinery -from . import util as ext_util -from .. import abc -from .. import util - -import sys -import unittest - - -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): - 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): - module = self.load_module(ext_util.NAME) - for attr, value in [('__name__', ext_util.NAME), - ('__file__', ext_util.FILEPATH), - ('__package__', '')]: - self.assertEqual(getattr(module, attr), value) - self.assertIn(ext_util.NAME, sys.modules) - self.assertIsInstance(module.__loader__, - machinery.ExtensionFileLoader) - - def test_package(self): - # Extensions are not found in packages. - pass - - def test_lacking_parent(self): - # Extensions are not found in packages. - pass - - def test_module_reuse(self): - with util.uncache(ext_util.NAME): - module1 = self.load_module(ext_util.NAME) - module2 = self.load_module(ext_util.NAME) - self.assertIs(module1, module2) - - def test_state_after_failure(self): - # No easy way to trigger a failure after a successful import. - pass - - def test_unloadable(self): - name = 'asdfjkl;' - with self.assertRaises(ImportError) as cm: - self.load_module(name) - self.assertEqual(cm.exception.name, name) - - -def test_main(): - from test.support import run_unittest - run_unittest(LoaderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/extension/test_path_hook.py b/Lib/importlib/test/extension/test_path_hook.py deleted file mode 100644 index 129e6e2..0000000 --- a/Lib/importlib/test/extension/test_path_hook.py +++ /dev/null @@ -1,32 +0,0 @@ -from importlib import _bootstrap -from . import util - -import collections -import imp -import sys -import unittest - - -class PathHookTests(unittest.TestCase): - - """Test the path hook for extension modules.""" - # XXX Should it only succeed for pre-existing directories? - # XXX Should it only work for directories containing an extension module? - - def hook(self, 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 - # exists. - self.assertTrue(hasattr(self.hook(util.PATH), 'find_module')) - - -def test_main(): - from test.support import run_unittest - run_unittest(PathHookTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/extension/util.py b/Lib/importlib/test/extension/util.py deleted file mode 100644 index a266dd9..0000000 --- a/Lib/importlib/test/extension/util.py +++ /dev/null @@ -1,20 +0,0 @@ -import imp -from importlib import machinery -import os -import sys - -PATH = None -EXT = None -FILENAME = None -NAME = '_testcapi' -try: - for PATH in sys.path: - for EXT in machinery.EXTENSION_SUFFIXES: - FILENAME = NAME + EXT - FILEPATH = os.path.join(PATH, FILENAME) - if os.path.exists(os.path.join(PATH, FILENAME)): - raise StopIteration - else: - PATH = EXT = FILENAME = FILEPATH = None -except StopIteration: - pass diff --git a/Lib/importlib/test/frozen/__init__.py b/Lib/importlib/test/frozen/__init__.py deleted file mode 100644 index 2945eeb..0000000 --- a/Lib/importlib/test/frozen/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import importlib.test -import os.path -import unittest - - -def test_suite(): - directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.frozen', directory) - - -if __name__ == '__main__': - from test.support import run_unittest - run_unittest(test_suite()) diff --git a/Lib/importlib/test/frozen/test_finder.py b/Lib/importlib/test/frozen/test_finder.py deleted file mode 100644 index 54c0c90..0000000 --- a/Lib/importlib/test/frozen/test_finder.py +++ /dev/null @@ -1,47 +0,0 @@ -from ... import machinery -from .. import abc - -import unittest - - -class FinderTests(abc.FinderTests): - - """Test finding frozen modules.""" - - def find(self, name, path=None): - finder = machinery.FrozenImporter - return finder.find_module(name, path) - - def test_module(self): - name = '__hello__' - loader = self.find(name) - self.assertTrue(hasattr(loader, 'load_module')) - - def test_package(self): - loader = self.find('__phello__') - self.assertTrue(hasattr(loader, 'load_module')) - - def test_module_in_package(self): - loader = self.find('__phello__.spam', ['__phello__']) - self.assertTrue(hasattr(loader, 'load_module')) - - def test_package_in_package(self): - # No frozen package within another package to test with. - pass - - def test_package_over_module(self): - # No easy way to test. - pass - - def test_failure(self): - loader = self.find('') - self.assertIsNone(loader) - - -def test_main(): - from test.support import run_unittest - run_unittest(FinderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/frozen/test_loader.py b/Lib/importlib/test/frozen/test_loader.py deleted file mode 100644 index 4b8ec15..0000000 --- a/Lib/importlib/test/frozen/test_loader.py +++ /dev/null @@ -1,121 +0,0 @@ -from importlib import machinery -import imp -import unittest -from .. import abc -from .. import util -from test.support import captured_stdout - -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__', - '__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__', - '__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', - '__package__': '__phello__', - '__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: - module1 = machinery.FrozenImporter.load_module('__hello__') - module2 = machinery.FrozenImporter.load_module('__hello__') - self.assertIs(module1, module2) - 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), - "") - - 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) as cm: - machinery.FrozenImporter.load_module('_not_real') - self.assertEqual(cm.exception.name, '_not_real') - - -class InspectLoaderTests(unittest.TestCase): - - """Tests for the InspectLoader methods for FrozenImporter.""" - - def test_get_code(self): - # Make sure that the code object is good. - name = '__hello__' - with captured_stdout() as stdout: - code = machinery.FrozenImporter.get_code(name) - mod = imp.new_module(name) - exec(code, mod.__dict__) - self.assertTrue(hasattr(mod, 'initialized')) - self.assertEqual(stdout.getvalue(), 'Hello world!\n') - - def test_get_source(self): - # Should always return None. - result = machinery.FrozenImporter.get_source('__hello__') - self.assertIsNone(result) - - def test_is_package(self): - # Should be able to tell what is a package. - test_for = (('__hello__', False), ('__phello__', True), - ('__phello__.spam', False)) - for name, is_package in test_for: - result = machinery.FrozenImporter.is_package(name) - self.assertEqual(bool(result), is_package) - - def test_failure(self): - # 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) as cm: - method('importlib') - self.assertEqual(cm.exception.name, 'importlib') - - -def test_main(): - from test.support import run_unittest - run_unittest(LoaderTests, InspectLoaderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/__init__.py b/Lib/importlib/test/import_/__init__.py deleted file mode 100644 index fdf7661..0000000 --- a/Lib/importlib/test/import_/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import importlib.test -import os.path -import unittest - - -def test_suite(): - directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.import_', directory) - - -if __name__ == '__main__': - from test.support import run_unittest - run_unittest(test_suite()) diff --git a/Lib/importlib/test/import_/test___package__.py b/Lib/importlib/test/import_/test___package__.py deleted file mode 100644 index 783cde1..0000000 --- a/Lib/importlib/test/import_/test___package__.py +++ /dev/null @@ -1,119 +0,0 @@ -"""PEP 366 ("Main module explicit relative imports") specifies the -semantics for the __package__ attribute on modules. This attribute is -used, when available, to detect which package a module belongs to (instead -of using the typical __path__/__name__ test). - -""" -import unittest -from .. import util -from . import util as import_util - - -class Using__package__(unittest.TestCase): - - """Use of __package__ supercedes the use of __name__/__path__ to calculate - what package a module belongs to. The basic algorithm is [__package__]:: - - def resolve_name(name, package, level): - level -= 1 - base = package.rsplit('.', level)[0] - return '{0}.{1}'.format(base, name) - - But since there is no guarantee that __package__ has been set (or not been - set to None [None]), there has to be a way to calculate the attribute's value - [__name__]:: - - def calc_package(caller_name, has___path__): - if has__path__: - return caller_name - else: - return caller_name.rsplit('.', 1)[0] - - Then the normal algorithm for relative name imports can proceed as if - __package__ had been set. - - """ - - def test_using___package__(self): - # [__package__] - with util.mock_modules('pkg.__init__', 'pkg.fake') as importer: - with util.import_state(meta_path=[importer]): - import_util.import_('pkg.fake') - module = import_util.import_('', - globals={'__package__': 'pkg.fake'}, - fromlist=['attr'], level=2) - self.assertEqual(module.__name__, 'pkg') - - def test_using___name__(self, package_as_None=False): - # [__name__] - globals_ = {'__name__': 'pkg.fake', '__path__': []} - if package_as_None: - globals_['__package__'] = None - with util.mock_modules('pkg.__init__', 'pkg.fake') as importer: - with util.import_state(meta_path=[importer]): - import_util.import_('pkg.fake') - module = import_util.import_('', globals= globals_, - fromlist=['attr'], level=2) - self.assertEqual(module.__name__, 'pkg') - - def test_None_as___package__(self): - # [None] - self.test_using___name__(package_as_None=True) - - def test_bad__package__(self): - globals = {'__package__': ''} - with self.assertRaises(SystemError): - import_util.import_('', globals, {}, ['relimport'], 1) - - def test_bunk__package__(self): - globals = {'__package__': 42} - with self.assertRaises(TypeError): - import_util.import_('', globals, {}, ['relimport'], 1) - - -@import_util.importlib_only -class Setting__package__(unittest.TestCase): - - """Because __package__ is a new feature, it is not always set by a loader. - Import will set it as needed to help with the transition to relying on - __package__. - - For a top-level module, __package__ is set to None [top-level]. For a - package __name__ is used for __package__ [package]. For submodules the - value is __name__.rsplit('.', 1)[0] [submodule]. - - """ - - # [top-level] - def test_top_level(self): - with util.mock_modules('top_level') as mock: - with util.import_state(meta_path=[mock]): - del mock['top_level'].__package__ - module = import_util.import_('top_level') - self.assertEqual(module.__package__, '') - - # [package] - def test_package(self): - with util.mock_modules('pkg.__init__') as mock: - with util.import_state(meta_path=[mock]): - del mock['pkg'].__package__ - module = import_util.import_('pkg') - self.assertEqual(module.__package__, 'pkg') - - # [submodule] - def test_submodule(self): - with util.mock_modules('pkg.__init__', 'pkg.mod') as mock: - with util.import_state(meta_path=[mock]): - del mock['pkg.mod'].__package__ - pkg = import_util.import_('pkg.mod') - module = getattr(pkg, 'mod') - self.assertEqual(module.__package__, 'pkg') - - -def test_main(): - from test.support import run_unittest - run_unittest(Using__package__, Setting__package__) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/test_api.py b/Lib/importlib/test/import_/test_api.py deleted file mode 100644 index 2fa1f90..0000000 --- a/Lib/importlib/test/import_/test_api.py +++ /dev/null @@ -1,29 +0,0 @@ -from . import util -import unittest - - -class APITest(unittest.TestCase): - - """Test API-specific details for __import__ (e.g. raising the right - exception when passing in an int for the module name).""" - - def test_name_requires_rparition(self): - # Raise TypeError if a non-string is passed in for the module name. - 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 - run_unittest(APITest) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/test_caching.py b/Lib/importlib/test/import_/test_caching.py deleted file mode 100644 index bf68027..0000000 --- a/Lib/importlib/test/import_/test_caching.py +++ /dev/null @@ -1,88 +0,0 @@ -"""Test that sys.modules is used properly by import.""" -from .. import util -from . import util as import_util -import sys -from types import MethodType -import unittest - - -class UseCache(unittest.TestCase): - - """When it comes to sys.modules, import prefers it over anything else. - - Once a name has been resolved, sys.modules is checked to see if it contains - the module desired. If so, then it is returned [use cache]. If it is not - found, then the proper steps are taken to perform the import, but - sys.modules is still used to return the imported module (e.g., not what a - loader returns) [from cache on return]. This also applies to imports of - things contained within a package and thus get assigned as an attribute - [from cache to attribute] or pulled in thanks to a fromlist import - [from cache for fromlist]. But if sys.modules contains None then - ImportError is raised [None in cache]. - - """ - def test_using_cache(self): - # [use cache] - module_to_use = "some module found!" - with util.uncache(module_to_use): - sys.modules['some_module'] = module_to_use - module = import_util.import_('some_module') - self.assertEqual(id(module_to_use), id(module)) - - def test_None_in_cache(self): - #[None in cache] - name = 'using_None' - with util.uncache(name): - sys.modules[name] = None - 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) - original_load = mock.load_module - def load_module(self, fullname): - original_load(fullname) - return return_ - mock.load_module = MethodType(load_module, mock) - return mock - - # __import__ inconsistent between loaders and built-in import when it comes - # to when to use the module in sys.modules and when not to. - @import_util.importlib_only - def test_using_cache_after_loader(self): - # [from cache on return] - with self.create_mock('module') as mock: - with util.import_state(meta_path=[mock]): - module = import_util.import_('module') - self.assertEqual(id(module), id(sys.modules['module'])) - - # See test_using_cache_after_loader() for reasoning. - @import_util.importlib_only - def test_using_cache_for_assigning_to_attribute(self): - # [from cache to attribute] - with self.create_mock('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('pkg.module') - self.assertTrue(hasattr(module, 'module')) - self.assertEqual(id(module.module), - id(sys.modules['pkg.module'])) - - # See test_using_cache_after_loader() for reasoning. - @import_util.importlib_only - def test_using_cache_for_fromlist(self): - # [from cache for fromlist] - with self.create_mock('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('pkg', fromlist=['module']) - self.assertTrue(hasattr(module, 'module')) - self.assertEqual(id(module.module), - id(sys.modules['pkg.module'])) - - -def test_main(): - from test.support import run_unittest - run_unittest(UseCache) - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/test_fromlist.py b/Lib/importlib/test/import_/test_fromlist.py deleted file mode 100644 index 281961d..0000000 --- a/Lib/importlib/test/import_/test_fromlist.py +++ /dev/null @@ -1,114 +0,0 @@ -"""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): - - """The use of fromlist influences what import returns. - - If direct ``import ...`` statement is used, the root module or package is - returned [import return]. But if fromlist is set, then the specified module - is actually returned (whether it is a relative import or not) - [from return]. - - """ - - def test_return_from_import(self): - # [import return] - with util.mock_modules('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('pkg.module') - self.assertEqual(module.__name__, 'pkg') - - def test_return_from_from_import(self): - # [from return] - with util.mock_modules('pkg.__init__', 'pkg.module')as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('pkg.module', fromlist=['attr']) - self.assertEqual(module.__name__, 'pkg.module') - - -class HandlingFromlist(unittest.TestCase): - - """Using fromlist triggers different actions based on what is being asked - of it. - - If fromlist specifies an object on a module, nothing special happens - [object case]. This is even true if the object does not exist [bad object]. - - If a package is being imported, then what is listed in fromlist may be - treated as a module to be imported [module]. And this extends to what is - contained in __all__ when '*' is imported [using *]. And '*' does not need - to be the only name in the fromlist [using * with others]. - - """ - - def test_object(self): - # [object case] - with util.mock_modules('module') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('module', fromlist=['attr']) - self.assertEqual(module.__name__, 'module') - - def test_unexistent_object(self): - # [bad object] - with util.mock_modules('module') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('module', fromlist=['non_existent']) - self.assertEqual(module.__name__, 'module') - self.assertTrue(not hasattr(module, 'non_existent')) - - def test_module_from_package(self): - # [module] - with util.mock_modules('pkg.__init__', 'pkg.module') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('pkg', fromlist=['module']) - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(hasattr(module, 'module')) - self.assertEqual(module.module.__name__, 'pkg.module') - - def test_empty_string(self): - with util.mock_modules('pkg.__init__', 'pkg.mod') as importer: - with util.import_state(meta_path=[importer]): - module = import_util.import_('pkg.mod', fromlist=['']) - self.assertEqual(module.__name__, 'pkg.mod') - - def basic_star_test(self, fromlist=['*']): - # [using *] - with util.mock_modules('pkg.__init__', 'pkg.module') as mock: - with util.import_state(meta_path=[mock]): - mock['pkg'].__all__ = ['module'] - module = import_util.import_('pkg', fromlist=fromlist) - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(hasattr(module, 'module')) - self.assertEqual(module.module.__name__, 'pkg.module') - - def test_using_star(self): - # [using *] - self.basic_star_test() - - def test_fromlist_as_tuple(self): - self.basic_star_test(('*',)) - - def test_star_with_others(self): - # [using * with others] - context = util.mock_modules('pkg.__init__', 'pkg.module1', 'pkg.module2') - with context as mock: - with util.import_state(meta_path=[mock]): - mock['pkg'].__all__ = ['module1'] - module = import_util.import_('pkg', fromlist=['module2', '*']) - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(hasattr(module, 'module1')) - self.assertTrue(hasattr(module, 'module2')) - self.assertEqual(module.module1.__name__, 'pkg.module1') - self.assertEqual(module.module2.__name__, 'pkg.module2') - - -def test_main(): - from test.support import run_unittest - run_unittest(ReturnValue, HandlingFromlist) - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/test_meta_path.py b/Lib/importlib/test/import_/test_meta_path.py deleted file mode 100644 index 4d85f80..0000000 --- a/Lib/importlib/test/import_/test_meta_path.py +++ /dev/null @@ -1,115 +0,0 @@ -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): - - """Calls to the importers on sys.meta_path happen in order that they are - specified in the sequence, starting with the first importer - [first called], and then continuing on down until one is found that doesn't - return None [continuing].""" - - - def test_first_called(self): - # [first called] - mod = 'top_level' - first = util.mock_modules(mod) - second = util.mock_modules(mod) - with util.mock_modules(mod) as first, util.mock_modules(mod) as second: - first.modules[mod] = 42 - second.modules[mod] = -13 - with util.import_state(meta_path=[first, second]): - self.assertEqual(import_util.import_(mod), 42) - - def test_continuing(self): - # [continuing] - mod_name = 'for_real' - with util.mock_modules('nonexistent') as first, \ - util.mock_modules(mod_name) as second: - first.find_module = lambda self, fullname, path=None: None - second.modules[mod_name] = 42 - 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): - - """If there is no __path__ entry on the parent module, then 'path' is None - [no path]. Otherwise, the value for __path__ is passed in for the 'path' - argument [path set].""" - - def log(self, fxn): - log = [] - def wrapper(self, *args, **kwargs): - log.append([args, kwargs]) - return fxn(*args, **kwargs) - return log, wrapper - - - def test_no_path(self): - # [no path] - mod_name = 'top_level' - assert '.' not in mod_name - with util.mock_modules(mod_name) as importer: - log, wrapped_call = self.log(importer.find_module) - importer.find_module = MethodType(wrapped_call, importer) - with util.import_state(meta_path=[importer]): - import_util.import_(mod_name) - assert len(log) == 1 - args = log[0][0] - kwargs = log[0][1] - # Assuming all arguments are positional. - self.assertEqual(len(args), 2) - self.assertEqual(len(kwargs), 0) - self.assertEqual(args[0], mod_name) - self.assertIsNone(args[1]) - - def test_with_path(self): - # [path set] - pkg_name = 'pkg' - mod_name = pkg_name + '.module' - path = [42] - assert '.' in mod_name - with util.mock_modules(pkg_name+'.__init__', mod_name) as importer: - importer.modules[pkg_name].__path__ = path - log, wrapped_call = self.log(importer.find_module) - importer.find_module = MethodType(wrapped_call, importer) - with util.import_state(meta_path=[importer]): - import_util.import_(mod_name) - assert len(log) == 2 - args = log[1][0] - kwargs = log[1][1] - # Assuming all arguments are positional. - self.assertTrue(not kwargs) - self.assertEqual(args[0], mod_name) - self.assertIs(args[1], path) - - - -def test_main(): - from test.support import run_unittest - run_unittest(CallingOrder, CallSignature) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/test_packages.py b/Lib/importlib/test/import_/test_packages.py deleted file mode 100644 index bfa18dc..0000000 --- a/Lib/importlib/test/import_/test_packages.py +++ /dev/null @@ -1,112 +0,0 @@ -from .. import util -from . import util as import_util -import sys -import unittest -import importlib -from test import support - - -class ParentModuleTests(unittest.TestCase): - - """Importing a submodule should import the parent modules.""" - - def test_import_parent(self): - with util.mock_modules('pkg.__init__', 'pkg.module') as mock: - with util.import_state(meta_path=[mock]): - module = import_util.import_('pkg.module') - self.assertIn('pkg', sys.modules) - - def test_bad_parent(self): - with util.mock_modules('pkg.module') as mock: - with util.import_state(meta_path=[mock]): - 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.assertNotIn('pkg', sys.modules) - self.assertIn('pkg.module', sys.modules) - with self.assertRaises(ZeroDivisionError): - import_util.import_('pkg.module') - self.assertNotIn('pkg', sys.modules) - self.assertIn('pkg.module', 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.assertNotIn('pkg', sys.modules) - with self.assertRaises((ZeroDivisionError, ImportError)): - import_util.import_('pkg.module') - self.assertNotIn('pkg', sys.modules) - # XXX False - #self.assertIn('pkg.module', 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.assertNotIn('pkg.subpkg', sys.modules) - with self.assertRaises((ZeroDivisionError, ImportError)): - import_util.import_('pkg.subpkg.module') - self.assertNotIn('pkg.subpkg', sys.modules) - # XXX False - #self.assertIn('pkg.subpkg.module', 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) 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(): - from test.support import run_unittest - run_unittest(ParentModuleTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/test_path.py b/Lib/importlib/test/import_/test_path.py deleted file mode 100644 index 0c086ce..0000000 --- a/Lib/importlib/test/import_/test_path.py +++ /dev/null @@ -1,98 +0,0 @@ -from importlib import _bootstrap -from importlib import machinery -from .. import util -from . import util as import_util -import imp -import os -import sys -import tempfile -from test import support -from types import MethodType -import unittest -import warnings - - -class FinderTests(unittest.TestCase): - - """Tests for PathFinder.""" - - def test_failure(self): - # Test None returned upon not finding a suitable finder. - module = '' - with util.import_state(): - self.assertIsNone(machinery.PathFinder.find_module(module)) - - def test_sys_path(self): - # Test that sys.path is used when 'path' is None. - # Implicitly tests that sys.path_importer_cache is used. - module = '' - path = '' - importer = util.mock_modules(module) - with util.import_state(path_importer_cache={path: importer}, - path=[path]): - loader = machinery.PathFinder.find_module(module) - self.assertIs(loader, importer) - - def test_path(self): - # Test that 'path' is used when set. - # Implicitly tests that sys.path_importer_cache is used. - module = '' - path = '' - importer = util.mock_modules(module) - with util.import_state(path_importer_cache={path: importer}): - loader = machinery.PathFinder.find_module(module, [path]) - self.assertIs(loader, importer) - - def test_empty_list(self): - # An empty list should not count as asking for sys.path. - module = 'module' - 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. - module = '' - path = '' - importer = util.mock_modules(module) - hook = import_util.mock_path_hook(path, importer=importer) - with util.import_state(path_hooks=[hook]): - loader = machinery.PathFinder.find_module(module, [path]) - self.assertIs(loader, importer) - self.assertIn(path, sys.path_importer_cache) - self.assertIs(sys.path_importer_cache[path], importer) - - 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 = '' - importer = util.mock_modules(module) - 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.assertIs(loader, importer) - self.assertIn(os.curdir, sys.path_importer_cache) - - -def test_main(): - from test.support import run_unittest - 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 deleted file mode 100644 index 4569c26..0000000 --- a/Lib/importlib/test/import_/test_relative_imports.py +++ /dev/null @@ -1,217 +0,0 @@ -"""Test relative imports (PEP 328).""" -from .. import util -from . import util as import_util -import sys -import unittest - -class RelativeImports(unittest.TestCase): - - """PEP 328 introduced relative imports. This allows for imports to occur - from within a package without having to specify the actual package name. - - A simple example is to import another module within the same package - [module from module]:: - - # From pkg.mod1 with pkg.mod2 being a module. - from . import mod2 - - This also works for getting an attribute from a module that is specified - in a relative fashion [attr from module]:: - - # From pkg.mod1. - from .mod2 import attr - - But this is in no way restricted to working between modules; it works - from [package to module],:: - - # From pkg, importing pkg.module which is a module. - from . import module - - [module to package],:: - - # Pull attr from pkg, called from pkg.module which is a module. - from . import attr - - and [package to package]:: - - # From pkg.subpkg1 (both pkg.subpkg[1,2] are packages). - from .. import subpkg2 - - The number of dots used is in no way restricted [deep import]:: - - # Import pkg.attr from pkg.pkg1.pkg2.pkg3.pkg4.pkg5. - from ...... import attr - - To prevent someone from accessing code that is outside of a package, one - cannot reach the location containing the root package itself:: - - # From pkg.__init__ [too high from package] - from .. import top_level - - # From pkg.module [too high from module] - from .. import top_level - - Relative imports are the only type of import that allow for an empty - module name for an import [empty name]. - - """ - - def relative_import_test(self, create, globals_, callback): - """Abstract out boilerplace for setting up for an import test.""" - uncache_names = [] - for name in create: - if not name.endswith('.__init__'): - uncache_names.append(name) - else: - uncache_names.append(name[:-len('.__init__')]) - with util.mock_modules(*create) as importer: - with util.import_state(meta_path=[importer]): - for global_ in globals_: - with util.uncache(*uncache_names): - callback(global_) - - - def test_module_from_module(self): - # [module from module] - create = 'pkg.__init__', 'pkg.mod2' - globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.mod1'} - def callback(global_): - import_util.import_('pkg') # For __import__(). - module = import_util.import_('', global_, fromlist=['mod2'], level=1) - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(hasattr(module, 'mod2')) - self.assertEqual(module.mod2.attr, 'pkg.mod2') - self.relative_import_test(create, globals_, callback) - - def test_attr_from_module(self): - # [attr from module] - create = 'pkg.__init__', 'pkg.mod2' - globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.mod1'} - def callback(global_): - import_util.import_('pkg') # For __import__(). - module = import_util.import_('mod2', global_, fromlist=['attr'], - level=1) - self.assertEqual(module.__name__, 'pkg.mod2') - self.assertEqual(module.attr, 'pkg.mod2') - self.relative_import_test(create, globals_, callback) - - def test_package_to_module(self): - # [package to module] - create = 'pkg.__init__', 'pkg.module' - globals_ = ({'__package__': 'pkg'}, - {'__name__': 'pkg', '__path__': ['blah']}) - def callback(global_): - import_util.import_('pkg') # For __import__(). - module = import_util.import_('', global_, fromlist=['module'], - level=1) - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(hasattr(module, 'module')) - self.assertEqual(module.module.attr, 'pkg.module') - self.relative_import_test(create, globals_, callback) - - def test_module_to_package(self): - # [module to package] - create = 'pkg.__init__', 'pkg.module' - globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.module'} - def callback(global_): - import_util.import_('pkg') # For __import__(). - module = import_util.import_('', global_, fromlist=['attr'], level=1) - self.assertEqual(module.__name__, 'pkg') - self.relative_import_test(create, globals_, callback) - - def test_package_to_package(self): - # [package to package] - create = ('pkg.__init__', 'pkg.subpkg1.__init__', - 'pkg.subpkg2.__init__') - globals_ = ({'__package__': 'pkg.subpkg1'}, - {'__name__': 'pkg.subpkg1', '__path__': ['blah']}) - def callback(global_): - module = import_util.import_('', global_, fromlist=['subpkg2'], - level=2) - self.assertEqual(module.__name__, 'pkg') - self.assertTrue(hasattr(module, 'subpkg2')) - self.assertEqual(module.subpkg2.attr, 'pkg.subpkg2.__init__') - - def test_deep_import(self): - # [deep import] - create = ['pkg.__init__'] - for count in range(1,6): - create.append('{0}.pkg{1}.__init__'.format( - create[-1][:-len('.__init__')], count)) - globals_ = ({'__package__': 'pkg.pkg1.pkg2.pkg3.pkg4.pkg5'}, - {'__name__': 'pkg.pkg1.pkg2.pkg3.pkg4.pkg5', - '__path__': ['blah']}) - def callback(global_): - import_util.import_(globals_[0]['__package__']) - module = import_util.import_('', global_, fromlist=['attr'], level=6) - self.assertEqual(module.__name__, 'pkg') - self.relative_import_test(create, globals_, callback) - - def test_too_high_from_package(self): - # [too high from package] - create = ['top_level', 'pkg.__init__'] - globals_ = ({'__package__': 'pkg'}, - {'__name__': 'pkg', '__path__': ['blah']}) - def callback(global_): - import_util.import_('pkg') - with self.assertRaises(ValueError): - import_util.import_('', global_, fromlist=['top_level'], - level=2) - self.relative_import_test(create, globals_, callback) - - def test_too_high_from_module(self): - # [too high from module] - create = ['top_level', 'pkg.__init__', 'pkg.module'] - globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.module'} - def callback(global_): - import_util.import_('pkg') - with self.assertRaises(ValueError): - import_util.import_('', global_, fromlist=['top_level'], - level=2) - self.relative_import_test(create, globals_, callback) - - def test_empty_name_w_level_0(self): - # [empty name] - with self.assertRaises(ValueError): - import_util.import_('') - - def test_import_from_different_package(self): - # Test importing from a different package than the caller. - # in pkg.subpkg1.mod - # from ..subpkg2 import mod - create = ['__runpy_pkg__.__init__', - '__runpy_pkg__.__runpy_pkg__.__init__', - '__runpy_pkg__.uncle.__init__', - '__runpy_pkg__.uncle.cousin.__init__', - '__runpy_pkg__.uncle.cousin.nephew'] - globals_ = {'__package__': '__runpy_pkg__.__runpy_pkg__'} - def callback(global_): - import_util.import_('__runpy_pkg__.__runpy_pkg__') - module = import_util.import_('uncle.cousin', globals_, {}, - fromlist=['nephew'], - level=2) - 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(): - from test.support import run_unittest - run_unittest(RelativeImports) - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/import_/util.py b/Lib/importlib/test/import_/util.py deleted file mode 100644 index 86ac065..0000000 --- a/Lib/importlib/test/import_/util.py +++ /dev/null @@ -1,28 +0,0 @@ -import functools -import importlib -import unittest - - -using___import__ = False - - -def import_(*args, **kwargs): - """Delegate to allow for injecting different implementations of import.""" - if using___import__: - return __import__(*args, **kwargs) - else: - return importlib.__import__(*args, **kwargs) - - -def importlib_only(fxn): - """Decorator to skip a test if using __builtins__.__import__.""" - return unittest.skipIf(using___import__, "importlib-specific test")(fxn) - - -def mock_path_hook(*entries, importer): - """A mock sys.path_hooks entry.""" - def hook(entry): - if entry not in entries: - raise ImportError - return importer - return hook diff --git a/Lib/importlib/test/regrtest.py b/Lib/importlib/test/regrtest.py deleted file mode 100644 index a5be11f..0000000 --- a/Lib/importlib/test/regrtest.py +++ /dev/null @@ -1,17 +0,0 @@ -"""Run Python's standard test suite using importlib.__import__. - -Tests known to fail because of assumptions that importlib (properly) -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. - -""" -import importlib -import sys -from test import regrtest - -if __name__ == '__main__': - __builtins__.__import__ = importlib.__import__ - sys.path_importer_cache.clear() - - regrtest.main(quiet=True, verbose2=True) diff --git a/Lib/importlib/test/source/__init__.py b/Lib/importlib/test/source/__init__.py deleted file mode 100644 index 8d7c49d..0000000 --- a/Lib/importlib/test/source/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import importlib.test -import os.path -import unittest - - -def test_suite(): - directory = os.path.dirname(__file__) - return importlib.test.test_suite('importlib.test.source', directory) - - -if __name__ == '__main__': - from test.support import run_unittest - run_unittest(test_suite()) diff --git a/Lib/importlib/test/source/test_abc_loader.py b/Lib/importlib/test/source/test_abc_loader.py deleted file mode 100644 index afcaad0..0000000 --- a/Lib/importlib/test/source/test_abc_loader.py +++ /dev/null @@ -1,886 +0,0 @@ -import importlib -from importlib import abc - -from .. import abc as testing_abc -from .. import util -from . import util as source_util - -import imp -import inspect -import io -import marshal -import os -import sys -import types -import unittest -import warnings - - -class SourceOnlyLoaderMock(abc.SourceLoader): - - # Globals that should be defined for all modules. - source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " - b"repr(__loader__)])") - - def __init__(self, path): - self.path = path - - def get_data(self, path): - assert self.path == path - return self.source - - def get_filename(self, fullname): - return self.path - - -class SourceLoaderMock(SourceOnlyLoaderMock): - - source_mtime = 1 - - 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(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)) - self.bytecode = bytes(data) - self.written = {} - - def get_data(self, path): - if path == self.path: - return super().get_data(path) - elif path == self.bytecode_path: - return self.bytecode - else: - raise IOError - - def path_stats(self, path): - assert path == self.path - return {'mtime': self.source_mtime, 'size': self.source_size} - - def set_data(self, path, data): - self.written[path] = bytes(data) - return path == self.bytecode_path - - -class PyLoaderMock(abc.PyLoader): - - # Globals that should be defined for all modules. - source = (b"_ = '::'.join([__name__, __file__, __package__, " - b"repr(__loader__)])") - - def __init__(self, data): - """Take a dict of 'module_name: path' pairings. - - Paths should have no file extension, allowing packages to be denoted by - ending in '__init__'. - - """ - self.module_paths = data - self.path_to_module = {val:key for key,val in data.items()} - - def get_data(self, path): - if path not in self.path_to_module: - raise IOError - return self.source - - def is_package(self, name): - filename = os.path.basename(self.get_filename(name)) - return os.path.splitext(filename)[0] == '__init__' - - def source_path(self, name): - try: - return self.module_paths[name] - except KeyError: - raise ImportError - - def get_filename(self, name): - """Silence deprecation warning.""" - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - path = super().get_filename(name) - assert len(w) == 1 - assert issubclass(w[0].category, DeprecationWarning) - return path - - -class PyLoaderCompatMock(PyLoaderMock): - - """Mock that matches what is suggested to have a loader that is compatible - from Python 3.1 onwards.""" - - def get_filename(self, fullname): - try: - return self.module_paths[fullname] - except KeyError: - raise ImportError - - def source_path(self, fullname): - try: - return self.get_filename(fullname) - except ImportError: - return None - - -class PyPycLoaderMock(abc.PyPycLoader, PyLoaderMock): - - default_mtime = 1 - - def __init__(self, source, bc={}): - """Initialize mock. - - 'bc' is a dict keyed on a module's name. The value is dict with - possible keys of 'path', 'mtime', 'magic', and 'bc'. Except for 'path', - each of those keys control if any part of created bytecode is to - deviate from default values. - - """ - super().__init__(source) - self.module_bytecode = {} - self.path_to_bytecode = {} - self.bytecode_to_path = {} - for name, data in bc.items(): - self.path_to_bytecode[data['path']] = name - self.bytecode_to_path[name] = data['path'] - magic = data.get('magic', imp.get_magic()) - mtime = importlib._w_long(data.get('mtime', self.default_mtime)) - source_size = importlib._w_long(len(self.source) & 0xFFFFFFFF) - if 'bc' in data: - bc = data['bc'] - else: - bc = self.compile_bc(name) - self.module_bytecode[name] = magic + mtime + source_size + bc - - def compile_bc(self, name): - source_path = self.module_paths.get(name, '') or '' - code = compile(self.source, source_path, 'exec') - return marshal.dumps(code) - - def source_mtime(self, name): - if name in self.module_paths: - return self.default_mtime - elif name in self.module_bytecode: - return None - else: - raise ImportError - - def bytecode_path(self, name): - try: - return self.bytecode_to_path[name] - except KeyError: - if name in self.module_paths: - return None - else: - raise ImportError - - def write_bytecode(self, name, bytecode): - self.module_bytecode[name] = bytecode - return True - - def get_data(self, path): - if path in self.path_to_module: - return super().get_data(path) - elif path in self.path_to_bytecode: - name = self.path_to_bytecode[path] - return self.module_bytecode[name] - else: - raise IOError - - def is_package(self, name): - try: - return super().is_package(name) - except TypeError: - return '__init__' in self.bytecode_to_path[name] - - def get_code(self, name): - with warnings.catch_warnings(record=True) as w: - warnings.simplefilter("always") - code_object = super().get_code(name) - assert len(w) == 1 - assert issubclass(w[0].category, DeprecationWarning) - return code_object - -class PyLoaderTests(testing_abc.LoaderTests): - - """Tests for importlib.abc.PyLoader.""" - - mocker = PyLoaderMock - - def eq_attrs(self, ob, **kwargs): - for attr, val in kwargs.items(): - found = getattr(ob, attr) - self.assertEqual(found, val, - "{} attribute: {} != {}".format(attr, found, val)) - - def test_module(self): - name = '' - path = os.path.join('', 'path', 'to', 'module') - mock = self.mocker({name: path}) - with util.uncache(name): - module = mock.load_module(name) - self.assertIn(name, sys.modules) - self.eq_attrs(module, __name__=name, __file__=path, __package__='', - __loader__=mock) - self.assertTrue(not hasattr(module, '__path__')) - return mock, name - - def test_package(self): - name = '' - path = os.path.join('path', 'to', name, '__init__') - mock = self.mocker({name: path}) - with util.uncache(name): - module = mock.load_module(name) - self.assertIn(name, sys.modules) - self.eq_attrs(module, __name__=name, __file__=path, - __path__=[os.path.dirname(path)], __package__=name, - __loader__=mock) - return mock, name - - def test_lacking_parent(self): - name = 'pkg.mod' - path = os.path.join('path', 'to', 'pkg', 'mod') - mock = self.mocker({name: path}) - with util.uncache(name): - module = mock.load_module(name) - self.assertIn(name, sys.modules) - self.eq_attrs(module, __name__=name, __file__=path, __package__='pkg', - __loader__=mock) - self.assertFalse(hasattr(module, '__path__')) - return mock, name - - def test_module_reuse(self): - name = 'mod' - path = os.path.join('path', 'to', 'mod') - module = imp.new_module(name) - mock = self.mocker({name: path}) - with util.uncache(name): - sys.modules[name] = module - loaded_module = mock.load_module(name) - self.assertIs(loaded_module, module) - self.assertIs(sys.modules[name], module) - return mock, name - - def test_state_after_failure(self): - name = "mod" - module = imp.new_module(name) - module.blah = None - mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) - mock.source = b"1/0" - with util.uncache(name): - sys.modules[name] = module - with self.assertRaises(ZeroDivisionError): - mock.load_module(name) - self.assertIs(sys.modules[name], module) - self.assertTrue(hasattr(module, 'blah')) - return mock - - def test_unloadable(self): - name = "mod" - mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) - mock.source = b"1/0" - with util.uncache(name): - with self.assertRaises(ZeroDivisionError): - mock.load_module(name) - self.assertNotIn(name, sys.modules) - return mock - - -class PyLoaderCompatTests(PyLoaderTests): - - """Test that the suggested code to make a loader that is compatible from - Python 3.1 forward works.""" - - mocker = PyLoaderCompatMock - - -class PyLoaderInterfaceTests(unittest.TestCase): - - """Tests for importlib.abc.PyLoader to make sure that when source_path() - doesn't return a path everything works as expected.""" - - def test_no_source_path(self): - # No source path should lead to ImportError. - name = 'mod' - mock = PyLoaderMock({}) - with util.uncache(name), self.assertRaises(ImportError): - mock.load_module(name) - - def test_source_path_is_None(self): - name = 'mod' - mock = PyLoaderMock({name: None}) - with util.uncache(name), self.assertRaises(ImportError): - mock.load_module(name) - - def test_get_filename_with_source_path(self): - # get_filename() should return what source_path() returns. - name = 'mod' - path = os.path.join('path', 'to', 'source') - mock = PyLoaderMock({name: path}) - with util.uncache(name): - self.assertEqual(mock.get_filename(name), path) - - def test_get_filename_no_source_path(self): - # get_filename() should raise ImportError if source_path returns None. - name = 'mod' - mock = PyLoaderMock({name: None}) - with util.uncache(name), self.assertRaises(ImportError): - mock.get_filename(name) - - -class PyPycLoaderTests(PyLoaderTests): - - """Tests for importlib.abc.PyPycLoader.""" - - mocker = PyPycLoaderMock - - @source_util.writes_bytecode_files - def verify_bytecode(self, mock, name): - assert name in mock.module_paths - self.assertIn(name, mock.module_bytecode) - magic = mock.module_bytecode[name][:4] - self.assertEqual(magic, imp.get_magic()) - mtime = importlib._r_long(mock.module_bytecode[name][4:8]) - self.assertEqual(mtime, 1) - source_size = mock.module_bytecode[name][8:12] - self.assertEqual(len(mock.source) & 0xFFFFFFFF, - importlib._r_long(source_size)) - bc = mock.module_bytecode[name][12:] - self.assertEqual(bc, mock.compile_bc(name)) - - def test_module(self): - mock, name = super().test_module() - self.verify_bytecode(mock, name) - - def test_package(self): - mock, name = super().test_package() - self.verify_bytecode(mock, name) - - def test_lacking_parent(self): - mock, name = super().test_lacking_parent() - self.verify_bytecode(mock, name) - - def test_module_reuse(self): - mock, name = super().test_module_reuse() - self.verify_bytecode(mock, name) - - def test_state_after_failure(self): - super().test_state_after_failure() - - def test_unloadable(self): - super().test_unloadable() - - -class PyPycLoaderInterfaceTests(unittest.TestCase): - - """Test for the interface of importlib.abc.PyPycLoader.""" - - def get_filename_check(self, src_path, bc_path, expect): - name = 'mod' - mock = PyPycLoaderMock({name: src_path}, {name: {'path': bc_path}}) - with util.uncache(name): - assert mock.source_path(name) == src_path - assert mock.bytecode_path(name) == bc_path - self.assertEqual(mock.get_filename(name), expect) - - def test_filename_with_source_bc(self): - # When source and bytecode paths present, return the source path. - self.get_filename_check('source_path', 'bc_path', 'source_path') - - def test_filename_with_source_no_bc(self): - # With source but no bc, return source path. - self.get_filename_check('source_path', None, 'source_path') - - def test_filename_with_no_source_bc(self): - # With not source but bc, return the bc path. - self.get_filename_check(None, 'bc_path', 'bc_path') - - def test_filename_with_no_source_or_bc(self): - # With no source or bc, raise ImportError. - name = 'mod' - mock = PyPycLoaderMock({name: None}, {name: {'path': None}}) - with util.uncache(name), self.assertRaises(ImportError): - mock.get_filename(name) - - -class SkipWritingBytecodeTests(unittest.TestCase): - - """Test that bytecode is properly handled based on - sys.dont_write_bytecode.""" - - @source_util.writes_bytecode_files - def run_test(self, dont_write_bytecode): - name = 'mod' - mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}) - sys.dont_write_bytecode = dont_write_bytecode - with util.uncache(name): - mock.load_module(name) - self.assertIsNot(name in mock.module_bytecode, dont_write_bytecode) - - def test_no_bytecode_written(self): - self.run_test(True) - - def test_bytecode_written(self): - self.run_test(False) - - -class RegeneratedBytecodeTests(unittest.TestCase): - - """Test that bytecode is regenerated as expected.""" - - @source_util.writes_bytecode_files - def test_different_magic(self): - # A different magic number should lead to new bytecode. - name = 'mod' - bad_magic = b'\x00\x00\x00\x00' - assert bad_magic != imp.get_magic() - mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, - {name: {'path': os.path.join('path', 'to', - 'mod.bytecode'), - 'magic': bad_magic}}) - with util.uncache(name): - mock.load_module(name) - self.assertIn(name, mock.module_bytecode) - magic = mock.module_bytecode[name][:4] - self.assertEqual(magic, imp.get_magic()) - - @source_util.writes_bytecode_files - def test_old_mtime(self): - # Bytecode with an older mtime should be regenerated. - name = 'mod' - old_mtime = PyPycLoaderMock.default_mtime - 1 - mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, - {name: {'path': 'path/to/mod.bytecode', 'mtime': old_mtime}}) - with util.uncache(name): - mock.load_module(name) - self.assertIn(name, mock.module_bytecode) - mtime = importlib._r_long(mock.module_bytecode[name][4:8]) - self.assertEqual(mtime, PyPycLoaderMock.default_mtime) - - -class BadBytecodeFailureTests(unittest.TestCase): - - """Test import failures when there is no source and parts of the bytecode - is bad.""" - - def test_bad_magic(self): - # A bad magic number should lead to an ImportError. - name = 'mod' - bad_magic = b'\x00\x00\x00\x00' - bc = {name: - {'path': os.path.join('path', 'to', 'mod'), - 'magic': bad_magic}} - mock = PyPycLoaderMock({name: None}, bc) - 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. - name = 'mod' - bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b''}} - mock = PyPycLoaderMock({name: None}, bc) - with util.uncache(name), self.assertRaises(EOFError): - mock.load_module(name) - - def test_bad_bytecode(self): - # Malformed code object bytecode should lead to a ValueError. - name = 'mod' - bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b'1234'}} - mock = PyPycLoaderMock({name: None}, bc) - with util.uncache(name), self.assertRaises(ValueError): - mock.load_module(name) - - -def raise_ImportError(*args, **kwargs): - raise ImportError - -class MissingPathsTests(unittest.TestCase): - - """Test what happens when a source or bytecode path does not exist (either - from *_path returning None or raising ImportError).""" - - def test_source_path_None(self): - # Bytecode should be used when source_path returns None, along with - # __file__ being set to the bytecode path. - name = 'mod' - bytecode_path = 'path/to/mod' - mock = PyPycLoaderMock({name: None}, {name: {'path': bytecode_path}}) - with util.uncache(name): - module = mock.load_module(name) - self.assertEqual(module.__file__, bytecode_path) - - # Testing for bytecode_path returning None handled by all tests where no - # bytecode initially exists. - - def test_all_paths_None(self): - # If all *_path methods return None, raise ImportError. - name = 'mod' - mock = PyPycLoaderMock({name: None}) - 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. - name = 'mod' - mock = PyPycLoaderMock({}, {name: {'path': os.path.join('path', 'to', - 'mod')}}) - with util.uncache(name), self.assertRaises(ImportError): - mock.load_module(name) - - def test_bytecode_path_ImportError(self): - # An ImportError from bytecode_path should trigger an ImportError. - name = 'mod' - 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) as cm: - mock.load_module(name) - - -class SourceLoaderTestHarness(unittest.TestCase): - - def setUp(self, *, is_package=True, **kwargs): - self.package = 'pkg' - if is_package: - self.path = os.path.join(self.package, '__init__.py') - self.name = self.package - else: - module_name = 'mod' - self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) - self.name = '.'.join([self.package, module_name]) - self.cached = imp.cache_from_source(self.path) - self.loader = self.loader_mock(self.path, **kwargs) - - def verify_module(self, module): - self.assertEqual(module.__name__, self.name) - self.assertEqual(module.__file__, self.path) - self.assertEqual(module.__cached__, self.cached) - self.assertEqual(module.__package__, self.package) - self.assertEqual(module.__loader__, self.loader) - values = module._.split('::') - self.assertEqual(values[0], self.name) - self.assertEqual(values[1], self.path) - self.assertEqual(values[2], self.cached) - self.assertEqual(values[3], self.package) - self.assertEqual(values[4], repr(self.loader)) - - def verify_code(self, code_object): - module = imp.new_module(self.name) - module.__file__ = self.path - module.__cached__ = self.cached - module.__package__ = self.package - module.__loader__ = self.loader - module.__path__ = [] - exec(code_object, module.__dict__) - self.verify_module(module) - - -class SourceOnlyLoaderTests(SourceLoaderTestHarness): - - """Test importlib.abc.SourceLoader for source-only loading. - - Reload testing is subsumed by the tests for - importlib.util.module_for_loader. - - """ - - loader_mock = SourceOnlyLoaderMock - - def test_get_source(self): - # Verify the source code is returned as a string. - # If an IOError is raised by get_data then raise ImportError. - expected_source = self.loader.source.decode('utf-8') - self.assertEqual(self.loader.get_source(self.name), expected_source) - def raise_IOError(path): - raise IOError - self.loader.get_data = raise_IOError - 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. - self.setUp(is_package=False) - self.assertFalse(self.loader.is_package(self.name)) - self.setUp(is_package=True) - self.assertTrue(self.loader.is_package(self.name)) - self.assertFalse(self.loader.is_package(self.name + '.__init__')) - - def test_get_code(self): - # Verify the code object is created. - code_object = self.loader.get_code(self.name) - self.verify_code(code_object) - - def test_load_module(self): - # Loading a module should set __name__, __loader__, __package__, - # __path__ (for packages), __file__, and __cached__. - # The module should also be put into sys.modules. - with util.uncache(self.name): - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertEqual(module.__path__, [os.path.dirname(self.path)]) - self.assertIn(self.name, sys.modules) - - def test_package_settings(self): - # __package__ needs to be set, while __path__ is set on if the module - # is a package. - # Testing the values for a package are covered by test_load_module. - self.setUp(is_package=False) - with util.uncache(self.name): - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertTrue(not hasattr(module, '__path__')) - - def test_get_source_encoding(self): - # Source is considered encoded in UTF-8 by default unless otherwise - # specified by an encoding line. - source = "_ = 'ü'" - self.loader.source = source.encode('utf-8') - returned_source = self.loader.get_source(self.name) - self.assertEqual(returned_source, source) - source = "# coding: latin-1\n_ = ü" - self.loader.source = source.encode('latin-1') - returned_source = self.loader.get_source(self.name) - self.assertEqual(returned_source, source) - - -@unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") -class SourceLoaderBytecodeTests(SourceLoaderTestHarness): - - """Test importlib.abc.SourceLoader's use of bytecode. - - Source-only testing handled by SourceOnlyLoaderTests. - - """ - - loader_mock = SourceLoaderMock - - def verify_code(self, code_object, *, bytecode_written=False): - super().verify_code(code_object) - if bytecode_written: - self.assertIn(self.cached, self.loader.written) - data = bytearray(imp.get_magic()) - 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)) - - def test_code_with_everything(self): - # When everything should work. - code_object = self.loader.get_code(self.name) - self.verify_code(code_object) - - def test_no_bytecode(self): - # If no bytecode exists then move on to the source. - self.loader.bytecode_path = "" - # Sanity check - with self.assertRaises(IOError): - bytecode_path = imp.cache_from_source(self.path) - self.loader.get_data(bytecode_path) - code_object = self.loader.get_code(self.name) - self.verify_code(code_object, bytecode_written=True) - - def test_code_bad_timestamp(self): - # Bytecode is only used when the timestamp matches the source EXACTLY. - for source_mtime in (0, 2): - assert source_mtime != self.loader.source_mtime - original = self.loader.source_mtime - self.loader.source_mtime = source_mtime - # If bytecode is used then EOFError would be raised by marshal. - self.loader.bytecode = self.loader.bytecode[8:] - code_object = self.loader.get_code(self.name) - self.verify_code(code_object, bytecode_written=True) - self.loader.source_mtime = original - - def test_code_bad_magic(self): - # Skip over bytecode with a bad magic number. - self.setUp(magic=b'0000') - # If bytecode is used then EOFError would be raised by marshal. - self.loader.bytecode = self.loader.bytecode[8:] - code_object = self.loader.get_code(self.name) - self.verify_code(code_object, bytecode_written=True) - - def test_dont_write_bytecode(self): - # Bytecode is not written if sys.dont_write_bytecode is true. - # Can assume it is false already thanks to the skipIf class decorator. - try: - sys.dont_write_bytecode = True - self.loader.bytecode_path = "" - code_object = self.loader.get_code(self.name) - self.assertNotIn(self.cached, self.loader.written) - finally: - sys.dont_write_bytecode = False - - def test_no_set_data(self): - # If set_data is not defined, one can still read bytecode. - self.setUp(magic=b'0000') - original_set_data = self.loader.__class__.set_data - try: - del self.loader.__class__.set_data - code_object = self.loader.get_code(self.name) - self.verify_code(code_object) - finally: - self.loader.__class__.set_data = original_set_data - - def test_set_data_raises_exceptions(self): - # Raising NotImplementedError or IOError is okay for set_data. - def raise_exception(exc): - def closure(*args, **kwargs): - raise exc - return closure - - self.setUp(magic=b'0000') - self.loader.set_data = raise_exception(NotImplementedError) - code_object = self.loader.get_code(self.name) - self.verify_code(code_object) - - -class SourceLoaderGetSourceTests(unittest.TestCase): - - """Tests for importlib.abc.SourceLoader.get_source().""" - - def test_default_encoding(self): - # Should have no problems with UTF-8 text. - name = 'mod' - mock = SourceOnlyLoaderMock('mod.file') - source = 'x = "ü"' - mock.source = source.encode('utf-8') - returned_source = mock.get_source(name) - self.assertEqual(returned_source, source) - - def test_decoded_source(self): - # Decoding should work. - name = 'mod' - mock = SourceOnlyLoaderMock("mod.file") - source = "# coding: Latin-1\nx='ü'" - assert source.encode('latin-1') != source.encode('utf-8') - mock.source = source.encode('latin-1') - returned_source = mock.get_source(name) - self.assertEqual(returned_source, source) - - def test_universal_newlines(self): - # PEP 302 says universal newlines should be used. - name = 'mod' - mock = SourceOnlyLoaderMock('mod.file') - source = "x = 42\r\ny = -13\r\n" - mock.source = source.encode('utf-8') - expect = io.IncrementalNewlineDecoder(None, True).decode(source) - self.assertEqual(mock.get_source(name), expect) - -class AbstractMethodImplTests(unittest.TestCase): - - """Test the concrete abstractmethod implementations.""" - - class Loader(abc.Loader): - def load_module(self, fullname): - super().load_module(fullname) - - class Finder(abc.Finder): - def find_module(self, _): - super().find_module(_) - - class ResourceLoader(Loader, abc.ResourceLoader): - def get_data(self, _): - super().get_data(_) - - class InspectLoader(Loader, abc.InspectLoader): - def is_package(self, _): - super().is_package(_) - - def get_code(self, _): - super().get_code(_) - - def get_source(self, _): - super().get_source(_) - - class ExecutionLoader(InspectLoader, abc.ExecutionLoader): - def get_filename(self, _): - super().get_filename(_) - - class SourceLoader(ResourceLoader, ExecutionLoader, abc.SourceLoader): - pass - - class PyLoader(ResourceLoader, InspectLoader, abc.PyLoader): - def source_path(self, _): - super().source_path(_) - - class PyPycLoader(PyLoader, abc.PyPycLoader): - def bytecode_path(self, _): - super().bytecode_path(_) - - def source_mtime(self, _): - super().source_mtime(_) - - def write_bytecode(self, _, _2): - super().write_bytecode(_, _2) - - def raises_NotImplementedError(self, ins, *args): - for method_name in args: - method = getattr(ins, method_name) - arg_count = len(inspect.getfullargspec(method)[0]) - 1 - args = [''] * arg_count - try: - method(*args) - except NotImplementedError: - pass - else: - msg = "{}.{} did not raise NotImplementedError" - self.fail(msg.format(ins.__class__.__name__, method_name)) - - def test_Loader(self): - self.raises_NotImplementedError(self.Loader(), 'load_module') - - # XXX misplaced; should be somewhere else - def test_Finder(self): - self.raises_NotImplementedError(self.Finder(), 'find_module') - - def test_ResourceLoader(self): - self.raises_NotImplementedError(self.ResourceLoader(), 'load_module', - 'get_data') - - def test_InspectLoader(self): - self.raises_NotImplementedError(self.InspectLoader(), 'load_module', - 'is_package', 'get_code', 'get_source') - - def test_ExecutionLoader(self): - self.raises_NotImplementedError(self.ExecutionLoader(), 'load_module', - 'is_package', 'get_code', 'get_source', - 'get_filename') - - def test_SourceLoader(self): - ins = self.SourceLoader() - # Required abstractmethods. - self.raises_NotImplementedError(ins, 'get_filename', 'get_data') - # Optional abstractmethods. - self.raises_NotImplementedError(ins,'path_stats', 'set_data') - - def test_PyLoader(self): - self.raises_NotImplementedError(self.PyLoader(), 'source_path', - 'get_data', 'is_package') - - def test_PyPycLoader(self): - self.raises_NotImplementedError(self.PyPycLoader(), 'source_path', - 'source_mtime', 'bytecode_path', - 'write_bytecode') - - -def test_main(): - from test.support import run_unittest - run_unittest(PyLoaderTests, PyLoaderCompatTests, - PyLoaderInterfaceTests, - PyPycLoaderTests, PyPycLoaderInterfaceTests, - SkipWritingBytecodeTests, RegeneratedBytecodeTests, - BadBytecodeFailureTests, MissingPathsTests, - SourceOnlyLoaderTests, - SourceLoaderBytecodeTests, - SourceLoaderGetSourceTests, - AbstractMethodImplTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/source/test_case_sensitivity.py b/Lib/importlib/test/source/test_case_sensitivity.py deleted file mode 100644 index 21a4378..0000000 --- a/Lib/importlib/test/source/test_case_sensitivity.py +++ /dev/null @@ -1,72 +0,0 @@ -"""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 -import unittest - - -@util.case_insensitive_tests -class CaseSensitivityTest(unittest.TestCase): - - """PEP 235 dictates that on case-preserving, case-insensitive file systems - that imports are case-sensitive unless the PYTHONCASEOK environment - variable is set.""" - - name = 'MoDuLe' - assert name != name.lower() - - def find(self, path): - 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): - """Look for a module with matching and non-matching sensitivity.""" - sensitive_pkg = 'sensitive.{0}'.format(self.name) - insensitive_pkg = 'insensitive.{0}'.format(self.name.lower()) - context = source_util.create_modules(insensitive_pkg, sensitive_pkg) - 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) - - 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)) - self.assertIsNone(insensitive) - - 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)) - self.assertTrue(hasattr(insensitive, 'load_module')) - self.assertIn(self.name, insensitive.get_filename(self.name)) - - -def test_main(): - test_support.run_unittest(CaseSensitivityTest) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/source/test_file_loader.py b/Lib/importlib/test/source/test_file_loader.py deleted file mode 100644 index 236abfb..0000000 --- a/Lib/importlib/test/source/test_file_loader.py +++ /dev/null @@ -1,482 +0,0 @@ -from ... import _bootstrap -import importlib -import importlib.abc -from .. import abc -from .. import util -from . import util as source_util - -import errno -import imp -import marshal -import os -import py_compile -import shutil -import stat -import sys -import unittest - -from test.support import make_legacy_pyc - - -class SimpleTest(unittest.TestCase): - - """Should have no issue importing a source module [basic]. And if there is - a syntax error, it should raise a SyntaxError [syntax error]. - - """ - - 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']) - module = loader.load_module('_temp') - self.assertIn('_temp', sys.modules) - check = {'__name__': '_temp', '__file__': mapping['_temp'], - '__package__': ''} - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) - - def test_package(self): - with source_util.create_modules('_pkg.__init__') as mapping: - loader = _bootstrap.SourceFileLoader('_pkg', - mapping['_pkg.__init__']) - module = loader.load_module('_pkg') - self.assertIn('_pkg', sys.modules) - check = {'__name__': '_pkg', '__file__': mapping['_pkg.__init__'], - '__path__': [os.path.dirname(mapping['_pkg.__init__'])], - '__package__': '_pkg'} - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) - - - def test_lacking_parent(self): - with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: - loader = _bootstrap.SourceFileLoader('_pkg.mod', - mapping['_pkg.mod']) - module = loader.load_module('_pkg.mod') - self.assertIn('_pkg.mod', sys.modules) - check = {'__name__': '_pkg.mod', '__file__': mapping['_pkg.mod'], - '__package__': '_pkg'} - for attr, value in check.items(): - self.assertEqual(getattr(module, attr), value) - - def fake_mtime(self, fxn): - """Fake mtime to always be higher than expected.""" - return lambda name: fxn(name) + 1 - - def test_module_reuse(self): - with source_util.create_modules('_temp') as mapping: - 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") - module = loader.load_module('_temp') - self.assertIn('testing_var', module.__dict__, - "'testing_var' not in " - "{0}".format(list(module.__dict__.keys()))) - self.assertEqual(module, sys.modules['_temp']) - self.assertEqual(id(module), module_id) - self.assertEqual(id(module.__dict__), module_dict_id) - - def test_state_after_failure(self): - # A failed reload should leave the original module intact. - attributes = ('__file__', '__path__', '__package__') - value = '' - name = '_temp' - with source_util.create_modules(name) as mapping: - orig_module = imp.new_module(name) - for attr in attributes: - setattr(orig_module, attr, value) - with open(mapping[name], 'w') as file: - file.write('+++ bad syntax +++') - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) - with self.assertRaises(SyntaxError): - loader.load_module(name) - for attr in attributes: - self.assertEqual(getattr(orig_module, attr), value) - - # [syntax error] - def test_bad_syntax(self): - with source_util.create_modules('_temp') as mapping: - with open(mapping['_temp'], 'w') as file: - file.write('=') - loader = _bootstrap.SourceFileLoader('_temp', mapping['_temp']) - with self.assertRaises(SyntaxError): - loader.load_module('_temp') - self.assertNotIn('_temp', sys.modules) - - def test_file_from_empty_string_dir(self): - # Loading a module found from an empty string entry on sys.path should - # not only work, but keep all attributes relative. - file_path = '_temp.py' - with open(file_path, 'w') as file: - file.write("# test file for importlib") - try: - with util.uncache('_temp'): - 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), - mod.__cached__) - finally: - os.unlink(file_path) - pycache = os.path.dirname(imp.cache_from_source(file_path)) - shutil.rmtree(pycache) - - def test_timestamp_overflow(self): - # When a modification timestamp is larger than 2**32, it should be - # truncated rather than raise an OverflowError. - with source_util.create_modules('_temp') as mapping: - source = mapping['_temp'] - compiled = imp.cache_from_source(source) - with open(source, 'w') as f: - f.write("x = 5") - try: - os.utime(source, (2 ** 33 - 5, 2 ** 33 - 5)) - except OverflowError: - self.skipTest("cannot set modification time to large integer") - except OSError as e: - 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']) - mod = loader.load_module('_temp') - # Sanity checks. - self.assertEqual(mod.__cached__, compiled) - self.assertEqual(mod.x, 5) - # The pyc file was created. - os.stat(compiled) - - -class BadBytecodeTest(unittest.TestCase): - - def import_(self, file, module_name): - loader = self.loader(module_name, file) - module = loader.load_module(module_name) - self.assertIn(module_name, sys.modules) - - def manipulate_bytecode(self, name, mapping, manipulator, *, - del_source=False): - """Manipulate the bytecode of a module by passing it into a callable - that returns what to use as the new bytecode.""" - try: - del sys.modules['_temp'] - except KeyError: - pass - py_compile.compile(mapping[name]) - if not del_source: - bytecode_path = imp.cache_from_source(mapping[name]) - else: - os.unlink(mapping[name]) - bytecode_path = make_legacy_pyc(mapping[name]) - if manipulator: - with open(bytecode_path, 'rb') as file: - bc = file.read() - new_bc = manipulator(bc) - with open(bytecode_path, 'wb') as file: - if new_bc is not None: - file.write(new_bc) - return bytecode_path - - def _test_empty_file(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: - bc_path = self.manipulate_bytecode('_temp', mapping, - lambda bc: b'', - del_source=del_source) - test('_temp', mapping, bc_path) - - @source_util.writes_bytecode_files - def _test_partial_magic(self, test, *, del_source=False): - # When their are less than 4 bytes to a .pyc, regenerate it if - # possible, else raise ImportError. - with source_util.create_modules('_temp') as mapping: - bc_path = self.manipulate_bytecode('_temp', mapping, - lambda bc: bc[:3], - del_source=del_source) - test('_temp', mapping, bc_path) - - def _test_magic_only(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: - bc_path = self.manipulate_bytecode('_temp', mapping, - lambda bc: bc[:4], - del_source=del_source) - test('_temp', mapping, bc_path) - - def _test_partial_timestamp(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: - bc_path = self.manipulate_bytecode('_temp', mapping, - lambda bc: bc[:7], - del_source=del_source) - test('_temp', mapping, bc_path) - - def _test_partial_size(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: - 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[:12], - del_source=del_source) - file_path = mapping['_temp'] if not del_source else bc_path - with self.assertRaises(EOFError): - self.import_(file_path, '_temp') - - 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[:12] + marshal.dumps(b'abcd'), - del_source=del_source) - file_path = mapping['_temp'] if not del_source else bytecode_path - 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[:12] + b'', - del_source=del_source) - file_path = mapping['_temp'] if not del_source else bytecode_path - with self.assertRaises(EOFError): - self.import_(file_path, '_temp') - - def _test_bad_magic(self, test, *, del_source=False): - with source_util.create_modules('_temp') as mapping: - bc_path = self.manipulate_bytecode('_temp', mapping, - lambda bc: b'\x00\x00\x00\x00' + bc[4:]) - test('_temp', mapping, bc_path) - - -class SourceLoaderBadBytecodeTest(BadBytecodeTest): - - loader = _bootstrap.SourceFileLoader - - @source_util.writes_bytecode_files - def test_empty_file(self): - # When a .pyc is empty, regenerate it if possible, else raise - # ImportError. - def test(name, mapping, bytecode_path): - self.import_(mapping[name], name) - with open(bytecode_path, 'rb') as file: - self.assertGreater(len(file.read()), 12) - - self._test_empty_file(test) - - def test_partial_magic(self): - def test(name, mapping, bytecode_path): - self.import_(mapping[name], name) - with open(bytecode_path, 'rb') as file: - self.assertGreater(len(file.read()), 12) - - self._test_partial_magic(test) - - @source_util.writes_bytecode_files - def test_magic_only(self): - # When there is only the magic number, regenerate the .pyc if possible, - # else raise EOFError. - def test(name, mapping, bytecode_path): - self.import_(mapping[name], name) - with open(bytecode_path, 'rb') as file: - self.assertGreater(len(file.read()), 12) - - self._test_magic_only(test) - - @source_util.writes_bytecode_files - def test_bad_magic(self): - # When the magic number is different, the bytecode should be - # regenerated. - def test(name, mapping, bytecode_path): - self.import_(mapping[name], name) - with open(bytecode_path, 'rb') as bytecode_file: - self.assertEqual(bytecode_file.read(4), imp.get_magic()) - - self._test_bad_magic(test) - - @source_util.writes_bytecode_files - def test_partial_timestamp(self): - # When the timestamp 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_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() - - @source_util.writes_bytecode_files - def test_non_code_marshal(self): - self._test_non_code_marshal() - # XXX ImportError when sourceless - - # [bad marshal] - @source_util.writes_bytecode_files - def test_bad_marshal(self): - # Bad marshal data should raise a ValueError. - self._test_bad_marshal() - - # [bad timestamp] - @source_util.writes_bytecode_files - def test_old_timestamp(self): - # When the timestamp is older than the source, bytecode should be - # regenerated. - zeros = b'\x00\x00\x00\x00' - with source_util.create_modules('_temp') as mapping: - py_compile.compile(mapping['_temp']) - bytecode_path = imp.cache_from_source(mapping['_temp']) - with open(bytecode_path, 'r+b') as bytecode_file: - bytecode_file.seek(4) - bytecode_file.write(zeros) - self.import_(mapping['_temp'], '_temp') - source_mtime = os.path.getmtime(mapping['_temp']) - source_timestamp = importlib._w_long(source_mtime) - with open(bytecode_path, 'rb') as bytecode_file: - bytecode_file.seek(4) - self.assertEqual(bytecode_file.read(4), source_timestamp) - - # [bytecode read-only] - @source_util.writes_bytecode_files - def test_read_only_bytecode(self): - # When bytecode is read-only but should be rewritten, fail silently. - with source_util.create_modules('_temp') as mapping: - # Create bytecode that will need to be re-created. - py_compile.compile(mapping['_temp']) - bytecode_path = imp.cache_from_source(mapping['_temp']) - with open(bytecode_path, 'r+b') as bytecode_file: - bytecode_file.seek(0) - bytecode_file.write(b'\x00\x00\x00\x00') - # Make the bytecode read-only. - os.chmod(bytecode_path, - stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) - try: - # Should not raise IOError! - self.import_(mapping['_temp'], '_temp') - finally: - # Make writable for eventual clean-up. - os.chmod(bytecode_path, stat.S_IWUSR) - - -class SourcelessLoaderBadBytecodeTest(BadBytecodeTest): - - loader = _bootstrap.SourcelessFileLoader - - def test_empty_file(self): - def test(name, mapping, bytecode_path): - 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) 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): - def test(name, mapping, bytecode_path): - with self.assertRaises(EOFError): - self.import_(bytecode_path, name) - - self._test_magic_only(test, del_source=True) - - def test_bad_magic(self): - def test(name, mapping, bytecode_path): - 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) - - def test_partial_timestamp(self): - def test(name, mapping, bytecode_path): - with self.assertRaises(EOFError): - self.import_(bytecode_path, name) - - 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) - - def test_non_code_marshal(self): - self._test_non_code_marshal(del_source=True) - - -def test_main(): - from test.support import run_unittest - run_unittest(SimpleTest, - SourceLoaderBadBytecodeTest, - SourcelessLoaderBadBytecodeTest - ) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/source/test_finder.py b/Lib/importlib/test/source/test_finder.py deleted file mode 100644 index fa5d356..0000000 --- a/Lib/importlib/test/source/test_finder.py +++ /dev/null @@ -1,147 +0,0 @@ -from .. import abc -from . import util as source_util - -from importlib import machinery -import errno -import imp -import os -import py_compile -from test.support import make_legacy_pyc -import unittest -import warnings - - -class FinderTests(abc.FinderTests): - - """For a top-level module, it should just be found directly in the - directory being searched. This is true for a directory with source - [top-level source], bytecode [top-level bc], or both [top-level both]. - There is also the possibility that it is a package [top-level package], in - which case there will be a directory with the module name and an - __init__.py file. If there is a directory without an __init__.py an - ImportWarning is returned [empty dir]. - - For sub-modules and sub-packages, the same happens as above but only use - the tail end of the name [sub module] [sub package] [sub empty]. - - When there is a conflict between a package and module having the same name - in the same directory, the package wins out [package over module]. This is - so that imports of modules within the package can occur rather than trigger - an import error. - - When there is a package and module with the same name, always pick the - package over the module [package over module]. This is so that imports from - the package have the possibility of succeeding. - - """ - - def import_(self, root, module): - 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): - """Test the finding of 'test' with the creation of modules listed in - 'create'. - - Any names listed in 'compile_' are byte-compiled. Modules - listed in 'unlink' have their source files deleted. - - """ - if create is None: - create = {test} - with source_util.create_modules(*create) as mapping: - if compile_: - for name in compile_: - py_compile.compile(mapping[name]) - if unlink: - for name in unlink: - os.unlink(mapping[name]) - try: - make_legacy_pyc(mapping[name]) - except OSError as error: - # Some tests do not set compile_=True so the source - # module will not get compiled and there will be no - # PEP 3147 pyc file to rename. - if error.errno != errno.ENOENT: - raise - loader = self.import_(mapping['.root'], test) - self.assertTrue(hasattr(loader, 'load_module')) - return loader - - def test_module(self): - # [top-level source] - self.run_test('top_level') - # [top-level bc] - self.run_test('top_level', compile_={'top_level'}, - unlink={'top_level'}) - # [top-level both] - self.run_test('top_level', compile_={'top_level'}) - - # [top-level package] - def test_package(self): - # Source. - self.run_test('pkg', {'pkg.__init__'}) - # Bytecode. - self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'}, - unlink={'pkg.__init__'}) - # Both. - self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'}) - - # [sub module] - def test_module_in_package(self): - 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.assertTrue(hasattr(loader, 'load_module')) - - # [sub package] - def test_package_in_package(self): - 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') - self.assertTrue(hasattr(loader, 'load_module')) - - # [package over modules] - def test_package_over_module(self): - name = '_temp' - loader = self.run_test(name, {'{0}.__init__'.format(name), name}) - self.assertIn('__init__', loader.get_filename(name)) - - def test_failure(self): - with source_util.create_modules('blah') as mapping: - nothing = self.import_(mapping['.root'], 'sdfsadsadf') - self.assertIsNone(nothing) - - def test_empty_string_for_dir(self): - # The empty string from sys.path means to search in the cwd. - finder = machinery.FileFinder('', (machinery.SourceFileLoader, - machinery.SOURCE_SUFFIXES, True)) - with open('mod.py', 'w') as file: - file.write("# test file for importlib") - try: - loader = finder.find_module('mod') - self.assertTrue(hasattr(loader, 'load_module')) - 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 - run_unittest(FinderTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/source/test_path_hook.py b/Lib/importlib/test/source/test_path_hook.py deleted file mode 100644 index 54c0699..0000000 --- a/Lib/importlib/test/source/test_path_hook.py +++ /dev/null @@ -1,32 +0,0 @@ -from . import util as source_util - -from importlib import machinery -import imp -import unittest - - -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(self.path_hook()(mapping['.root']), - 'find_module')) - - def test_empty_string(self): - # The empty string represents the cwd. - self.assertTrue(hasattr(self.path_hook()(''), 'find_module')) - - -def test_main(): - from test.support import run_unittest - run_unittest(PathHookTest) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/source/test_source_encoding.py b/Lib/importlib/test/source/test_source_encoding.py deleted file mode 100644 index 0ca5195..0000000 --- a/Lib/importlib/test/source/test_source_encoding.py +++ /dev/null @@ -1,123 +0,0 @@ -from . import util as source_util - -from importlib import _bootstrap -import codecs -import re -import sys -# Because sys.path gets essentially blanked, need to have unicodedata already -# imported for the parser to use. -import unicodedata -import unittest - - -CODING_RE = re.compile(r'coding[:=]\s*([-\w.]+)') - - -class EncodingTest(unittest.TestCase): - - """PEP 3120 makes UTF-8 the default encoding for source code - [default encoding]. - - PEP 263 specifies how that can change on a per-file basis. Either the first - or second line can contain the encoding line [encoding first line] - encoding second line]. If the file has the BOM marker it is considered UTF-8 - implicitly [BOM]. If any encoding is specified it must be UTF-8, else it is - an error [BOM and utf-8][BOM conflict]. - - """ - - variable = '\u00fc' - character = '\u00c9' - source_line = "{0} = '{1}'\n".format(variable, character) - module_name = '_temp' - - def run_test(self, source): - 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]) - return loader.load_module(self.module_name) - - def create_source(self, encoding): - encoding_line = "# coding={0}".format(encoding) - assert CODING_RE.search(encoding_line) - source_lines = [encoding_line.encode('utf-8')] - source_lines.append(self.source_line.encode(encoding)) - return b'\n'.join(source_lines) - - def test_non_obvious_encoding(self): - # Make sure that an encoding that has never been a standard one for - # Python works. - encoding_line = "# coding=koi8-r" - assert CODING_RE.search(encoding_line) - source = "{0}\na=42\n".format(encoding_line).encode("koi8-r") - self.run_test(source) - - # [default encoding] - def test_default_encoding(self): - self.run_test(self.source_line.encode('utf-8')) - - # [encoding first line] - def test_encoding_on_first_line(self): - encoding = 'Latin-1' - source = self.create_source(encoding) - self.run_test(source) - - # [encoding second line] - def test_encoding_on_second_line(self): - source = b"#/usr/bin/python\n" + self.create_source('Latin-1') - self.run_test(source) - - # [BOM] - def test_bom(self): - self.run_test(codecs.BOM_UTF8 + self.source_line.encode('utf-8')) - - # [BOM and utf-8] - def test_bom_and_utf_8(self): - source = codecs.BOM_UTF8 + self.create_source('utf-8') - self.run_test(source) - - # [BOM conflict] - def test_bom_conflict(self): - source = codecs.BOM_UTF8 + self.create_source('latin-1') - with self.assertRaises(SyntaxError): - self.run_test(source) - - -class LineEndingTest(unittest.TestCase): - - r"""Source written with the three types of line endings (\n, \r\n, \r) - need to be readable [cr][crlf][lf].""" - - def run_test(self, line_ending): - module_name = '_temp' - source_lines = [b"a = 42", b"b = -13", b''] - source = line_ending.join(source_lines) - with source_util.create_modules(module_name) as mapping: - with open(mapping[module_name], 'wb') as file: - file.write(source) - loader = _bootstrap.SourceFileLoader(module_name, - mapping[module_name]) - return loader.load_module(module_name) - - # [cr] - def test_cr(self): - self.run_test(b'\r') - - # [crlf] - def test_crlf(self): - self.run_test(b'\r\n') - - # [lf] - def test_lf(self): - self.run_test(b'\n') - - -def test_main(): - from test.support import run_unittest - run_unittest(EncodingTest, LineEndingTest) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/source/util.py b/Lib/importlib/test/source/util.py deleted file mode 100644 index ae65663..0000000 --- a/Lib/importlib/test/source/util.py +++ /dev/null @@ -1,97 +0,0 @@ -from .. import util -import contextlib -import errno -import functools -import imp -import os -import os.path -import sys -import tempfile -from test import support - - -def writes_bytecode_files(fxn): - """Decorator to protect sys.dont_write_bytecode from mutation and to skip - tests that require it to be set to False.""" - if sys.dont_write_bytecode: - return lambda *args, **kwargs: None - @functools.wraps(fxn) - def wrapper(*args, **kwargs): - original = sys.dont_write_bytecode - sys.dont_write_bytecode = False - try: - to_return = fxn(*args, **kwargs) - finally: - sys.dont_write_bytecode = original - return to_return - return wrapper - - -def ensure_bytecode_path(bytecode_path): - """Ensure that the __pycache__ directory for PEP 3147 pyc file exists. - - :param bytecode_path: File system path to PEP 3147 pyc file. - """ - try: - os.mkdir(os.path.dirname(bytecode_path)) - except OSError as error: - if error.errno != errno.EEXIST: - raise - - -@contextlib.contextmanager -def create_modules(*names): - """Temporarily create each named module with an attribute (named 'attr') - that contains the name passed into the context manager that caused the - creation of the module. - - All files are created in a temporary directory returned by - tempfile.mkdtemp(). This directory is inserted at the beginning of - sys.path. When the context manager exits all created files (source and - bytecode) are explicitly deleted. - - No magic is performed when creating packages! This means that if you create - a module within a package you must also create the package's __init__ as - well. - - """ - source = 'attr = {0!r}' - created_paths = [] - mapping = {} - state_manager = None - uncache_manager = None - try: - temp_dir = tempfile.mkdtemp() - mapping['.root'] = temp_dir - import_names = set() - for name in names: - if not name.endswith('__init__'): - import_name = name - else: - import_name = name[:-len('.__init__')] - import_names.add(import_name) - if import_name in sys.modules: - del sys.modules[import_name] - name_parts = name.split('.') - file_path = temp_dir - for directory in name_parts[:-1]: - file_path = os.path.join(file_path, directory) - if not os.path.exists(file_path): - os.mkdir(file_path) - created_paths.append(file_path) - file_path = os.path.join(file_path, name_parts[-1] + '.py') - with open(file_path, 'w') as file: - file.write(source.format(name)) - created_paths.append(file_path) - mapping[name] = file_path - uncache_manager = util.uncache(*import_names) - uncache_manager.__enter__() - state_manager = util.import_state(path=[temp_dir]) - state_manager.__enter__() - yield mapping - finally: - if state_manager is not None: - state_manager.__exit__(None, None, None) - if uncache_manager is not None: - uncache_manager.__exit__(None, None, None) - support.rmtree(temp_dir) diff --git a/Lib/importlib/test/test_abc.py b/Lib/importlib/test/test_abc.py deleted file mode 100644 index 008bd21..0000000 --- a/Lib/importlib/test/test_abc.py +++ /dev/null @@ -1,96 +0,0 @@ -from importlib import abc -from importlib import machinery -import inspect -import unittest - - -class InheritanceTests: - - """Test that the specified class is a subclass/superclass of the expected - classes.""" - - subclasses = [] - superclasses = [] - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - assert self.subclasses or self.superclasses, self.__class__ - self.__test = getattr(abc, self.__class__.__name__) - - def test_subclasses(self): - # Test that the expected subclasses inherit. - for subclass in self.subclasses: - self.assertTrue(issubclass(subclass, self.__test), - "{0} is not a subclass of {1}".format(subclass, self.__test)) - - def test_superclasses(self): - # Test that the class inherits from the expected superclasses. - for superclass in self.superclasses: - self.assertTrue(issubclass(self.__test, superclass), - "{0} is not a superclass of {1}".format(superclass, self.__test)) - - -class Finder(InheritanceTests, unittest.TestCase): - - subclasses = [machinery.BuiltinImporter, machinery.FrozenImporter, - machinery.PathFinder] - - -class Loader(InheritanceTests, unittest.TestCase): - - subclasses = [abc.PyLoader] - - -class ResourceLoader(InheritanceTests, unittest.TestCase): - - superclasses = [abc.Loader] - - -class InspectLoader(InheritanceTests, unittest.TestCase): - - superclasses = [abc.Loader] - subclasses = [abc.PyLoader, machinery.BuiltinImporter, - machinery.FrozenImporter, machinery.ExtensionFileLoader] - - -class ExecutionLoader(InheritanceTests, unittest.TestCase): - - superclasses = [abc.InspectLoader] - 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): - - superclasses = [abc.Loader, abc.ResourceLoader, abc.ExecutionLoader] - - -class PyPycLoader(InheritanceTests, unittest.TestCase): - - superclasses = [abc.PyLoader] - - -def test_main(): - from test.support import run_unittest - classes = [] - for class_ in globals().values(): - if (inspect.isclass(class_) and - issubclass(class_, unittest.TestCase) and - issubclass(class_, InheritanceTests)): - classes.append(class_) - run_unittest(*classes) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/test_api.py b/Lib/importlib/test/test_api.py deleted file mode 100644 index ba2a721..0000000 --- a/Lib/importlib/test/test_api.py +++ /dev/null @@ -1,183 +0,0 @@ -from . import util -import imp -import importlib -from importlib import machinery -import sys -from test import support -import unittest - - -class ImportModuleTests(unittest.TestCase): - - """Test importlib.import_module.""" - - def test_module_import(self): - # Test importing a top-level module. - with util.mock_modules('top_level') as mock: - with util.import_state(meta_path=[mock]): - module = importlib.import_module('top_level') - self.assertEqual(module.__name__, 'top_level') - - def test_absolute_package_import(self): - # Test importing a module from a package with an absolute name. - pkg_name = 'pkg' - pkg_long_name = '{0}.__init__'.format(pkg_name) - name = '{0}.mod'.format(pkg_name) - with util.mock_modules(pkg_long_name, name) as mock: - with util.import_state(meta_path=[mock]): - module = importlib.import_module(name) - self.assertEqual(module.__name__, name) - - def test_shallow_relative_package_import(self): - # Test importing a module from a package through a relative import. - pkg_name = 'pkg' - pkg_long_name = '{0}.__init__'.format(pkg_name) - module_name = 'mod' - absolute_name = '{0}.{1}'.format(pkg_name, module_name) - relative_name = '.{0}'.format(module_name) - with util.mock_modules(pkg_long_name, absolute_name) as mock: - with util.import_state(meta_path=[mock]): - importlib.import_module(pkg_name) - module = importlib.import_module(relative_name, pkg_name) - self.assertEqual(module.__name__, absolute_name) - - def test_deep_relative_package_import(self): - modules = ['a.__init__', 'a.b.__init__', 'a.c'] - with util.mock_modules(*modules) as mock: - with util.import_state(meta_path=[mock]): - importlib.import_module('a') - importlib.import_module('a.b') - module = importlib.import_module('..c', 'a.b') - self.assertEqual(module.__name__, 'a.c') - - def test_absolute_import_with_package(self): - # Test importing a module from a package with an absolute name with - # the 'package' argument given. - pkg_name = 'pkg' - pkg_long_name = '{0}.__init__'.format(pkg_name) - name = '{0}.mod'.format(pkg_name) - with util.mock_modules(pkg_long_name, name) as mock: - with util.import_state(meta_path=[mock]): - importlib.import_module(pkg_name) - module = importlib.import_module(name, pkg_name) - self.assertEqual(module.__name__, name) - - def test_relative_import_wo_package(self): - # Relative imports cannot happen without the 'package' argument being - # set. - with self.assertRaises(TypeError): - importlib.import_module('.support') - - - def test_loaded_once(self): - # Issue #13591: Modules should only be loaded once when - # initializing the parent package attempts to import the - # module currently being imported. - b_load_count = 0 - def load_a(): - importlib.import_module('a.b') - def load_b(): - nonlocal b_load_count - b_load_count += 1 - code = {'a': load_a, 'a.b': load_b} - modules = ['a.__init__', 'a.b'] - with util.mock_modules(*modules, module_code=code) as mock: - with util.import_state(meta_path=[mock]): - 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. - - -class FrozenImportlibTests(unittest.TestCase): - - def test_no_frozen_importlib(self): - # Should be able to import w/o _frozen_importlib being defined. - module = support.import_fresh_module('importlib', blocked=['_frozen_importlib']) - self.assertFalse(isinstance(module.__loader__, - machinery.FrozenImporter)) - - -def test_main(): - from test.support import run_unittest - run_unittest(ImportModuleTests, - FindLoaderTests, - InvalidateCacheTests, - FrozenImportlibTests) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/test_locks.py b/Lib/importlib/test/test_locks.py deleted file mode 100644 index d36b71e..0000000 --- a/Lib/importlib/test/test_locks.py +++ /dev/null @@ -1,115 +0,0 @@ -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.assertIsNone(wr()) - - def test_all_locks(self): - support.gc_collect() - self.assertEqual(0, len(_bootstrap._module_locks), _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 deleted file mode 100644 index efc8977..0000000 --- a/Lib/importlib/test/test_util.py +++ /dev/null @@ -1,208 +0,0 @@ -from importlib import util -from . import util as test_util -import imp -import sys -import types -import unittest - - -class ModuleForLoaderTests(unittest.TestCase): - - """Tests for importlib.util.module_for_loader.""" - - def return_module(self, name): - fxn = util.module_for_loader(lambda self, module: module) - return fxn(self, name) - - def raise_exception(self, name): - def to_wrap(self, module): - raise ImportError - fxn = util.module_for_loader(to_wrap) - try: - fxn(self, name) - except ImportError: - pass - - def test_new_module(self): - # Test that when no module exists in sys.modules a new module is - # created. - module_name = 'a.b.c' - with test_util.uncache(module_name): - module = self.return_module(module_name) - self.assertIn(module_name, sys.modules) - self.assertIsInstance(module, types.ModuleType) - self.assertEqual(module.__name__, module_name) - - def test_reload(self): - # Test that a module is reused if already in sys.modules. - name = 'a.b.c' - module = imp.new_module('a.b.c') - with test_util.uncache(name): - sys.modules[name] = module - returned_module = self.return_module(name) - self.assertIs(returned_module, sys.modules[name]) - - def test_new_module_failure(self): - # Test that a module is removed from sys.modules if added but an - # exception is raised. - name = 'a.b.c' - with test_util.uncache(name): - self.raise_exception(name) - self.assertNotIn(name, sys.modules) - - def test_reload_failure(self): - # Test that a failure on reload leaves the module in-place. - name = 'a.b.c' - module = imp.new_module(name) - with test_util.uncache(name): - sys.modules[name] = module - 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.assertIs(given, 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') - - 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): - """Verify the module has the expected value for __package__ after - passing through set_package.""" - fxn = lambda: module - wrapped = util.set_package(fxn) - wrapped() - self.assertTrue(hasattr(module, '__package__')) - self.assertEqual(expect, module.__package__) - - def test_top_level(self): - # __package__ should be set to the empty string if a top-level module. - # Implicitly tests when package is set to None. - module = imp.new_module('module') - module.__package__ = None - self.verify(module, '') - - def test_package(self): - # Test setting __package__ for a package. - module = imp.new_module('pkg') - module.__path__ = [''] - module.__package__ = None - self.verify(module, 'pkg') - - def test_submodule(self): - # Test __package__ for a module in a package. - module = imp.new_module('pkg.mod') - module.__package__ = None - self.verify(module, 'pkg') - - def test_setting_if_missing(self): - # __package__ should be set if it is missing. - module = imp.new_module('mod') - if hasattr(module, '__package__'): - delattr(module, '__package__') - self.verify(module, '') - - def test_leaving_alone(self): - # If __package__ is set and not None then leave it alone. - for value in (True, False): - module = imp.new_module('mod') - 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, - ResolveNameTests - ) - - -if __name__ == '__main__': - test_main() diff --git a/Lib/importlib/test/util.py b/Lib/importlib/test/util.py deleted file mode 100644 index ef32f7d..0000000 --- a/Lib/importlib/test/util.py +++ /dev/null @@ -1,140 +0,0 @@ -from contextlib import contextmanager -import imp -import os.path -from test import support -import unittest -import sys - - -CASE_INSENSITIVE_FS = True -# Windows is the only OS that is *always* case-insensitive -# (OS X *can* be case-sensitive). -if sys.platform not in ('win32', 'cygwin'): - changed_name = __file__.upper() - if changed_name == __file__: - changed_name = __file__.lower() - if not os.path.exists(changed_name): - CASE_INSENSITIVE_FS = False - - -def case_insensitive_tests(test): - """Class decorator that nullifies tests requiring a case-insensitive - file system.""" - return unittest.skipIf(not CASE_INSENSITIVE_FS, - "requires a case-insensitive filesystem")(test) - - -@contextmanager -def uncache(*names): - """Uncache a module from sys.modules. - - A basic sanity check is performed to prevent uncaching modules that either - cannot/shouldn't be uncached. - - """ - for name in names: - if name in ('sys', 'marshal', 'imp'): - raise ValueError( - "cannot uncache {0}".format(name)) - try: - del sys.modules[name] - except KeyError: - pass - try: - yield - finally: - for name in names: - try: - del sys.modules[name] - except KeyError: - pass - -@contextmanager -def import_state(**kwargs): - """Context manager to manage the various importers and stored state in the - sys module. - - The 'modules' attribute is not supported as the interpreter state stores a - pointer to the dict that the interpreter uses internally; - reassigning to sys.modules does not have the desired effect. - - """ - originals = {} - try: - for attr, default in (('meta_path', []), ('path', []), - ('path_hooks', []), - ('path_importer_cache', {})): - originals[attr] = getattr(sys, attr) - if attr in kwargs: - new_value = kwargs[attr] - del kwargs[attr] - else: - new_value = default - setattr(sys, attr, new_value) - if len(kwargs): - raise ValueError( - 'unrecognized arguments: {0}'.format(kwargs.keys())) - yield - finally: - for attr, value in originals.items(): - setattr(sys, attr, value) - - -class mock_modules: - - """A mock importer/loader.""" - - def __init__(self, *names, module_code={}): - self.modules = {} - self.module_code = {} - for name in names: - if not name.endswith('.__init__'): - import_name = name - else: - import_name = name[:-len('.__init__')] - if '.' not in name: - package = None - elif import_name == name: - package = name.rsplit('.', 1)[0] - else: - package = import_name - module = imp.new_module(import_name) - module.__loader__ = self - module.__file__ = '' - module.__package__ = package - module.attr = name - if import_name != name: - module.__path__ = [''] - self.modules[import_name] = module - if import_name in module_code: - self.module_code[import_name] = module_code[import_name] - - def __getitem__(self, name): - return self.modules[name] - - def find_module(self, fullname, path=None): - if fullname not in self.modules: - return None - else: - return self - - def load_module(self, fullname): - if fullname not in self.modules: - raise ImportError - else: - sys.modules[fullname] = self.modules[fullname] - if fullname in self.module_code: - try: - self.module_code[fullname]() - except Exception: - del sys.modules[fullname] - raise - return self.modules[fullname] - - def __enter__(self): - self._uncache = uncache(*self.modules.keys()) - self._uncache.__enter__() - return self - - def __exit__(self, *exc_info): - self._uncache.__exit__(None, None, None) diff --git a/Lib/test/test_importlib.py b/Lib/test/test_importlib.py deleted file mode 100644 index 6ed0585..0000000 --- a/Lib/test/test_importlib.py +++ /dev/null @@ -1,5 +0,0 @@ -from importlib.test.__main__ import test_main - - -if __name__ == '__main__': - test_main() diff --git a/Lib/test/test_importlib/__init__.py b/Lib/test/test_importlib/__init__.py new file mode 100644 index 0000000..502eb7d --- /dev/null +++ b/Lib/test/test_importlib/__init__.py @@ -0,0 +1,33 @@ +import os +import sys +from .. import support +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 + + +def test_main(): + start_dir = os.path.dirname(__file__) + top_dir = os.path.dirname(os.path.dirname(start_dir)) + test_loader = unittest.TestLoader() + support.run_unittest(test_loader.discover(start_dir, top_level_dir=top_dir)) diff --git a/Lib/test/test_importlib/__main__.py b/Lib/test/test_importlib/__main__.py new file mode 100644 index 0000000..c397128 --- /dev/null +++ b/Lib/test/test_importlib/__main__.py @@ -0,0 +1,20 @@ +"""Run importlib's test suite. + +Specifying the ``--builtin`` flag will run tests, where applicable, with +builtins.__import__ instead of importlib.__import__. + +""" +from . import test_main + + +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/test/test_importlib/abc.py b/Lib/test/test_importlib/abc.py new file mode 100644 index 0000000..2c17ac3 --- /dev/null +++ b/Lib/test/test_importlib/abc.py @@ -0,0 +1,99 @@ +import abc +import unittest + + +class FinderTests(unittest.TestCase, metaclass=abc.ABCMeta): + + """Basic tests for a finder to pass.""" + + @abc.abstractmethod + def test_module(self): + # Test importing a top-level module. + pass + + @abc.abstractmethod + def test_package(self): + # Test importing a package. + pass + + @abc.abstractmethod + def test_module_in_package(self): + # Test importing a module contained within a package. + # A value for 'path' should be used if for a meta_path finder. + pass + + @abc.abstractmethod + def test_package_in_package(self): + # Test importing a subpackage. + # A value for 'path' should be used if for a meta_path finder. + pass + + @abc.abstractmethod + def test_package_over_module(self): + # Test that packages are chosen over modules. + pass + + @abc.abstractmethod + def test_failure(self): + # Test trying to find a module that cannot be handled. + pass + + +class LoaderTests(unittest.TestCase, metaclass=abc.ABCMeta): + + @abc.abstractmethod + def test_module(self): + """A module should load without issue. + + After the loader returns the module should be in sys.modules. + + Attributes to verify: + + * __file__ + * __loader__ + * __name__ + * No __path__ + + """ + pass + + @abc.abstractmethod + def test_package(self): + """Loading a package should work. + + After the loader returns the module should be in sys.modules. + + Attributes to verify: + + * __name__ + * __file__ + * __package__ + * __path__ + * __loader__ + + """ + pass + + @abc.abstractmethod + def test_lacking_parent(self): + """A loader should not be dependent on it's parent package being + imported.""" + pass + + @abc.abstractmethod + def test_module_reuse(self): + """If a module is already in sys.modules, it should be reused.""" + pass + + @abc.abstractmethod + def test_state_after_failure(self): + """If a module is already in sys.modules and a reload fails + (e.g. a SyntaxError), the module should be in the state it was before + the reload began.""" + pass + + @abc.abstractmethod + def test_unloadable(self): + """Test ImportError is raised when the loader is asked to load a module + it can't.""" + pass diff --git a/Lib/test/test_importlib/benchmark.py b/Lib/test/test_importlib/benchmark.py new file mode 100644 index 0000000..183e818 --- /dev/null +++ b/Lib/test/test_importlib/benchmark.py @@ -0,0 +1,252 @@ +"""Benchmark some basic import use-cases. + +The assumption is made that this benchmark is run in a fresh interpreter and +thus has no external changes made to import-related attributes in sys. + +""" +from . import util +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 + + +def bench(name, cleanup=lambda: None, *, seconds=1, repeat=3): + """Bench the given statement as many times as necessary until total + executions take one second.""" + stmt = "__import__({!r})".format(name) + timer = timeit.Timer(stmt) + for x in range(repeat): + total_time = 0 + count = 0 + while total_time < seconds: + try: + total_time += timer.timeit(1) + finally: + cleanup() + count += 1 + else: + # One execution too far + if total_time > seconds: + count -= 1 + yield count // seconds + +def from_cache(seconds, repeat): + """sys.modules""" + name = '' + module = imp.new_module(name) + module.__file__ = '' + module.__package__ = '' + with util.uncache(name): + sys.modules[name] = module + for result in bench(name, repeat=repeat, seconds=seconds): + yield result + + +def builtin_mod(seconds, repeat): + """Built-in module""" + name = 'errno' + if name in sys.modules: + del sys.modules[name] + # Relying on built-in importer being implicit. + for result in bench(name, lambda: sys.modules.pop(name), repeat=repeat, + seconds=seconds): + yield result + + +def source_wo_bytecode(seconds, repeat): + """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 + 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: 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])) + for result in bench(name, cleanup, repeat=repeat, seconds=seconds): + assert not os.path.exists(imp.cache_from_source(mapping[name])) + 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): + """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, + 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 + +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_writing_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' + '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() + results = [] + for result in benchmark(seconds=seconds, repeat=repeat): + results.append(result) + print(result, end=' ') + 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 argparse + + parser = argparse.ArgumentParser() + parser.add_argument('-b', '--builtin', dest='builtin', action='store_true', + default=False, help="use the built-in __import__") + 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_, options) diff --git a/Lib/test/test_importlib/builtin/__init__.py b/Lib/test/test_importlib/builtin/__init__.py new file mode 100644 index 0000000..15c0ade --- /dev/null +++ b/Lib/test/test_importlib/builtin/__init__.py @@ -0,0 +1,12 @@ +from .. import test_suite +import os + + +def test_suite(): + directory = os.path.dirname(__file__) + return test_suite('importlib.test.builtin', directory) + + +if __name__ == '__main__': + from test.support import run_unittest + run_unittest(test_suite()) diff --git a/Lib/test/test_importlib/builtin/test_finder.py b/Lib/test/test_importlib/builtin/test_finder.py new file mode 100644 index 0000000..146538d --- /dev/null +++ b/Lib/test/test_importlib/builtin/test_finder.py @@ -0,0 +1,55 @@ +from importlib import machinery +from .. import abc +from .. import util +from . import util as builtin_util + +import sys +import unittest + +class FinderTests(abc.FinderTests): + + """Test find_module() for built-in modules.""" + + def test_module(self): + # Common case. + with util.uncache(builtin_util.NAME): + found = machinery.BuiltinImporter.find_module(builtin_util.NAME) + self.assertTrue(found) + + def test_package(self): + # Built-in modules cannot be a package. + pass + + def test_module_in_package(self): + # Built-in modules cannobt be in a package. + pass + + def test_package_in_package(self): + # Built-in modules cannot be a package. + pass + + def test_package_over_module(self): + # Built-in modules cannot be a package. + pass + + def test_failure(self): + assert 'importlib' not in sys.builtin_module_names + loader = machinery.BuiltinImporter.find_module('importlib') + self.assertIsNone(loader) + + def test_ignore_path(self): + # The value for 'path' should always trigger a failed import. + with util.uncache(builtin_util.NAME): + loader = machinery.BuiltinImporter.find_module(builtin_util.NAME, + ['pkg']) + self.assertIsNone(loader) + + + +def test_main(): + from test.support import run_unittest + run_unittest(FinderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/builtin/test_loader.py b/Lib/test/test_importlib/builtin/test_loader.py new file mode 100644 index 0000000..8e186e7 --- /dev/null +++ b/Lib/test/test_importlib/builtin/test_loader.py @@ -0,0 +1,105 @@ +import importlib +from importlib import machinery +from .. import abc +from .. import util +from . import util as builtin_util + +import sys +import types +import unittest + + +class LoaderTests(abc.LoaderTests): + + """Test load_module() for built-in modules.""" + + verification = {'__name__': 'errno', '__package__': '', + '__loader__': machinery.BuiltinImporter} + + def verify(self, module): + """Verify that the module matches against what it should have.""" + self.assertIsInstance(module, types.ModuleType) + for attr, value in self.verification.items(): + self.assertEqual(getattr(module, attr), value) + self.assertIn(module.__name__, sys.modules) + + load_module = staticmethod(lambda name: + machinery.BuiltinImporter.load_module(name)) + + def test_module(self): + # Common case. + with util.uncache(builtin_util.NAME): + module = self.load_module(builtin_util.NAME) + self.verify(module) + + def test_package(self): + # Built-in modules cannot be a package. + pass + + def test_lacking_parent(self): + # Built-in modules cannot be a package. + pass + + def test_state_after_failure(self): + # Not way to force an imoprt failure. + pass + + def test_module_reuse(self): + # Test that the same module is used in a reload. + with util.uncache(builtin_util.NAME): + module1 = self.load_module(builtin_util.NAME) + module2 = self.load_module(builtin_util.NAME) + self.assertIs(module1, module2) + + def test_unloadable(self): + name = 'dssdsdfff' + assert name not in sys.builtin_module_names + 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) as cm: + self.load_module('importlib') + self.assertEqual(cm.exception.name, 'importlib') + + +class InspectLoaderTests(unittest.TestCase): + + """Tests for InspectLoader methods for BuiltinImporter.""" + + def test_get_code(self): + # There is no code object. + result = machinery.BuiltinImporter.get_code(builtin_util.NAME) + self.assertIsNone(result) + + def test_get_source(self): + # There is no source. + result = machinery.BuiltinImporter.get_source(builtin_util.NAME) + self.assertIsNone(result) + + def test_is_package(self): + # Cannot be a package. + result = machinery.BuiltinImporter.is_package(builtin_util.NAME) + self.assertTrue(not result) + + def test_not_builtin(self): + # 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) as cm: + method(builtin_util.BAD_NAME) + self.assertRaises(builtin_util.BAD_NAME) + + + +def test_main(): + from test.support import run_unittest + run_unittest(LoaderTests, InspectLoaderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/builtin/util.py b/Lib/test/test_importlib/builtin/util.py new file mode 100644 index 0000000..5704699 --- /dev/null +++ b/Lib/test/test_importlib/builtin/util.py @@ -0,0 +1,7 @@ +import sys + +assert 'errno' in sys.builtin_module_names +NAME = 'errno' + +assert 'importlib' not in sys.builtin_module_names +BAD_NAME = 'importlib' diff --git a/Lib/test/test_importlib/extension/__init__.py b/Lib/test/test_importlib/extension/__init__.py new file mode 100644 index 0000000..c033923 --- /dev/null +++ b/Lib/test/test_importlib/extension/__init__.py @@ -0,0 +1,13 @@ +from .. import test_suite +import os.path +import unittest + + +def test_suite(): + directory = os.path.dirname(__file__) + return test_suite('importlib.test.extension', directory) + + +if __name__ == '__main__': + from test.support import run_unittest + run_unittest(test_suite()) diff --git a/Lib/test/test_importlib/extension/test_case_sensitivity.py b/Lib/test/test_importlib/extension/test_case_sensitivity.py new file mode 100644 index 0000000..bdc21e7 --- /dev/null +++ b/Lib/test/test_importlib/extension/test_case_sensitivity.py @@ -0,0 +1,51 @@ +import imp +import sys +from test import support +import unittest +from importlib import _bootstrap +from .. import util +from . import util as ext_util + + +@util.case_insensitive_tests +class ExtensionModuleCaseSensitivityTest(unittest.TestCase): + + def find_module(self): + good_name = ext_util.NAME + bad_name = good_name.upper() + assert good_name != bad_name + 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')) + + + + +def test_main(): + if ext_util.FILENAME is None: + return + support.run_unittest(ExtensionModuleCaseSensitivityTest) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py new file mode 100644 index 0000000..1c60292 --- /dev/null +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -0,0 +1,50 @@ +from importlib import _bootstrap +from .. import abc +from . import util + +import imp +import unittest + +class FinderTests(abc.FinderTests): + + """Test the finder for extension modules.""" + + def find_module(self, fullname): + importer = _bootstrap.FileFinder(util.PATH, + (_bootstrap.ExtensionFileLoader, + imp.extension_suffixes(), + False)) + return importer.find_module(fullname) + + def test_module(self): + self.assertTrue(self.find_module(util.NAME)) + + def test_package(self): + # Extension modules cannot be an __init__ for a package. + pass + + def test_module_in_package(self): + # No extension module in a package available for testing. + pass + + def test_package_in_package(self): + # Extension modules cannot be an __init__ for a package. + pass + + def test_package_over_module(self): + # Extension modules cannot be an __init__ for a package. + pass + + def test_failure(self): + self.assertIsNone(self.find_module('asdfjkl;')) + + # XXX Raise an exception if someone tries to use the 'path' argument? + + +def test_main(): + from test.support import run_unittest + run_unittest(FinderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/extension/test_loader.py b/Lib/test/test_importlib/extension/test_loader.py new file mode 100644 index 0000000..917843f --- /dev/null +++ b/Lib/test/test_importlib/extension/test_loader.py @@ -0,0 +1,71 @@ +from importlib import machinery +from . import util as ext_util +from .. import abc +from .. import util + +import sys +import unittest + + +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): + 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): + module = self.load_module(ext_util.NAME) + for attr, value in [('__name__', ext_util.NAME), + ('__file__', ext_util.FILEPATH), + ('__package__', '')]: + self.assertEqual(getattr(module, attr), value) + self.assertIn(ext_util.NAME, sys.modules) + self.assertIsInstance(module.__loader__, + machinery.ExtensionFileLoader) + + def test_package(self): + # Extensions are not found in packages. + pass + + def test_lacking_parent(self): + # Extensions are not found in packages. + pass + + def test_module_reuse(self): + with util.uncache(ext_util.NAME): + module1 = self.load_module(ext_util.NAME) + module2 = self.load_module(ext_util.NAME) + self.assertIs(module1, module2) + + def test_state_after_failure(self): + # No easy way to trigger a failure after a successful import. + pass + + def test_unloadable(self): + name = 'asdfjkl;' + with self.assertRaises(ImportError) as cm: + self.load_module(name) + self.assertEqual(cm.exception.name, name) + + +def test_main(): + from test.support import run_unittest + run_unittest(LoaderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/extension/test_path_hook.py b/Lib/test/test_importlib/extension/test_path_hook.py new file mode 100644 index 0000000..129e6e2 --- /dev/null +++ b/Lib/test/test_importlib/extension/test_path_hook.py @@ -0,0 +1,32 @@ +from importlib import _bootstrap +from . import util + +import collections +import imp +import sys +import unittest + + +class PathHookTests(unittest.TestCase): + + """Test the path hook for extension modules.""" + # XXX Should it only succeed for pre-existing directories? + # XXX Should it only work for directories containing an extension module? + + def hook(self, 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 + # exists. + self.assertTrue(hasattr(self.hook(util.PATH), 'find_module')) + + +def test_main(): + from test.support import run_unittest + run_unittest(PathHookTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/extension/util.py b/Lib/test/test_importlib/extension/util.py new file mode 100644 index 0000000..a266dd9 --- /dev/null +++ b/Lib/test/test_importlib/extension/util.py @@ -0,0 +1,20 @@ +import imp +from importlib import machinery +import os +import sys + +PATH = None +EXT = None +FILENAME = None +NAME = '_testcapi' +try: + for PATH in sys.path: + for EXT in machinery.EXTENSION_SUFFIXES: + FILENAME = NAME + EXT + FILEPATH = os.path.join(PATH, FILENAME) + if os.path.exists(os.path.join(PATH, FILENAME)): + raise StopIteration + else: + PATH = EXT = FILENAME = FILEPATH = None +except StopIteration: + pass diff --git a/Lib/test/test_importlib/frozen/__init__.py b/Lib/test/test_importlib/frozen/__init__.py new file mode 100644 index 0000000..9ef103b --- /dev/null +++ b/Lib/test/test_importlib/frozen/__init__.py @@ -0,0 +1,13 @@ +from .. import test_suite +import os.path +import unittest + + +def test_suite(): + directory = os.path.dirname(__file__) + return test_suite('importlib.test.frozen', directory) + + +if __name__ == '__main__': + from test.support import run_unittest + run_unittest(test_suite()) diff --git a/Lib/test/test_importlib/frozen/test_finder.py b/Lib/test/test_importlib/frozen/test_finder.py new file mode 100644 index 0000000..fa0c2a0 --- /dev/null +++ b/Lib/test/test_importlib/frozen/test_finder.py @@ -0,0 +1,47 @@ +from importlib import machinery +from .. import abc + +import unittest + + +class FinderTests(abc.FinderTests): + + """Test finding frozen modules.""" + + def find(self, name, path=None): + finder = machinery.FrozenImporter + return finder.find_module(name, path) + + def test_module(self): + name = '__hello__' + loader = self.find(name) + self.assertTrue(hasattr(loader, 'load_module')) + + def test_package(self): + loader = self.find('__phello__') + self.assertTrue(hasattr(loader, 'load_module')) + + def test_module_in_package(self): + loader = self.find('__phello__.spam', ['__phello__']) + self.assertTrue(hasattr(loader, 'load_module')) + + def test_package_in_package(self): + # No frozen package within another package to test with. + pass + + def test_package_over_module(self): + # No easy way to test. + pass + + def test_failure(self): + loader = self.find('') + self.assertIsNone(loader) + + +def test_main(): + from test.support import run_unittest + run_unittest(FinderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py new file mode 100644 index 0000000..4b8ec15 --- /dev/null +++ b/Lib/test/test_importlib/frozen/test_loader.py @@ -0,0 +1,121 @@ +from importlib import machinery +import imp +import unittest +from .. import abc +from .. import util +from test.support import captured_stdout + +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__', + '__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__', + '__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', + '__package__': '__phello__', + '__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: + module1 = machinery.FrozenImporter.load_module('__hello__') + module2 = machinery.FrozenImporter.load_module('__hello__') + self.assertIs(module1, module2) + 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), + "") + + 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) as cm: + machinery.FrozenImporter.load_module('_not_real') + self.assertEqual(cm.exception.name, '_not_real') + + +class InspectLoaderTests(unittest.TestCase): + + """Tests for the InspectLoader methods for FrozenImporter.""" + + def test_get_code(self): + # Make sure that the code object is good. + name = '__hello__' + with captured_stdout() as stdout: + code = machinery.FrozenImporter.get_code(name) + mod = imp.new_module(name) + exec(code, mod.__dict__) + self.assertTrue(hasattr(mod, 'initialized')) + self.assertEqual(stdout.getvalue(), 'Hello world!\n') + + def test_get_source(self): + # Should always return None. + result = machinery.FrozenImporter.get_source('__hello__') + self.assertIsNone(result) + + def test_is_package(self): + # Should be able to tell what is a package. + test_for = (('__hello__', False), ('__phello__', True), + ('__phello__.spam', False)) + for name, is_package in test_for: + result = machinery.FrozenImporter.is_package(name) + self.assertEqual(bool(result), is_package) + + def test_failure(self): + # 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) as cm: + method('importlib') + self.assertEqual(cm.exception.name, 'importlib') + + +def test_main(): + from test.support import run_unittest + run_unittest(LoaderTests, InspectLoaderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/__init__.py b/Lib/test/test_importlib/import_/__init__.py new file mode 100644 index 0000000..366e531 --- /dev/null +++ b/Lib/test/test_importlib/import_/__init__.py @@ -0,0 +1,13 @@ +from .. import test_suite +import os.path +import unittest + + +def test_suite(): + directory = os.path.dirname(__file__) + return test_suite('importlib.test.import_', directory) + + +if __name__ == '__main__': + from test.support import run_unittest + run_unittest(test_suite()) diff --git a/Lib/test/test_importlib/import_/test___package__.py b/Lib/test/test_importlib/import_/test___package__.py new file mode 100644 index 0000000..783cde1 --- /dev/null +++ b/Lib/test/test_importlib/import_/test___package__.py @@ -0,0 +1,119 @@ +"""PEP 366 ("Main module explicit relative imports") specifies the +semantics for the __package__ attribute on modules. This attribute is +used, when available, to detect which package a module belongs to (instead +of using the typical __path__/__name__ test). + +""" +import unittest +from .. import util +from . import util as import_util + + +class Using__package__(unittest.TestCase): + + """Use of __package__ supercedes the use of __name__/__path__ to calculate + what package a module belongs to. The basic algorithm is [__package__]:: + + def resolve_name(name, package, level): + level -= 1 + base = package.rsplit('.', level)[0] + return '{0}.{1}'.format(base, name) + + But since there is no guarantee that __package__ has been set (or not been + set to None [None]), there has to be a way to calculate the attribute's value + [__name__]:: + + def calc_package(caller_name, has___path__): + if has__path__: + return caller_name + else: + return caller_name.rsplit('.', 1)[0] + + Then the normal algorithm for relative name imports can proceed as if + __package__ had been set. + + """ + + def test_using___package__(self): + # [__package__] + with util.mock_modules('pkg.__init__', 'pkg.fake') as importer: + with util.import_state(meta_path=[importer]): + import_util.import_('pkg.fake') + module = import_util.import_('', + globals={'__package__': 'pkg.fake'}, + fromlist=['attr'], level=2) + self.assertEqual(module.__name__, 'pkg') + + def test_using___name__(self, package_as_None=False): + # [__name__] + globals_ = {'__name__': 'pkg.fake', '__path__': []} + if package_as_None: + globals_['__package__'] = None + with util.mock_modules('pkg.__init__', 'pkg.fake') as importer: + with util.import_state(meta_path=[importer]): + import_util.import_('pkg.fake') + module = import_util.import_('', globals= globals_, + fromlist=['attr'], level=2) + self.assertEqual(module.__name__, 'pkg') + + def test_None_as___package__(self): + # [None] + self.test_using___name__(package_as_None=True) + + def test_bad__package__(self): + globals = {'__package__': ''} + with self.assertRaises(SystemError): + import_util.import_('', globals, {}, ['relimport'], 1) + + def test_bunk__package__(self): + globals = {'__package__': 42} + with self.assertRaises(TypeError): + import_util.import_('', globals, {}, ['relimport'], 1) + + +@import_util.importlib_only +class Setting__package__(unittest.TestCase): + + """Because __package__ is a new feature, it is not always set by a loader. + Import will set it as needed to help with the transition to relying on + __package__. + + For a top-level module, __package__ is set to None [top-level]. For a + package __name__ is used for __package__ [package]. For submodules the + value is __name__.rsplit('.', 1)[0] [submodule]. + + """ + + # [top-level] + def test_top_level(self): + with util.mock_modules('top_level') as mock: + with util.import_state(meta_path=[mock]): + del mock['top_level'].__package__ + module = import_util.import_('top_level') + self.assertEqual(module.__package__, '') + + # [package] + def test_package(self): + with util.mock_modules('pkg.__init__') as mock: + with util.import_state(meta_path=[mock]): + del mock['pkg'].__package__ + module = import_util.import_('pkg') + self.assertEqual(module.__package__, 'pkg') + + # [submodule] + def test_submodule(self): + with util.mock_modules('pkg.__init__', 'pkg.mod') as mock: + with util.import_state(meta_path=[mock]): + del mock['pkg.mod'].__package__ + pkg = import_util.import_('pkg.mod') + module = getattr(pkg, 'mod') + self.assertEqual(module.__package__, 'pkg') + + +def test_main(): + from test.support import run_unittest + run_unittest(Using__package__, Setting__package__) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_api.py b/Lib/test/test_importlib/import_/test_api.py new file mode 100644 index 0000000..2fa1f90 --- /dev/null +++ b/Lib/test/test_importlib/import_/test_api.py @@ -0,0 +1,29 @@ +from . import util +import unittest + + +class APITest(unittest.TestCase): + + """Test API-specific details for __import__ (e.g. raising the right + exception when passing in an int for the module name).""" + + def test_name_requires_rparition(self): + # Raise TypeError if a non-string is passed in for the module name. + 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 + run_unittest(APITest) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_caching.py b/Lib/test/test_importlib/import_/test_caching.py new file mode 100644 index 0000000..bf68027 --- /dev/null +++ b/Lib/test/test_importlib/import_/test_caching.py @@ -0,0 +1,88 @@ +"""Test that sys.modules is used properly by import.""" +from .. import util +from . import util as import_util +import sys +from types import MethodType +import unittest + + +class UseCache(unittest.TestCase): + + """When it comes to sys.modules, import prefers it over anything else. + + Once a name has been resolved, sys.modules is checked to see if it contains + the module desired. If so, then it is returned [use cache]. If it is not + found, then the proper steps are taken to perform the import, but + sys.modules is still used to return the imported module (e.g., not what a + loader returns) [from cache on return]. This also applies to imports of + things contained within a package and thus get assigned as an attribute + [from cache to attribute] or pulled in thanks to a fromlist import + [from cache for fromlist]. But if sys.modules contains None then + ImportError is raised [None in cache]. + + """ + def test_using_cache(self): + # [use cache] + module_to_use = "some module found!" + with util.uncache(module_to_use): + sys.modules['some_module'] = module_to_use + module = import_util.import_('some_module') + self.assertEqual(id(module_to_use), id(module)) + + def test_None_in_cache(self): + #[None in cache] + name = 'using_None' + with util.uncache(name): + sys.modules[name] = None + 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) + original_load = mock.load_module + def load_module(self, fullname): + original_load(fullname) + return return_ + mock.load_module = MethodType(load_module, mock) + return mock + + # __import__ inconsistent between loaders and built-in import when it comes + # to when to use the module in sys.modules and when not to. + @import_util.importlib_only + def test_using_cache_after_loader(self): + # [from cache on return] + with self.create_mock('module') as mock: + with util.import_state(meta_path=[mock]): + module = import_util.import_('module') + self.assertEqual(id(module), id(sys.modules['module'])) + + # See test_using_cache_after_loader() for reasoning. + @import_util.importlib_only + def test_using_cache_for_assigning_to_attribute(self): + # [from cache to attribute] + with self.create_mock('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('pkg.module') + self.assertTrue(hasattr(module, 'module')) + self.assertEqual(id(module.module), + id(sys.modules['pkg.module'])) + + # See test_using_cache_after_loader() for reasoning. + @import_util.importlib_only + def test_using_cache_for_fromlist(self): + # [from cache for fromlist] + with self.create_mock('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('pkg', fromlist=['module']) + self.assertTrue(hasattr(module, 'module')) + self.assertEqual(id(module.module), + id(sys.modules['pkg.module'])) + + +def test_main(): + from test.support import run_unittest + run_unittest(UseCache) + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_fromlist.py b/Lib/test/test_importlib/import_/test_fromlist.py new file mode 100644 index 0000000..281961d --- /dev/null +++ b/Lib/test/test_importlib/import_/test_fromlist.py @@ -0,0 +1,114 @@ +"""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): + + """The use of fromlist influences what import returns. + + If direct ``import ...`` statement is used, the root module or package is + returned [import return]. But if fromlist is set, then the specified module + is actually returned (whether it is a relative import or not) + [from return]. + + """ + + def test_return_from_import(self): + # [import return] + with util.mock_modules('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('pkg.module') + self.assertEqual(module.__name__, 'pkg') + + def test_return_from_from_import(self): + # [from return] + with util.mock_modules('pkg.__init__', 'pkg.module')as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('pkg.module', fromlist=['attr']) + self.assertEqual(module.__name__, 'pkg.module') + + +class HandlingFromlist(unittest.TestCase): + + """Using fromlist triggers different actions based on what is being asked + of it. + + If fromlist specifies an object on a module, nothing special happens + [object case]. This is even true if the object does not exist [bad object]. + + If a package is being imported, then what is listed in fromlist may be + treated as a module to be imported [module]. And this extends to what is + contained in __all__ when '*' is imported [using *]. And '*' does not need + to be the only name in the fromlist [using * with others]. + + """ + + def test_object(self): + # [object case] + with util.mock_modules('module') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('module', fromlist=['attr']) + self.assertEqual(module.__name__, 'module') + + def test_unexistent_object(self): + # [bad object] + with util.mock_modules('module') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('module', fromlist=['non_existent']) + self.assertEqual(module.__name__, 'module') + self.assertTrue(not hasattr(module, 'non_existent')) + + def test_module_from_package(self): + # [module] + with util.mock_modules('pkg.__init__', 'pkg.module') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('pkg', fromlist=['module']) + self.assertEqual(module.__name__, 'pkg') + self.assertTrue(hasattr(module, 'module')) + self.assertEqual(module.module.__name__, 'pkg.module') + + def test_empty_string(self): + with util.mock_modules('pkg.__init__', 'pkg.mod') as importer: + with util.import_state(meta_path=[importer]): + module = import_util.import_('pkg.mod', fromlist=['']) + self.assertEqual(module.__name__, 'pkg.mod') + + def basic_star_test(self, fromlist=['*']): + # [using *] + with util.mock_modules('pkg.__init__', 'pkg.module') as mock: + with util.import_state(meta_path=[mock]): + mock['pkg'].__all__ = ['module'] + module = import_util.import_('pkg', fromlist=fromlist) + self.assertEqual(module.__name__, 'pkg') + self.assertTrue(hasattr(module, 'module')) + self.assertEqual(module.module.__name__, 'pkg.module') + + def test_using_star(self): + # [using *] + self.basic_star_test() + + def test_fromlist_as_tuple(self): + self.basic_star_test(('*',)) + + def test_star_with_others(self): + # [using * with others] + context = util.mock_modules('pkg.__init__', 'pkg.module1', 'pkg.module2') + with context as mock: + with util.import_state(meta_path=[mock]): + mock['pkg'].__all__ = ['module1'] + module = import_util.import_('pkg', fromlist=['module2', '*']) + self.assertEqual(module.__name__, 'pkg') + self.assertTrue(hasattr(module, 'module1')) + self.assertTrue(hasattr(module, 'module2')) + self.assertEqual(module.module1.__name__, 'pkg.module1') + self.assertEqual(module.module2.__name__, 'pkg.module2') + + +def test_main(): + from test.support import run_unittest + run_unittest(ReturnValue, HandlingFromlist) + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_meta_path.py b/Lib/test/test_importlib/import_/test_meta_path.py new file mode 100644 index 0000000..4d85f80 --- /dev/null +++ b/Lib/test/test_importlib/import_/test_meta_path.py @@ -0,0 +1,115 @@ +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): + + """Calls to the importers on sys.meta_path happen in order that they are + specified in the sequence, starting with the first importer + [first called], and then continuing on down until one is found that doesn't + return None [continuing].""" + + + def test_first_called(self): + # [first called] + mod = 'top_level' + first = util.mock_modules(mod) + second = util.mock_modules(mod) + with util.mock_modules(mod) as first, util.mock_modules(mod) as second: + first.modules[mod] = 42 + second.modules[mod] = -13 + with util.import_state(meta_path=[first, second]): + self.assertEqual(import_util.import_(mod), 42) + + def test_continuing(self): + # [continuing] + mod_name = 'for_real' + with util.mock_modules('nonexistent') as first, \ + util.mock_modules(mod_name) as second: + first.find_module = lambda self, fullname, path=None: None + second.modules[mod_name] = 42 + 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): + + """If there is no __path__ entry on the parent module, then 'path' is None + [no path]. Otherwise, the value for __path__ is passed in for the 'path' + argument [path set].""" + + def log(self, fxn): + log = [] + def wrapper(self, *args, **kwargs): + log.append([args, kwargs]) + return fxn(*args, **kwargs) + return log, wrapper + + + def test_no_path(self): + # [no path] + mod_name = 'top_level' + assert '.' not in mod_name + with util.mock_modules(mod_name) as importer: + log, wrapped_call = self.log(importer.find_module) + importer.find_module = MethodType(wrapped_call, importer) + with util.import_state(meta_path=[importer]): + import_util.import_(mod_name) + assert len(log) == 1 + args = log[0][0] + kwargs = log[0][1] + # Assuming all arguments are positional. + self.assertEqual(len(args), 2) + self.assertEqual(len(kwargs), 0) + self.assertEqual(args[0], mod_name) + self.assertIsNone(args[1]) + + def test_with_path(self): + # [path set] + pkg_name = 'pkg' + mod_name = pkg_name + '.module' + path = [42] + assert '.' in mod_name + with util.mock_modules(pkg_name+'.__init__', mod_name) as importer: + importer.modules[pkg_name].__path__ = path + log, wrapped_call = self.log(importer.find_module) + importer.find_module = MethodType(wrapped_call, importer) + with util.import_state(meta_path=[importer]): + import_util.import_(mod_name) + assert len(log) == 2 + args = log[1][0] + kwargs = log[1][1] + # Assuming all arguments are positional. + self.assertTrue(not kwargs) + self.assertEqual(args[0], mod_name) + self.assertIs(args[1], path) + + + +def test_main(): + from test.support import run_unittest + run_unittest(CallingOrder, CallSignature) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_packages.py b/Lib/test/test_importlib/import_/test_packages.py new file mode 100644 index 0000000..bfa18dc --- /dev/null +++ b/Lib/test/test_importlib/import_/test_packages.py @@ -0,0 +1,112 @@ +from .. import util +from . import util as import_util +import sys +import unittest +import importlib +from test import support + + +class ParentModuleTests(unittest.TestCase): + + """Importing a submodule should import the parent modules.""" + + def test_import_parent(self): + with util.mock_modules('pkg.__init__', 'pkg.module') as mock: + with util.import_state(meta_path=[mock]): + module = import_util.import_('pkg.module') + self.assertIn('pkg', sys.modules) + + def test_bad_parent(self): + with util.mock_modules('pkg.module') as mock: + with util.import_state(meta_path=[mock]): + 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.assertNotIn('pkg', sys.modules) + self.assertIn('pkg.module', sys.modules) + with self.assertRaises(ZeroDivisionError): + import_util.import_('pkg.module') + self.assertNotIn('pkg', sys.modules) + self.assertIn('pkg.module', 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.assertNotIn('pkg', sys.modules) + with self.assertRaises((ZeroDivisionError, ImportError)): + import_util.import_('pkg.module') + self.assertNotIn('pkg', sys.modules) + # XXX False + #self.assertIn('pkg.module', 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.assertNotIn('pkg.subpkg', sys.modules) + with self.assertRaises((ZeroDivisionError, ImportError)): + import_util.import_('pkg.subpkg.module') + self.assertNotIn('pkg.subpkg', sys.modules) + # XXX False + #self.assertIn('pkg.subpkg.module', 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) 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(): + from test.support import run_unittest + run_unittest(ParentModuleTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py new file mode 100644 index 0000000..0c086ce --- /dev/null +++ b/Lib/test/test_importlib/import_/test_path.py @@ -0,0 +1,98 @@ +from importlib import _bootstrap +from importlib import machinery +from .. import util +from . import util as import_util +import imp +import os +import sys +import tempfile +from test import support +from types import MethodType +import unittest +import warnings + + +class FinderTests(unittest.TestCase): + + """Tests for PathFinder.""" + + def test_failure(self): + # Test None returned upon not finding a suitable finder. + module = '' + with util.import_state(): + self.assertIsNone(machinery.PathFinder.find_module(module)) + + def test_sys_path(self): + # Test that sys.path is used when 'path' is None. + # Implicitly tests that sys.path_importer_cache is used. + module = '' + path = '' + importer = util.mock_modules(module) + with util.import_state(path_importer_cache={path: importer}, + path=[path]): + loader = machinery.PathFinder.find_module(module) + self.assertIs(loader, importer) + + def test_path(self): + # Test that 'path' is used when set. + # Implicitly tests that sys.path_importer_cache is used. + module = '' + path = '' + importer = util.mock_modules(module) + with util.import_state(path_importer_cache={path: importer}): + loader = machinery.PathFinder.find_module(module, [path]) + self.assertIs(loader, importer) + + def test_empty_list(self): + # An empty list should not count as asking for sys.path. + module = 'module' + 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. + module = '' + path = '' + importer = util.mock_modules(module) + hook = import_util.mock_path_hook(path, importer=importer) + with util.import_state(path_hooks=[hook]): + loader = machinery.PathFinder.find_module(module, [path]) + self.assertIs(loader, importer) + self.assertIn(path, sys.path_importer_cache) + self.assertIs(sys.path_importer_cache[path], importer) + + 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 = '' + importer = util.mock_modules(module) + 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.assertIs(loader, importer) + self.assertIn(os.curdir, sys.path_importer_cache) + + +def test_main(): + from test.support import run_unittest + run_unittest(FinderTests) + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/test_relative_imports.py b/Lib/test/test_importlib/import_/test_relative_imports.py new file mode 100644 index 0000000..4569c26 --- /dev/null +++ b/Lib/test/test_importlib/import_/test_relative_imports.py @@ -0,0 +1,217 @@ +"""Test relative imports (PEP 328).""" +from .. import util +from . import util as import_util +import sys +import unittest + +class RelativeImports(unittest.TestCase): + + """PEP 328 introduced relative imports. This allows for imports to occur + from within a package without having to specify the actual package name. + + A simple example is to import another module within the same package + [module from module]:: + + # From pkg.mod1 with pkg.mod2 being a module. + from . import mod2 + + This also works for getting an attribute from a module that is specified + in a relative fashion [attr from module]:: + + # From pkg.mod1. + from .mod2 import attr + + But this is in no way restricted to working between modules; it works + from [package to module],:: + + # From pkg, importing pkg.module which is a module. + from . import module + + [module to package],:: + + # Pull attr from pkg, called from pkg.module which is a module. + from . import attr + + and [package to package]:: + + # From pkg.subpkg1 (both pkg.subpkg[1,2] are packages). + from .. import subpkg2 + + The number of dots used is in no way restricted [deep import]:: + + # Import pkg.attr from pkg.pkg1.pkg2.pkg3.pkg4.pkg5. + from ...... import attr + + To prevent someone from accessing code that is outside of a package, one + cannot reach the location containing the root package itself:: + + # From pkg.__init__ [too high from package] + from .. import top_level + + # From pkg.module [too high from module] + from .. import top_level + + Relative imports are the only type of import that allow for an empty + module name for an import [empty name]. + + """ + + def relative_import_test(self, create, globals_, callback): + """Abstract out boilerplace for setting up for an import test.""" + uncache_names = [] + for name in create: + if not name.endswith('.__init__'): + uncache_names.append(name) + else: + uncache_names.append(name[:-len('.__init__')]) + with util.mock_modules(*create) as importer: + with util.import_state(meta_path=[importer]): + for global_ in globals_: + with util.uncache(*uncache_names): + callback(global_) + + + def test_module_from_module(self): + # [module from module] + create = 'pkg.__init__', 'pkg.mod2' + globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.mod1'} + def callback(global_): + import_util.import_('pkg') # For __import__(). + module = import_util.import_('', global_, fromlist=['mod2'], level=1) + self.assertEqual(module.__name__, 'pkg') + self.assertTrue(hasattr(module, 'mod2')) + self.assertEqual(module.mod2.attr, 'pkg.mod2') + self.relative_import_test(create, globals_, callback) + + def test_attr_from_module(self): + # [attr from module] + create = 'pkg.__init__', 'pkg.mod2' + globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.mod1'} + def callback(global_): + import_util.import_('pkg') # For __import__(). + module = import_util.import_('mod2', global_, fromlist=['attr'], + level=1) + self.assertEqual(module.__name__, 'pkg.mod2') + self.assertEqual(module.attr, 'pkg.mod2') + self.relative_import_test(create, globals_, callback) + + def test_package_to_module(self): + # [package to module] + create = 'pkg.__init__', 'pkg.module' + globals_ = ({'__package__': 'pkg'}, + {'__name__': 'pkg', '__path__': ['blah']}) + def callback(global_): + import_util.import_('pkg') # For __import__(). + module = import_util.import_('', global_, fromlist=['module'], + level=1) + self.assertEqual(module.__name__, 'pkg') + self.assertTrue(hasattr(module, 'module')) + self.assertEqual(module.module.attr, 'pkg.module') + self.relative_import_test(create, globals_, callback) + + def test_module_to_package(self): + # [module to package] + create = 'pkg.__init__', 'pkg.module' + globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.module'} + def callback(global_): + import_util.import_('pkg') # For __import__(). + module = import_util.import_('', global_, fromlist=['attr'], level=1) + self.assertEqual(module.__name__, 'pkg') + self.relative_import_test(create, globals_, callback) + + def test_package_to_package(self): + # [package to package] + create = ('pkg.__init__', 'pkg.subpkg1.__init__', + 'pkg.subpkg2.__init__') + globals_ = ({'__package__': 'pkg.subpkg1'}, + {'__name__': 'pkg.subpkg1', '__path__': ['blah']}) + def callback(global_): + module = import_util.import_('', global_, fromlist=['subpkg2'], + level=2) + self.assertEqual(module.__name__, 'pkg') + self.assertTrue(hasattr(module, 'subpkg2')) + self.assertEqual(module.subpkg2.attr, 'pkg.subpkg2.__init__') + + def test_deep_import(self): + # [deep import] + create = ['pkg.__init__'] + for count in range(1,6): + create.append('{0}.pkg{1}.__init__'.format( + create[-1][:-len('.__init__')], count)) + globals_ = ({'__package__': 'pkg.pkg1.pkg2.pkg3.pkg4.pkg5'}, + {'__name__': 'pkg.pkg1.pkg2.pkg3.pkg4.pkg5', + '__path__': ['blah']}) + def callback(global_): + import_util.import_(globals_[0]['__package__']) + module = import_util.import_('', global_, fromlist=['attr'], level=6) + self.assertEqual(module.__name__, 'pkg') + self.relative_import_test(create, globals_, callback) + + def test_too_high_from_package(self): + # [too high from package] + create = ['top_level', 'pkg.__init__'] + globals_ = ({'__package__': 'pkg'}, + {'__name__': 'pkg', '__path__': ['blah']}) + def callback(global_): + import_util.import_('pkg') + with self.assertRaises(ValueError): + import_util.import_('', global_, fromlist=['top_level'], + level=2) + self.relative_import_test(create, globals_, callback) + + def test_too_high_from_module(self): + # [too high from module] + create = ['top_level', 'pkg.__init__', 'pkg.module'] + globals_ = {'__package__': 'pkg'}, {'__name__': 'pkg.module'} + def callback(global_): + import_util.import_('pkg') + with self.assertRaises(ValueError): + import_util.import_('', global_, fromlist=['top_level'], + level=2) + self.relative_import_test(create, globals_, callback) + + def test_empty_name_w_level_0(self): + # [empty name] + with self.assertRaises(ValueError): + import_util.import_('') + + def test_import_from_different_package(self): + # Test importing from a different package than the caller. + # in pkg.subpkg1.mod + # from ..subpkg2 import mod + create = ['__runpy_pkg__.__init__', + '__runpy_pkg__.__runpy_pkg__.__init__', + '__runpy_pkg__.uncle.__init__', + '__runpy_pkg__.uncle.cousin.__init__', + '__runpy_pkg__.uncle.cousin.nephew'] + globals_ = {'__package__': '__runpy_pkg__.__runpy_pkg__'} + def callback(global_): + import_util.import_('__runpy_pkg__.__runpy_pkg__') + module = import_util.import_('uncle.cousin', globals_, {}, + fromlist=['nephew'], + level=2) + 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(): + from test.support import run_unittest + run_unittest(RelativeImports) + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/import_/util.py b/Lib/test/test_importlib/import_/util.py new file mode 100644 index 0000000..86ac065 --- /dev/null +++ b/Lib/test/test_importlib/import_/util.py @@ -0,0 +1,28 @@ +import functools +import importlib +import unittest + + +using___import__ = False + + +def import_(*args, **kwargs): + """Delegate to allow for injecting different implementations of import.""" + if using___import__: + return __import__(*args, **kwargs) + else: + return importlib.__import__(*args, **kwargs) + + +def importlib_only(fxn): + """Decorator to skip a test if using __builtins__.__import__.""" + return unittest.skipIf(using___import__, "importlib-specific test")(fxn) + + +def mock_path_hook(*entries, importer): + """A mock sys.path_hooks entry.""" + def hook(entry): + if entry not in entries: + raise ImportError + return importer + return hook diff --git a/Lib/test/test_importlib/regrtest.py b/Lib/test/test_importlib/regrtest.py new file mode 100644 index 0000000..a5be11f --- /dev/null +++ b/Lib/test/test_importlib/regrtest.py @@ -0,0 +1,17 @@ +"""Run Python's standard test suite using importlib.__import__. + +Tests known to fail because of assumptions that importlib (properly) +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. + +""" +import importlib +import sys +from test import regrtest + +if __name__ == '__main__': + __builtins__.__import__ = importlib.__import__ + sys.path_importer_cache.clear() + + regrtest.main(quiet=True, verbose2=True) diff --git a/Lib/test/test_importlib/source/__init__.py b/Lib/test/test_importlib/source/__init__.py new file mode 100644 index 0000000..3ef97f3 --- /dev/null +++ b/Lib/test/test_importlib/source/__init__.py @@ -0,0 +1,13 @@ +from .. import test_suite +import os.path +import unittest + + +def test_suite(): + directory = os.path.dirname(__file__) + return test.test_suite('importlib.test.source', directory) + + +if __name__ == '__main__': + from test.support import run_unittest + run_unittest(test_suite()) diff --git a/Lib/test/test_importlib/source/test_abc_loader.py b/Lib/test/test_importlib/source/test_abc_loader.py new file mode 100644 index 0000000..afcaad0 --- /dev/null +++ b/Lib/test/test_importlib/source/test_abc_loader.py @@ -0,0 +1,886 @@ +import importlib +from importlib import abc + +from .. import abc as testing_abc +from .. import util +from . import util as source_util + +import imp +import inspect +import io +import marshal +import os +import sys +import types +import unittest +import warnings + + +class SourceOnlyLoaderMock(abc.SourceLoader): + + # Globals that should be defined for all modules. + source = (b"_ = '::'.join([__name__, __file__, __cached__, __package__, " + b"repr(__loader__)])") + + def __init__(self, path): + self.path = path + + def get_data(self, path): + assert self.path == path + return self.source + + def get_filename(self, fullname): + return self.path + + +class SourceLoaderMock(SourceOnlyLoaderMock): + + source_mtime = 1 + + 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(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)) + self.bytecode = bytes(data) + self.written = {} + + def get_data(self, path): + if path == self.path: + return super().get_data(path) + elif path == self.bytecode_path: + return self.bytecode + else: + raise IOError + + def path_stats(self, path): + assert path == self.path + return {'mtime': self.source_mtime, 'size': self.source_size} + + def set_data(self, path, data): + self.written[path] = bytes(data) + return path == self.bytecode_path + + +class PyLoaderMock(abc.PyLoader): + + # Globals that should be defined for all modules. + source = (b"_ = '::'.join([__name__, __file__, __package__, " + b"repr(__loader__)])") + + def __init__(self, data): + """Take a dict of 'module_name: path' pairings. + + Paths should have no file extension, allowing packages to be denoted by + ending in '__init__'. + + """ + self.module_paths = data + self.path_to_module = {val:key for key,val in data.items()} + + def get_data(self, path): + if path not in self.path_to_module: + raise IOError + return self.source + + def is_package(self, name): + filename = os.path.basename(self.get_filename(name)) + return os.path.splitext(filename)[0] == '__init__' + + def source_path(self, name): + try: + return self.module_paths[name] + except KeyError: + raise ImportError + + def get_filename(self, name): + """Silence deprecation warning.""" + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + path = super().get_filename(name) + assert len(w) == 1 + assert issubclass(w[0].category, DeprecationWarning) + return path + + +class PyLoaderCompatMock(PyLoaderMock): + + """Mock that matches what is suggested to have a loader that is compatible + from Python 3.1 onwards.""" + + def get_filename(self, fullname): + try: + return self.module_paths[fullname] + except KeyError: + raise ImportError + + def source_path(self, fullname): + try: + return self.get_filename(fullname) + except ImportError: + return None + + +class PyPycLoaderMock(abc.PyPycLoader, PyLoaderMock): + + default_mtime = 1 + + def __init__(self, source, bc={}): + """Initialize mock. + + 'bc' is a dict keyed on a module's name. The value is dict with + possible keys of 'path', 'mtime', 'magic', and 'bc'. Except for 'path', + each of those keys control if any part of created bytecode is to + deviate from default values. + + """ + super().__init__(source) + self.module_bytecode = {} + self.path_to_bytecode = {} + self.bytecode_to_path = {} + for name, data in bc.items(): + self.path_to_bytecode[data['path']] = name + self.bytecode_to_path[name] = data['path'] + magic = data.get('magic', imp.get_magic()) + mtime = importlib._w_long(data.get('mtime', self.default_mtime)) + source_size = importlib._w_long(len(self.source) & 0xFFFFFFFF) + if 'bc' in data: + bc = data['bc'] + else: + bc = self.compile_bc(name) + self.module_bytecode[name] = magic + mtime + source_size + bc + + def compile_bc(self, name): + source_path = self.module_paths.get(name, '') or '' + code = compile(self.source, source_path, 'exec') + return marshal.dumps(code) + + def source_mtime(self, name): + if name in self.module_paths: + return self.default_mtime + elif name in self.module_bytecode: + return None + else: + raise ImportError + + def bytecode_path(self, name): + try: + return self.bytecode_to_path[name] + except KeyError: + if name in self.module_paths: + return None + else: + raise ImportError + + def write_bytecode(self, name, bytecode): + self.module_bytecode[name] = bytecode + return True + + def get_data(self, path): + if path in self.path_to_module: + return super().get_data(path) + elif path in self.path_to_bytecode: + name = self.path_to_bytecode[path] + return self.module_bytecode[name] + else: + raise IOError + + def is_package(self, name): + try: + return super().is_package(name) + except TypeError: + return '__init__' in self.bytecode_to_path[name] + + def get_code(self, name): + with warnings.catch_warnings(record=True) as w: + warnings.simplefilter("always") + code_object = super().get_code(name) + assert len(w) == 1 + assert issubclass(w[0].category, DeprecationWarning) + return code_object + +class PyLoaderTests(testing_abc.LoaderTests): + + """Tests for importlib.abc.PyLoader.""" + + mocker = PyLoaderMock + + def eq_attrs(self, ob, **kwargs): + for attr, val in kwargs.items(): + found = getattr(ob, attr) + self.assertEqual(found, val, + "{} attribute: {} != {}".format(attr, found, val)) + + def test_module(self): + name = '' + path = os.path.join('', 'path', 'to', 'module') + mock = self.mocker({name: path}) + with util.uncache(name): + module = mock.load_module(name) + self.assertIn(name, sys.modules) + self.eq_attrs(module, __name__=name, __file__=path, __package__='', + __loader__=mock) + self.assertTrue(not hasattr(module, '__path__')) + return mock, name + + def test_package(self): + name = '' + path = os.path.join('path', 'to', name, '__init__') + mock = self.mocker({name: path}) + with util.uncache(name): + module = mock.load_module(name) + self.assertIn(name, sys.modules) + self.eq_attrs(module, __name__=name, __file__=path, + __path__=[os.path.dirname(path)], __package__=name, + __loader__=mock) + return mock, name + + def test_lacking_parent(self): + name = 'pkg.mod' + path = os.path.join('path', 'to', 'pkg', 'mod') + mock = self.mocker({name: path}) + with util.uncache(name): + module = mock.load_module(name) + self.assertIn(name, sys.modules) + self.eq_attrs(module, __name__=name, __file__=path, __package__='pkg', + __loader__=mock) + self.assertFalse(hasattr(module, '__path__')) + return mock, name + + def test_module_reuse(self): + name = 'mod' + path = os.path.join('path', 'to', 'mod') + module = imp.new_module(name) + mock = self.mocker({name: path}) + with util.uncache(name): + sys.modules[name] = module + loaded_module = mock.load_module(name) + self.assertIs(loaded_module, module) + self.assertIs(sys.modules[name], module) + return mock, name + + def test_state_after_failure(self): + name = "mod" + module = imp.new_module(name) + module.blah = None + mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) + mock.source = b"1/0" + with util.uncache(name): + sys.modules[name] = module + with self.assertRaises(ZeroDivisionError): + mock.load_module(name) + self.assertIs(sys.modules[name], module) + self.assertTrue(hasattr(module, 'blah')) + return mock + + def test_unloadable(self): + name = "mod" + mock = self.mocker({name: os.path.join('path', 'to', 'mod')}) + mock.source = b"1/0" + with util.uncache(name): + with self.assertRaises(ZeroDivisionError): + mock.load_module(name) + self.assertNotIn(name, sys.modules) + return mock + + +class PyLoaderCompatTests(PyLoaderTests): + + """Test that the suggested code to make a loader that is compatible from + Python 3.1 forward works.""" + + mocker = PyLoaderCompatMock + + +class PyLoaderInterfaceTests(unittest.TestCase): + + """Tests for importlib.abc.PyLoader to make sure that when source_path() + doesn't return a path everything works as expected.""" + + def test_no_source_path(self): + # No source path should lead to ImportError. + name = 'mod' + mock = PyLoaderMock({}) + with util.uncache(name), self.assertRaises(ImportError): + mock.load_module(name) + + def test_source_path_is_None(self): + name = 'mod' + mock = PyLoaderMock({name: None}) + with util.uncache(name), self.assertRaises(ImportError): + mock.load_module(name) + + def test_get_filename_with_source_path(self): + # get_filename() should return what source_path() returns. + name = 'mod' + path = os.path.join('path', 'to', 'source') + mock = PyLoaderMock({name: path}) + with util.uncache(name): + self.assertEqual(mock.get_filename(name), path) + + def test_get_filename_no_source_path(self): + # get_filename() should raise ImportError if source_path returns None. + name = 'mod' + mock = PyLoaderMock({name: None}) + with util.uncache(name), self.assertRaises(ImportError): + mock.get_filename(name) + + +class PyPycLoaderTests(PyLoaderTests): + + """Tests for importlib.abc.PyPycLoader.""" + + mocker = PyPycLoaderMock + + @source_util.writes_bytecode_files + def verify_bytecode(self, mock, name): + assert name in mock.module_paths + self.assertIn(name, mock.module_bytecode) + magic = mock.module_bytecode[name][:4] + self.assertEqual(magic, imp.get_magic()) + mtime = importlib._r_long(mock.module_bytecode[name][4:8]) + self.assertEqual(mtime, 1) + source_size = mock.module_bytecode[name][8:12] + self.assertEqual(len(mock.source) & 0xFFFFFFFF, + importlib._r_long(source_size)) + bc = mock.module_bytecode[name][12:] + self.assertEqual(bc, mock.compile_bc(name)) + + def test_module(self): + mock, name = super().test_module() + self.verify_bytecode(mock, name) + + def test_package(self): + mock, name = super().test_package() + self.verify_bytecode(mock, name) + + def test_lacking_parent(self): + mock, name = super().test_lacking_parent() + self.verify_bytecode(mock, name) + + def test_module_reuse(self): + mock, name = super().test_module_reuse() + self.verify_bytecode(mock, name) + + def test_state_after_failure(self): + super().test_state_after_failure() + + def test_unloadable(self): + super().test_unloadable() + + +class PyPycLoaderInterfaceTests(unittest.TestCase): + + """Test for the interface of importlib.abc.PyPycLoader.""" + + def get_filename_check(self, src_path, bc_path, expect): + name = 'mod' + mock = PyPycLoaderMock({name: src_path}, {name: {'path': bc_path}}) + with util.uncache(name): + assert mock.source_path(name) == src_path + assert mock.bytecode_path(name) == bc_path + self.assertEqual(mock.get_filename(name), expect) + + def test_filename_with_source_bc(self): + # When source and bytecode paths present, return the source path. + self.get_filename_check('source_path', 'bc_path', 'source_path') + + def test_filename_with_source_no_bc(self): + # With source but no bc, return source path. + self.get_filename_check('source_path', None, 'source_path') + + def test_filename_with_no_source_bc(self): + # With not source but bc, return the bc path. + self.get_filename_check(None, 'bc_path', 'bc_path') + + def test_filename_with_no_source_or_bc(self): + # With no source or bc, raise ImportError. + name = 'mod' + mock = PyPycLoaderMock({name: None}, {name: {'path': None}}) + with util.uncache(name), self.assertRaises(ImportError): + mock.get_filename(name) + + +class SkipWritingBytecodeTests(unittest.TestCase): + + """Test that bytecode is properly handled based on + sys.dont_write_bytecode.""" + + @source_util.writes_bytecode_files + def run_test(self, dont_write_bytecode): + name = 'mod' + mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}) + sys.dont_write_bytecode = dont_write_bytecode + with util.uncache(name): + mock.load_module(name) + self.assertIsNot(name in mock.module_bytecode, dont_write_bytecode) + + def test_no_bytecode_written(self): + self.run_test(True) + + def test_bytecode_written(self): + self.run_test(False) + + +class RegeneratedBytecodeTests(unittest.TestCase): + + """Test that bytecode is regenerated as expected.""" + + @source_util.writes_bytecode_files + def test_different_magic(self): + # A different magic number should lead to new bytecode. + name = 'mod' + bad_magic = b'\x00\x00\x00\x00' + assert bad_magic != imp.get_magic() + mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, + {name: {'path': os.path.join('path', 'to', + 'mod.bytecode'), + 'magic': bad_magic}}) + with util.uncache(name): + mock.load_module(name) + self.assertIn(name, mock.module_bytecode) + magic = mock.module_bytecode[name][:4] + self.assertEqual(magic, imp.get_magic()) + + @source_util.writes_bytecode_files + def test_old_mtime(self): + # Bytecode with an older mtime should be regenerated. + name = 'mod' + old_mtime = PyPycLoaderMock.default_mtime - 1 + mock = PyPycLoaderMock({name: os.path.join('path', 'to', 'mod')}, + {name: {'path': 'path/to/mod.bytecode', 'mtime': old_mtime}}) + with util.uncache(name): + mock.load_module(name) + self.assertIn(name, mock.module_bytecode) + mtime = importlib._r_long(mock.module_bytecode[name][4:8]) + self.assertEqual(mtime, PyPycLoaderMock.default_mtime) + + +class BadBytecodeFailureTests(unittest.TestCase): + + """Test import failures when there is no source and parts of the bytecode + is bad.""" + + def test_bad_magic(self): + # A bad magic number should lead to an ImportError. + name = 'mod' + bad_magic = b'\x00\x00\x00\x00' + bc = {name: + {'path': os.path.join('path', 'to', 'mod'), + 'magic': bad_magic}} + mock = PyPycLoaderMock({name: None}, bc) + 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. + name = 'mod' + bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b''}} + mock = PyPycLoaderMock({name: None}, bc) + with util.uncache(name), self.assertRaises(EOFError): + mock.load_module(name) + + def test_bad_bytecode(self): + # Malformed code object bytecode should lead to a ValueError. + name = 'mod' + bc = {name: {'path': os.path.join('path', 'to', 'mod'), 'bc': b'1234'}} + mock = PyPycLoaderMock({name: None}, bc) + with util.uncache(name), self.assertRaises(ValueError): + mock.load_module(name) + + +def raise_ImportError(*args, **kwargs): + raise ImportError + +class MissingPathsTests(unittest.TestCase): + + """Test what happens when a source or bytecode path does not exist (either + from *_path returning None or raising ImportError).""" + + def test_source_path_None(self): + # Bytecode should be used when source_path returns None, along with + # __file__ being set to the bytecode path. + name = 'mod' + bytecode_path = 'path/to/mod' + mock = PyPycLoaderMock({name: None}, {name: {'path': bytecode_path}}) + with util.uncache(name): + module = mock.load_module(name) + self.assertEqual(module.__file__, bytecode_path) + + # Testing for bytecode_path returning None handled by all tests where no + # bytecode initially exists. + + def test_all_paths_None(self): + # If all *_path methods return None, raise ImportError. + name = 'mod' + mock = PyPycLoaderMock({name: None}) + 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. + name = 'mod' + mock = PyPycLoaderMock({}, {name: {'path': os.path.join('path', 'to', + 'mod')}}) + with util.uncache(name), self.assertRaises(ImportError): + mock.load_module(name) + + def test_bytecode_path_ImportError(self): + # An ImportError from bytecode_path should trigger an ImportError. + name = 'mod' + 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) as cm: + mock.load_module(name) + + +class SourceLoaderTestHarness(unittest.TestCase): + + def setUp(self, *, is_package=True, **kwargs): + self.package = 'pkg' + if is_package: + self.path = os.path.join(self.package, '__init__.py') + self.name = self.package + else: + module_name = 'mod' + self.path = os.path.join(self.package, '.'.join(['mod', 'py'])) + self.name = '.'.join([self.package, module_name]) + self.cached = imp.cache_from_source(self.path) + self.loader = self.loader_mock(self.path, **kwargs) + + def verify_module(self, module): + self.assertEqual(module.__name__, self.name) + self.assertEqual(module.__file__, self.path) + self.assertEqual(module.__cached__, self.cached) + self.assertEqual(module.__package__, self.package) + self.assertEqual(module.__loader__, self.loader) + values = module._.split('::') + self.assertEqual(values[0], self.name) + self.assertEqual(values[1], self.path) + self.assertEqual(values[2], self.cached) + self.assertEqual(values[3], self.package) + self.assertEqual(values[4], repr(self.loader)) + + def verify_code(self, code_object): + module = imp.new_module(self.name) + module.__file__ = self.path + module.__cached__ = self.cached + module.__package__ = self.package + module.__loader__ = self.loader + module.__path__ = [] + exec(code_object, module.__dict__) + self.verify_module(module) + + +class SourceOnlyLoaderTests(SourceLoaderTestHarness): + + """Test importlib.abc.SourceLoader for source-only loading. + + Reload testing is subsumed by the tests for + importlib.util.module_for_loader. + + """ + + loader_mock = SourceOnlyLoaderMock + + def test_get_source(self): + # Verify the source code is returned as a string. + # If an IOError is raised by get_data then raise ImportError. + expected_source = self.loader.source.decode('utf-8') + self.assertEqual(self.loader.get_source(self.name), expected_source) + def raise_IOError(path): + raise IOError + self.loader.get_data = raise_IOError + 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. + self.setUp(is_package=False) + self.assertFalse(self.loader.is_package(self.name)) + self.setUp(is_package=True) + self.assertTrue(self.loader.is_package(self.name)) + self.assertFalse(self.loader.is_package(self.name + '.__init__')) + + def test_get_code(self): + # Verify the code object is created. + code_object = self.loader.get_code(self.name) + self.verify_code(code_object) + + def test_load_module(self): + # Loading a module should set __name__, __loader__, __package__, + # __path__ (for packages), __file__, and __cached__. + # The module should also be put into sys.modules. + with util.uncache(self.name): + module = self.loader.load_module(self.name) + self.verify_module(module) + self.assertEqual(module.__path__, [os.path.dirname(self.path)]) + self.assertIn(self.name, sys.modules) + + def test_package_settings(self): + # __package__ needs to be set, while __path__ is set on if the module + # is a package. + # Testing the values for a package are covered by test_load_module. + self.setUp(is_package=False) + with util.uncache(self.name): + module = self.loader.load_module(self.name) + self.verify_module(module) + self.assertTrue(not hasattr(module, '__path__')) + + def test_get_source_encoding(self): + # Source is considered encoded in UTF-8 by default unless otherwise + # specified by an encoding line. + source = "_ = 'ü'" + self.loader.source = source.encode('utf-8') + returned_source = self.loader.get_source(self.name) + self.assertEqual(returned_source, source) + source = "# coding: latin-1\n_ = ü" + self.loader.source = source.encode('latin-1') + returned_source = self.loader.get_source(self.name) + self.assertEqual(returned_source, source) + + +@unittest.skipIf(sys.dont_write_bytecode, "sys.dont_write_bytecode is true") +class SourceLoaderBytecodeTests(SourceLoaderTestHarness): + + """Test importlib.abc.SourceLoader's use of bytecode. + + Source-only testing handled by SourceOnlyLoaderTests. + + """ + + loader_mock = SourceLoaderMock + + def verify_code(self, code_object, *, bytecode_written=False): + super().verify_code(code_object) + if bytecode_written: + self.assertIn(self.cached, self.loader.written) + data = bytearray(imp.get_magic()) + 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)) + + def test_code_with_everything(self): + # When everything should work. + code_object = self.loader.get_code(self.name) + self.verify_code(code_object) + + def test_no_bytecode(self): + # If no bytecode exists then move on to the source. + self.loader.bytecode_path = "" + # Sanity check + with self.assertRaises(IOError): + bytecode_path = imp.cache_from_source(self.path) + self.loader.get_data(bytecode_path) + code_object = self.loader.get_code(self.name) + self.verify_code(code_object, bytecode_written=True) + + def test_code_bad_timestamp(self): + # Bytecode is only used when the timestamp matches the source EXACTLY. + for source_mtime in (0, 2): + assert source_mtime != self.loader.source_mtime + original = self.loader.source_mtime + self.loader.source_mtime = source_mtime + # If bytecode is used then EOFError would be raised by marshal. + self.loader.bytecode = self.loader.bytecode[8:] + code_object = self.loader.get_code(self.name) + self.verify_code(code_object, bytecode_written=True) + self.loader.source_mtime = original + + def test_code_bad_magic(self): + # Skip over bytecode with a bad magic number. + self.setUp(magic=b'0000') + # If bytecode is used then EOFError would be raised by marshal. + self.loader.bytecode = self.loader.bytecode[8:] + code_object = self.loader.get_code(self.name) + self.verify_code(code_object, bytecode_written=True) + + def test_dont_write_bytecode(self): + # Bytecode is not written if sys.dont_write_bytecode is true. + # Can assume it is false already thanks to the skipIf class decorator. + try: + sys.dont_write_bytecode = True + self.loader.bytecode_path = "" + code_object = self.loader.get_code(self.name) + self.assertNotIn(self.cached, self.loader.written) + finally: + sys.dont_write_bytecode = False + + def test_no_set_data(self): + # If set_data is not defined, one can still read bytecode. + self.setUp(magic=b'0000') + original_set_data = self.loader.__class__.set_data + try: + del self.loader.__class__.set_data + code_object = self.loader.get_code(self.name) + self.verify_code(code_object) + finally: + self.loader.__class__.set_data = original_set_data + + def test_set_data_raises_exceptions(self): + # Raising NotImplementedError or IOError is okay for set_data. + def raise_exception(exc): + def closure(*args, **kwargs): + raise exc + return closure + + self.setUp(magic=b'0000') + self.loader.set_data = raise_exception(NotImplementedError) + code_object = self.loader.get_code(self.name) + self.verify_code(code_object) + + +class SourceLoaderGetSourceTests(unittest.TestCase): + + """Tests for importlib.abc.SourceLoader.get_source().""" + + def test_default_encoding(self): + # Should have no problems with UTF-8 text. + name = 'mod' + mock = SourceOnlyLoaderMock('mod.file') + source = 'x = "ü"' + mock.source = source.encode('utf-8') + returned_source = mock.get_source(name) + self.assertEqual(returned_source, source) + + def test_decoded_source(self): + # Decoding should work. + name = 'mod' + mock = SourceOnlyLoaderMock("mod.file") + source = "# coding: Latin-1\nx='ü'" + assert source.encode('latin-1') != source.encode('utf-8') + mock.source = source.encode('latin-1') + returned_source = mock.get_source(name) + self.assertEqual(returned_source, source) + + def test_universal_newlines(self): + # PEP 302 says universal newlines should be used. + name = 'mod' + mock = SourceOnlyLoaderMock('mod.file') + source = "x = 42\r\ny = -13\r\n" + mock.source = source.encode('utf-8') + expect = io.IncrementalNewlineDecoder(None, True).decode(source) + self.assertEqual(mock.get_source(name), expect) + +class AbstractMethodImplTests(unittest.TestCase): + + """Test the concrete abstractmethod implementations.""" + + class Loader(abc.Loader): + def load_module(self, fullname): + super().load_module(fullname) + + class Finder(abc.Finder): + def find_module(self, _): + super().find_module(_) + + class ResourceLoader(Loader, abc.ResourceLoader): + def get_data(self, _): + super().get_data(_) + + class InspectLoader(Loader, abc.InspectLoader): + def is_package(self, _): + super().is_package(_) + + def get_code(self, _): + super().get_code(_) + + def get_source(self, _): + super().get_source(_) + + class ExecutionLoader(InspectLoader, abc.ExecutionLoader): + def get_filename(self, _): + super().get_filename(_) + + class SourceLoader(ResourceLoader, ExecutionLoader, abc.SourceLoader): + pass + + class PyLoader(ResourceLoader, InspectLoader, abc.PyLoader): + def source_path(self, _): + super().source_path(_) + + class PyPycLoader(PyLoader, abc.PyPycLoader): + def bytecode_path(self, _): + super().bytecode_path(_) + + def source_mtime(self, _): + super().source_mtime(_) + + def write_bytecode(self, _, _2): + super().write_bytecode(_, _2) + + def raises_NotImplementedError(self, ins, *args): + for method_name in args: + method = getattr(ins, method_name) + arg_count = len(inspect.getfullargspec(method)[0]) - 1 + args = [''] * arg_count + try: + method(*args) + except NotImplementedError: + pass + else: + msg = "{}.{} did not raise NotImplementedError" + self.fail(msg.format(ins.__class__.__name__, method_name)) + + def test_Loader(self): + self.raises_NotImplementedError(self.Loader(), 'load_module') + + # XXX misplaced; should be somewhere else + def test_Finder(self): + self.raises_NotImplementedError(self.Finder(), 'find_module') + + def test_ResourceLoader(self): + self.raises_NotImplementedError(self.ResourceLoader(), 'load_module', + 'get_data') + + def test_InspectLoader(self): + self.raises_NotImplementedError(self.InspectLoader(), 'load_module', + 'is_package', 'get_code', 'get_source') + + def test_ExecutionLoader(self): + self.raises_NotImplementedError(self.ExecutionLoader(), 'load_module', + 'is_package', 'get_code', 'get_source', + 'get_filename') + + def test_SourceLoader(self): + ins = self.SourceLoader() + # Required abstractmethods. + self.raises_NotImplementedError(ins, 'get_filename', 'get_data') + # Optional abstractmethods. + self.raises_NotImplementedError(ins,'path_stats', 'set_data') + + def test_PyLoader(self): + self.raises_NotImplementedError(self.PyLoader(), 'source_path', + 'get_data', 'is_package') + + def test_PyPycLoader(self): + self.raises_NotImplementedError(self.PyPycLoader(), 'source_path', + 'source_mtime', 'bytecode_path', + 'write_bytecode') + + +def test_main(): + from test.support import run_unittest + run_unittest(PyLoaderTests, PyLoaderCompatTests, + PyLoaderInterfaceTests, + PyPycLoaderTests, PyPycLoaderInterfaceTests, + SkipWritingBytecodeTests, RegeneratedBytecodeTests, + BadBytecodeFailureTests, MissingPathsTests, + SourceOnlyLoaderTests, + SourceLoaderBytecodeTests, + SourceLoaderGetSourceTests, + AbstractMethodImplTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/source/test_case_sensitivity.py b/Lib/test/test_importlib/source/test_case_sensitivity.py new file mode 100644 index 0000000..21a4378 --- /dev/null +++ b/Lib/test/test_importlib/source/test_case_sensitivity.py @@ -0,0 +1,72 @@ +"""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 +import unittest + + +@util.case_insensitive_tests +class CaseSensitivityTest(unittest.TestCase): + + """PEP 235 dictates that on case-preserving, case-insensitive file systems + that imports are case-sensitive unless the PYTHONCASEOK environment + variable is set.""" + + name = 'MoDuLe' + assert name != name.lower() + + def find(self, path): + 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): + """Look for a module with matching and non-matching sensitivity.""" + sensitive_pkg = 'sensitive.{0}'.format(self.name) + insensitive_pkg = 'insensitive.{0}'.format(self.name.lower()) + context = source_util.create_modules(insensitive_pkg, sensitive_pkg) + 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) + + 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)) + self.assertIsNone(insensitive) + + 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)) + self.assertTrue(hasattr(insensitive, 'load_module')) + self.assertIn(self.name, insensitive.get_filename(self.name)) + + +def test_main(): + test_support.run_unittest(CaseSensitivityTest) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py new file mode 100644 index 0000000..c401cf7 --- /dev/null +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -0,0 +1,482 @@ +from importlib import machinery +import importlib +import importlib.abc +from .. import abc +from .. import util +from . import util as source_util + +import errno +import imp +import marshal +import os +import py_compile +import shutil +import stat +import sys +import unittest + +from test.support import make_legacy_pyc + + +class SimpleTest(unittest.TestCase): + + """Should have no issue importing a source module [basic]. And if there is + a syntax error, it should raise a SyntaxError [syntax error]. + + """ + + 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 = machinery.SourceFileLoader('_temp', mapping['_temp']) + module = loader.load_module('_temp') + self.assertIn('_temp', sys.modules) + check = {'__name__': '_temp', '__file__': mapping['_temp'], + '__package__': ''} + for attr, value in check.items(): + self.assertEqual(getattr(module, attr), value) + + def test_package(self): + with source_util.create_modules('_pkg.__init__') as mapping: + loader = machinery.SourceFileLoader('_pkg', + mapping['_pkg.__init__']) + module = loader.load_module('_pkg') + self.assertIn('_pkg', sys.modules) + check = {'__name__': '_pkg', '__file__': mapping['_pkg.__init__'], + '__path__': [os.path.dirname(mapping['_pkg.__init__'])], + '__package__': '_pkg'} + for attr, value in check.items(): + self.assertEqual(getattr(module, attr), value) + + + def test_lacking_parent(self): + with source_util.create_modules('_pkg.__init__', '_pkg.mod')as mapping: + loader = machinery.SourceFileLoader('_pkg.mod', + mapping['_pkg.mod']) + module = loader.load_module('_pkg.mod') + self.assertIn('_pkg.mod', sys.modules) + check = {'__name__': '_pkg.mod', '__file__': mapping['_pkg.mod'], + '__package__': '_pkg'} + for attr, value in check.items(): + self.assertEqual(getattr(module, attr), value) + + def fake_mtime(self, fxn): + """Fake mtime to always be higher than expected.""" + return lambda name: fxn(name) + 1 + + def test_module_reuse(self): + with source_util.create_modules('_temp') as mapping: + loader = machinery.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") + module = loader.load_module('_temp') + self.assertIn('testing_var', module.__dict__, + "'testing_var' not in " + "{0}".format(list(module.__dict__.keys()))) + self.assertEqual(module, sys.modules['_temp']) + self.assertEqual(id(module), module_id) + self.assertEqual(id(module.__dict__), module_dict_id) + + def test_state_after_failure(self): + # A failed reload should leave the original module intact. + attributes = ('__file__', '__path__', '__package__') + value = '' + name = '_temp' + with source_util.create_modules(name) as mapping: + orig_module = imp.new_module(name) + for attr in attributes: + setattr(orig_module, attr, value) + with open(mapping[name], 'w') as file: + file.write('+++ bad syntax +++') + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) + with self.assertRaises(SyntaxError): + loader.load_module(name) + for attr in attributes: + self.assertEqual(getattr(orig_module, attr), value) + + # [syntax error] + def test_bad_syntax(self): + with source_util.create_modules('_temp') as mapping: + with open(mapping['_temp'], 'w') as file: + file.write('=') + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) + with self.assertRaises(SyntaxError): + loader.load_module('_temp') + self.assertNotIn('_temp', sys.modules) + + def test_file_from_empty_string_dir(self): + # Loading a module found from an empty string entry on sys.path should + # not only work, but keep all attributes relative. + file_path = '_temp.py' + with open(file_path, 'w') as file: + file.write("# test file for importlib") + try: + with util.uncache('_temp'): + loader = machinery.SourceFileLoader('_temp', file_path) + mod = loader.load_module('_temp') + self.assertEqual(file_path, mod.__file__) + self.assertEqual(imp.cache_from_source(file_path), + mod.__cached__) + finally: + os.unlink(file_path) + pycache = os.path.dirname(imp.cache_from_source(file_path)) + shutil.rmtree(pycache) + + def test_timestamp_overflow(self): + # When a modification timestamp is larger than 2**32, it should be + # truncated rather than raise an OverflowError. + with source_util.create_modules('_temp') as mapping: + source = mapping['_temp'] + compiled = imp.cache_from_source(source) + with open(source, 'w') as f: + f.write("x = 5") + try: + os.utime(source, (2 ** 33 - 5, 2 ** 33 - 5)) + except OverflowError: + self.skipTest("cannot set modification time to large integer") + except OSError as e: + if e.errno != getattr(errno, 'EOVERFLOW', None): + raise + self.skipTest("cannot set modification time to large integer ({})".format(e)) + loader = machinery.SourceFileLoader('_temp', mapping['_temp']) + mod = loader.load_module('_temp') + # Sanity checks. + self.assertEqual(mod.__cached__, compiled) + self.assertEqual(mod.x, 5) + # The pyc file was created. + os.stat(compiled) + + +class BadBytecodeTest(unittest.TestCase): + + def import_(self, file, module_name): + loader = self.loader(module_name, file) + module = loader.load_module(module_name) + self.assertIn(module_name, sys.modules) + + def manipulate_bytecode(self, name, mapping, manipulator, *, + del_source=False): + """Manipulate the bytecode of a module by passing it into a callable + that returns what to use as the new bytecode.""" + try: + del sys.modules['_temp'] + except KeyError: + pass + py_compile.compile(mapping[name]) + if not del_source: + bytecode_path = imp.cache_from_source(mapping[name]) + else: + os.unlink(mapping[name]) + bytecode_path = make_legacy_pyc(mapping[name]) + if manipulator: + with open(bytecode_path, 'rb') as file: + bc = file.read() + new_bc = manipulator(bc) + with open(bytecode_path, 'wb') as file: + if new_bc is not None: + file.write(new_bc) + return bytecode_path + + def _test_empty_file(self, test, *, del_source=False): + with source_util.create_modules('_temp') as mapping: + bc_path = self.manipulate_bytecode('_temp', mapping, + lambda bc: b'', + del_source=del_source) + test('_temp', mapping, bc_path) + + @source_util.writes_bytecode_files + def _test_partial_magic(self, test, *, del_source=False): + # When their are less than 4 bytes to a .pyc, regenerate it if + # possible, else raise ImportError. + with source_util.create_modules('_temp') as mapping: + bc_path = self.manipulate_bytecode('_temp', mapping, + lambda bc: bc[:3], + del_source=del_source) + test('_temp', mapping, bc_path) + + def _test_magic_only(self, test, *, del_source=False): + with source_util.create_modules('_temp') as mapping: + bc_path = self.manipulate_bytecode('_temp', mapping, + lambda bc: bc[:4], + del_source=del_source) + test('_temp', mapping, bc_path) + + def _test_partial_timestamp(self, test, *, del_source=False): + with source_util.create_modules('_temp') as mapping: + bc_path = self.manipulate_bytecode('_temp', mapping, + lambda bc: bc[:7], + del_source=del_source) + test('_temp', mapping, bc_path) + + def _test_partial_size(self, test, *, del_source=False): + with source_util.create_modules('_temp') as mapping: + 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[:12], + del_source=del_source) + file_path = mapping['_temp'] if not del_source else bc_path + with self.assertRaises(EOFError): + self.import_(file_path, '_temp') + + 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[:12] + marshal.dumps(b'abcd'), + del_source=del_source) + file_path = mapping['_temp'] if not del_source else bytecode_path + 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[:12] + b'', + del_source=del_source) + file_path = mapping['_temp'] if not del_source else bytecode_path + with self.assertRaises(EOFError): + self.import_(file_path, '_temp') + + def _test_bad_magic(self, test, *, del_source=False): + with source_util.create_modules('_temp') as mapping: + bc_path = self.manipulate_bytecode('_temp', mapping, + lambda bc: b'\x00\x00\x00\x00' + bc[4:]) + test('_temp', mapping, bc_path) + + +class SourceLoaderBadBytecodeTest(BadBytecodeTest): + + loader = machinery.SourceFileLoader + + @source_util.writes_bytecode_files + def test_empty_file(self): + # When a .pyc is empty, regenerate it if possible, else raise + # ImportError. + def test(name, mapping, bytecode_path): + self.import_(mapping[name], name) + with open(bytecode_path, 'rb') as file: + self.assertGreater(len(file.read()), 12) + + self._test_empty_file(test) + + def test_partial_magic(self): + def test(name, mapping, bytecode_path): + self.import_(mapping[name], name) + with open(bytecode_path, 'rb') as file: + self.assertGreater(len(file.read()), 12) + + self._test_partial_magic(test) + + @source_util.writes_bytecode_files + def test_magic_only(self): + # When there is only the magic number, regenerate the .pyc if possible, + # else raise EOFError. + def test(name, mapping, bytecode_path): + self.import_(mapping[name], name) + with open(bytecode_path, 'rb') as file: + self.assertGreater(len(file.read()), 12) + + self._test_magic_only(test) + + @source_util.writes_bytecode_files + def test_bad_magic(self): + # When the magic number is different, the bytecode should be + # regenerated. + def test(name, mapping, bytecode_path): + self.import_(mapping[name], name) + with open(bytecode_path, 'rb') as bytecode_file: + self.assertEqual(bytecode_file.read(4), imp.get_magic()) + + self._test_bad_magic(test) + + @source_util.writes_bytecode_files + def test_partial_timestamp(self): + # When the timestamp 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_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() + + @source_util.writes_bytecode_files + def test_non_code_marshal(self): + self._test_non_code_marshal() + # XXX ImportError when sourceless + + # [bad marshal] + @source_util.writes_bytecode_files + def test_bad_marshal(self): + # Bad marshal data should raise a ValueError. + self._test_bad_marshal() + + # [bad timestamp] + @source_util.writes_bytecode_files + def test_old_timestamp(self): + # When the timestamp is older than the source, bytecode should be + # regenerated. + zeros = b'\x00\x00\x00\x00' + with source_util.create_modules('_temp') as mapping: + py_compile.compile(mapping['_temp']) + bytecode_path = imp.cache_from_source(mapping['_temp']) + with open(bytecode_path, 'r+b') as bytecode_file: + bytecode_file.seek(4) + bytecode_file.write(zeros) + self.import_(mapping['_temp'], '_temp') + source_mtime = os.path.getmtime(mapping['_temp']) + source_timestamp = importlib._w_long(source_mtime) + with open(bytecode_path, 'rb') as bytecode_file: + bytecode_file.seek(4) + self.assertEqual(bytecode_file.read(4), source_timestamp) + + # [bytecode read-only] + @source_util.writes_bytecode_files + def test_read_only_bytecode(self): + # When bytecode is read-only but should be rewritten, fail silently. + with source_util.create_modules('_temp') as mapping: + # Create bytecode that will need to be re-created. + py_compile.compile(mapping['_temp']) + bytecode_path = imp.cache_from_source(mapping['_temp']) + with open(bytecode_path, 'r+b') as bytecode_file: + bytecode_file.seek(0) + bytecode_file.write(b'\x00\x00\x00\x00') + # Make the bytecode read-only. + os.chmod(bytecode_path, + stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH) + try: + # Should not raise IOError! + self.import_(mapping['_temp'], '_temp') + finally: + # Make writable for eventual clean-up. + os.chmod(bytecode_path, stat.S_IWUSR) + + +class SourcelessLoaderBadBytecodeTest(BadBytecodeTest): + + loader = machinery.SourcelessFileLoader + + def test_empty_file(self): + def test(name, mapping, bytecode_path): + 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) 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): + def test(name, mapping, bytecode_path): + with self.assertRaises(EOFError): + self.import_(bytecode_path, name) + + self._test_magic_only(test, del_source=True) + + def test_bad_magic(self): + def test(name, mapping, bytecode_path): + 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) + + def test_partial_timestamp(self): + def test(name, mapping, bytecode_path): + with self.assertRaises(EOFError): + self.import_(bytecode_path, name) + + 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) + + def test_non_code_marshal(self): + self._test_non_code_marshal(del_source=True) + + +def test_main(): + from test.support import run_unittest + run_unittest(SimpleTest, + SourceLoaderBadBytecodeTest, + SourcelessLoaderBadBytecodeTest + ) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/source/test_finder.py b/Lib/test/test_importlib/source/test_finder.py new file mode 100644 index 0000000..fa5d356 --- /dev/null +++ b/Lib/test/test_importlib/source/test_finder.py @@ -0,0 +1,147 @@ +from .. import abc +from . import util as source_util + +from importlib import machinery +import errno +import imp +import os +import py_compile +from test.support import make_legacy_pyc +import unittest +import warnings + + +class FinderTests(abc.FinderTests): + + """For a top-level module, it should just be found directly in the + directory being searched. This is true for a directory with source + [top-level source], bytecode [top-level bc], or both [top-level both]. + There is also the possibility that it is a package [top-level package], in + which case there will be a directory with the module name and an + __init__.py file. If there is a directory without an __init__.py an + ImportWarning is returned [empty dir]. + + For sub-modules and sub-packages, the same happens as above but only use + the tail end of the name [sub module] [sub package] [sub empty]. + + When there is a conflict between a package and module having the same name + in the same directory, the package wins out [package over module]. This is + so that imports of modules within the package can occur rather than trigger + an import error. + + When there is a package and module with the same name, always pick the + package over the module [package over module]. This is so that imports from + the package have the possibility of succeeding. + + """ + + def import_(self, root, module): + 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): + """Test the finding of 'test' with the creation of modules listed in + 'create'. + + Any names listed in 'compile_' are byte-compiled. Modules + listed in 'unlink' have their source files deleted. + + """ + if create is None: + create = {test} + with source_util.create_modules(*create) as mapping: + if compile_: + for name in compile_: + py_compile.compile(mapping[name]) + if unlink: + for name in unlink: + os.unlink(mapping[name]) + try: + make_legacy_pyc(mapping[name]) + except OSError as error: + # Some tests do not set compile_=True so the source + # module will not get compiled and there will be no + # PEP 3147 pyc file to rename. + if error.errno != errno.ENOENT: + raise + loader = self.import_(mapping['.root'], test) + self.assertTrue(hasattr(loader, 'load_module')) + return loader + + def test_module(self): + # [top-level source] + self.run_test('top_level') + # [top-level bc] + self.run_test('top_level', compile_={'top_level'}, + unlink={'top_level'}) + # [top-level both] + self.run_test('top_level', compile_={'top_level'}) + + # [top-level package] + def test_package(self): + # Source. + self.run_test('pkg', {'pkg.__init__'}) + # Bytecode. + self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'}, + unlink={'pkg.__init__'}) + # Both. + self.run_test('pkg', {'pkg.__init__'}, compile_={'pkg.__init__'}) + + # [sub module] + def test_module_in_package(self): + 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.assertTrue(hasattr(loader, 'load_module')) + + # [sub package] + def test_package_in_package(self): + 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') + self.assertTrue(hasattr(loader, 'load_module')) + + # [package over modules] + def test_package_over_module(self): + name = '_temp' + loader = self.run_test(name, {'{0}.__init__'.format(name), name}) + self.assertIn('__init__', loader.get_filename(name)) + + def test_failure(self): + with source_util.create_modules('blah') as mapping: + nothing = self.import_(mapping['.root'], 'sdfsadsadf') + self.assertIsNone(nothing) + + def test_empty_string_for_dir(self): + # The empty string from sys.path means to search in the cwd. + finder = machinery.FileFinder('', (machinery.SourceFileLoader, + machinery.SOURCE_SUFFIXES, True)) + with open('mod.py', 'w') as file: + file.write("# test file for importlib") + try: + loader = finder.find_module('mod') + self.assertTrue(hasattr(loader, 'load_module')) + 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 + run_unittest(FinderTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py new file mode 100644 index 0000000..54c0699 --- /dev/null +++ b/Lib/test/test_importlib/source/test_path_hook.py @@ -0,0 +1,32 @@ +from . import util as source_util + +from importlib import machinery +import imp +import unittest + + +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(self.path_hook()(mapping['.root']), + 'find_module')) + + def test_empty_string(self): + # The empty string represents the cwd. + self.assertTrue(hasattr(self.path_hook()(''), 'find_module')) + + +def test_main(): + from test.support import run_unittest + run_unittest(PathHookTest) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/source/test_source_encoding.py b/Lib/test/test_importlib/source/test_source_encoding.py new file mode 100644 index 0000000..0ca5195 --- /dev/null +++ b/Lib/test/test_importlib/source/test_source_encoding.py @@ -0,0 +1,123 @@ +from . import util as source_util + +from importlib import _bootstrap +import codecs +import re +import sys +# Because sys.path gets essentially blanked, need to have unicodedata already +# imported for the parser to use. +import unicodedata +import unittest + + +CODING_RE = re.compile(r'coding[:=]\s*([-\w.]+)') + + +class EncodingTest(unittest.TestCase): + + """PEP 3120 makes UTF-8 the default encoding for source code + [default encoding]. + + PEP 263 specifies how that can change on a per-file basis. Either the first + or second line can contain the encoding line [encoding first line] + encoding second line]. If the file has the BOM marker it is considered UTF-8 + implicitly [BOM]. If any encoding is specified it must be UTF-8, else it is + an error [BOM and utf-8][BOM conflict]. + + """ + + variable = '\u00fc' + character = '\u00c9' + source_line = "{0} = '{1}'\n".format(variable, character) + module_name = '_temp' + + def run_test(self, source): + 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]) + return loader.load_module(self.module_name) + + def create_source(self, encoding): + encoding_line = "# coding={0}".format(encoding) + assert CODING_RE.search(encoding_line) + source_lines = [encoding_line.encode('utf-8')] + source_lines.append(self.source_line.encode(encoding)) + return b'\n'.join(source_lines) + + def test_non_obvious_encoding(self): + # Make sure that an encoding that has never been a standard one for + # Python works. + encoding_line = "# coding=koi8-r" + assert CODING_RE.search(encoding_line) + source = "{0}\na=42\n".format(encoding_line).encode("koi8-r") + self.run_test(source) + + # [default encoding] + def test_default_encoding(self): + self.run_test(self.source_line.encode('utf-8')) + + # [encoding first line] + def test_encoding_on_first_line(self): + encoding = 'Latin-1' + source = self.create_source(encoding) + self.run_test(source) + + # [encoding second line] + def test_encoding_on_second_line(self): + source = b"#/usr/bin/python\n" + self.create_source('Latin-1') + self.run_test(source) + + # [BOM] + def test_bom(self): + self.run_test(codecs.BOM_UTF8 + self.source_line.encode('utf-8')) + + # [BOM and utf-8] + def test_bom_and_utf_8(self): + source = codecs.BOM_UTF8 + self.create_source('utf-8') + self.run_test(source) + + # [BOM conflict] + def test_bom_conflict(self): + source = codecs.BOM_UTF8 + self.create_source('latin-1') + with self.assertRaises(SyntaxError): + self.run_test(source) + + +class LineEndingTest(unittest.TestCase): + + r"""Source written with the three types of line endings (\n, \r\n, \r) + need to be readable [cr][crlf][lf].""" + + def run_test(self, line_ending): + module_name = '_temp' + source_lines = [b"a = 42", b"b = -13", b''] + source = line_ending.join(source_lines) + with source_util.create_modules(module_name) as mapping: + with open(mapping[module_name], 'wb') as file: + file.write(source) + loader = _bootstrap.SourceFileLoader(module_name, + mapping[module_name]) + return loader.load_module(module_name) + + # [cr] + def test_cr(self): + self.run_test(b'\r') + + # [crlf] + def test_crlf(self): + self.run_test(b'\r\n') + + # [lf] + def test_lf(self): + self.run_test(b'\n') + + +def test_main(): + from test.support import run_unittest + run_unittest(EncodingTest, LineEndingTest) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/source/util.py b/Lib/test/test_importlib/source/util.py new file mode 100644 index 0000000..ae65663 --- /dev/null +++ b/Lib/test/test_importlib/source/util.py @@ -0,0 +1,97 @@ +from .. import util +import contextlib +import errno +import functools +import imp +import os +import os.path +import sys +import tempfile +from test import support + + +def writes_bytecode_files(fxn): + """Decorator to protect sys.dont_write_bytecode from mutation and to skip + tests that require it to be set to False.""" + if sys.dont_write_bytecode: + return lambda *args, **kwargs: None + @functools.wraps(fxn) + def wrapper(*args, **kwargs): + original = sys.dont_write_bytecode + sys.dont_write_bytecode = False + try: + to_return = fxn(*args, **kwargs) + finally: + sys.dont_write_bytecode = original + return to_return + return wrapper + + +def ensure_bytecode_path(bytecode_path): + """Ensure that the __pycache__ directory for PEP 3147 pyc file exists. + + :param bytecode_path: File system path to PEP 3147 pyc file. + """ + try: + os.mkdir(os.path.dirname(bytecode_path)) + except OSError as error: + if error.errno != errno.EEXIST: + raise + + +@contextlib.contextmanager +def create_modules(*names): + """Temporarily create each named module with an attribute (named 'attr') + that contains the name passed into the context manager that caused the + creation of the module. + + All files are created in a temporary directory returned by + tempfile.mkdtemp(). This directory is inserted at the beginning of + sys.path. When the context manager exits all created files (source and + bytecode) are explicitly deleted. + + No magic is performed when creating packages! This means that if you create + a module within a package you must also create the package's __init__ as + well. + + """ + source = 'attr = {0!r}' + created_paths = [] + mapping = {} + state_manager = None + uncache_manager = None + try: + temp_dir = tempfile.mkdtemp() + mapping['.root'] = temp_dir + import_names = set() + for name in names: + if not name.endswith('__init__'): + import_name = name + else: + import_name = name[:-len('.__init__')] + import_names.add(import_name) + if import_name in sys.modules: + del sys.modules[import_name] + name_parts = name.split('.') + file_path = temp_dir + for directory in name_parts[:-1]: + file_path = os.path.join(file_path, directory) + if not os.path.exists(file_path): + os.mkdir(file_path) + created_paths.append(file_path) + file_path = os.path.join(file_path, name_parts[-1] + '.py') + with open(file_path, 'w') as file: + file.write(source.format(name)) + created_paths.append(file_path) + mapping[name] = file_path + uncache_manager = util.uncache(*import_names) + uncache_manager.__enter__() + state_manager = util.import_state(path=[temp_dir]) + state_manager.__enter__() + yield mapping + finally: + if state_manager is not None: + state_manager.__exit__(None, None, None) + if uncache_manager is not None: + uncache_manager.__exit__(None, None, None) + support.rmtree(temp_dir) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py new file mode 100644 index 0000000..008bd21 --- /dev/null +++ b/Lib/test/test_importlib/test_abc.py @@ -0,0 +1,96 @@ +from importlib import abc +from importlib import machinery +import inspect +import unittest + + +class InheritanceTests: + + """Test that the specified class is a subclass/superclass of the expected + classes.""" + + subclasses = [] + superclasses = [] + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + assert self.subclasses or self.superclasses, self.__class__ + self.__test = getattr(abc, self.__class__.__name__) + + def test_subclasses(self): + # Test that the expected subclasses inherit. + for subclass in self.subclasses: + self.assertTrue(issubclass(subclass, self.__test), + "{0} is not a subclass of {1}".format(subclass, self.__test)) + + def test_superclasses(self): + # Test that the class inherits from the expected superclasses. + for superclass in self.superclasses: + self.assertTrue(issubclass(self.__test, superclass), + "{0} is not a superclass of {1}".format(superclass, self.__test)) + + +class Finder(InheritanceTests, unittest.TestCase): + + subclasses = [machinery.BuiltinImporter, machinery.FrozenImporter, + machinery.PathFinder] + + +class Loader(InheritanceTests, unittest.TestCase): + + subclasses = [abc.PyLoader] + + +class ResourceLoader(InheritanceTests, unittest.TestCase): + + superclasses = [abc.Loader] + + +class InspectLoader(InheritanceTests, unittest.TestCase): + + superclasses = [abc.Loader] + subclasses = [abc.PyLoader, machinery.BuiltinImporter, + machinery.FrozenImporter, machinery.ExtensionFileLoader] + + +class ExecutionLoader(InheritanceTests, unittest.TestCase): + + superclasses = [abc.InspectLoader] + 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): + + superclasses = [abc.Loader, abc.ResourceLoader, abc.ExecutionLoader] + + +class PyPycLoader(InheritanceTests, unittest.TestCase): + + superclasses = [abc.PyLoader] + + +def test_main(): + from test.support import run_unittest + classes = [] + for class_ in globals().values(): + if (inspect.isclass(class_) and + issubclass(class_, unittest.TestCase) and + issubclass(class_, InheritanceTests)): + classes.append(class_) + run_unittest(*classes) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py new file mode 100644 index 0000000..ba2a721 --- /dev/null +++ b/Lib/test/test_importlib/test_api.py @@ -0,0 +1,183 @@ +from . import util +import imp +import importlib +from importlib import machinery +import sys +from test import support +import unittest + + +class ImportModuleTests(unittest.TestCase): + + """Test importlib.import_module.""" + + def test_module_import(self): + # Test importing a top-level module. + with util.mock_modules('top_level') as mock: + with util.import_state(meta_path=[mock]): + module = importlib.import_module('top_level') + self.assertEqual(module.__name__, 'top_level') + + def test_absolute_package_import(self): + # Test importing a module from a package with an absolute name. + pkg_name = 'pkg' + pkg_long_name = '{0}.__init__'.format(pkg_name) + name = '{0}.mod'.format(pkg_name) + with util.mock_modules(pkg_long_name, name) as mock: + with util.import_state(meta_path=[mock]): + module = importlib.import_module(name) + self.assertEqual(module.__name__, name) + + def test_shallow_relative_package_import(self): + # Test importing a module from a package through a relative import. + pkg_name = 'pkg' + pkg_long_name = '{0}.__init__'.format(pkg_name) + module_name = 'mod' + absolute_name = '{0}.{1}'.format(pkg_name, module_name) + relative_name = '.{0}'.format(module_name) + with util.mock_modules(pkg_long_name, absolute_name) as mock: + with util.import_state(meta_path=[mock]): + importlib.import_module(pkg_name) + module = importlib.import_module(relative_name, pkg_name) + self.assertEqual(module.__name__, absolute_name) + + def test_deep_relative_package_import(self): + modules = ['a.__init__', 'a.b.__init__', 'a.c'] + with util.mock_modules(*modules) as mock: + with util.import_state(meta_path=[mock]): + importlib.import_module('a') + importlib.import_module('a.b') + module = importlib.import_module('..c', 'a.b') + self.assertEqual(module.__name__, 'a.c') + + def test_absolute_import_with_package(self): + # Test importing a module from a package with an absolute name with + # the 'package' argument given. + pkg_name = 'pkg' + pkg_long_name = '{0}.__init__'.format(pkg_name) + name = '{0}.mod'.format(pkg_name) + with util.mock_modules(pkg_long_name, name) as mock: + with util.import_state(meta_path=[mock]): + importlib.import_module(pkg_name) + module = importlib.import_module(name, pkg_name) + self.assertEqual(module.__name__, name) + + def test_relative_import_wo_package(self): + # Relative imports cannot happen without the 'package' argument being + # set. + with self.assertRaises(TypeError): + importlib.import_module('.support') + + + def test_loaded_once(self): + # Issue #13591: Modules should only be loaded once when + # initializing the parent package attempts to import the + # module currently being imported. + b_load_count = 0 + def load_a(): + importlib.import_module('a.b') + def load_b(): + nonlocal b_load_count + b_load_count += 1 + code = {'a': load_a, 'a.b': load_b} + modules = ['a.__init__', 'a.b'] + with util.mock_modules(*modules, module_code=code) as mock: + with util.import_state(meta_path=[mock]): + 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. + + +class FrozenImportlibTests(unittest.TestCase): + + def test_no_frozen_importlib(self): + # Should be able to import w/o _frozen_importlib being defined. + module = support.import_fresh_module('importlib', blocked=['_frozen_importlib']) + self.assertFalse(isinstance(module.__loader__, + machinery.FrozenImporter)) + + +def test_main(): + from test.support import run_unittest + run_unittest(ImportModuleTests, + FindLoaderTests, + InvalidateCacheTests, + FrozenImportlibTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/test_locks.py b/Lib/test/test_importlib/test_locks.py new file mode 100644 index 0000000..d36b71e --- /dev/null +++ b/Lib/test/test_importlib/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.assertIsNone(wr()) + + def test_all_locks(self): + support.gc_collect() + self.assertEqual(0, len(_bootstrap._module_locks), _bootstrap._module_locks) + + +@support.reap_threads +def test_main(): + support.run_unittest(ModuleLockAsRLockTests, + DeadlockAvoidanceTests, + LifetimeTests) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py new file mode 100644 index 0000000..efc8977 --- /dev/null +++ b/Lib/test/test_importlib/test_util.py @@ -0,0 +1,208 @@ +from importlib import util +from . import util as test_util +import imp +import sys +import types +import unittest + + +class ModuleForLoaderTests(unittest.TestCase): + + """Tests for importlib.util.module_for_loader.""" + + def return_module(self, name): + fxn = util.module_for_loader(lambda self, module: module) + return fxn(self, name) + + def raise_exception(self, name): + def to_wrap(self, module): + raise ImportError + fxn = util.module_for_loader(to_wrap) + try: + fxn(self, name) + except ImportError: + pass + + def test_new_module(self): + # Test that when no module exists in sys.modules a new module is + # created. + module_name = 'a.b.c' + with test_util.uncache(module_name): + module = self.return_module(module_name) + self.assertIn(module_name, sys.modules) + self.assertIsInstance(module, types.ModuleType) + self.assertEqual(module.__name__, module_name) + + def test_reload(self): + # Test that a module is reused if already in sys.modules. + name = 'a.b.c' + module = imp.new_module('a.b.c') + with test_util.uncache(name): + sys.modules[name] = module + returned_module = self.return_module(name) + self.assertIs(returned_module, sys.modules[name]) + + def test_new_module_failure(self): + # Test that a module is removed from sys.modules if added but an + # exception is raised. + name = 'a.b.c' + with test_util.uncache(name): + self.raise_exception(name) + self.assertNotIn(name, sys.modules) + + def test_reload_failure(self): + # Test that a failure on reload leaves the module in-place. + name = 'a.b.c' + module = imp.new_module(name) + with test_util.uncache(name): + sys.modules[name] = module + 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.assertIs(given, 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') + + 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): + """Verify the module has the expected value for __package__ after + passing through set_package.""" + fxn = lambda: module + wrapped = util.set_package(fxn) + wrapped() + self.assertTrue(hasattr(module, '__package__')) + self.assertEqual(expect, module.__package__) + + def test_top_level(self): + # __package__ should be set to the empty string if a top-level module. + # Implicitly tests when package is set to None. + module = imp.new_module('module') + module.__package__ = None + self.verify(module, '') + + def test_package(self): + # Test setting __package__ for a package. + module = imp.new_module('pkg') + module.__path__ = [''] + module.__package__ = None + self.verify(module, 'pkg') + + def test_submodule(self): + # Test __package__ for a module in a package. + module = imp.new_module('pkg.mod') + module.__package__ = None + self.verify(module, 'pkg') + + def test_setting_if_missing(self): + # __package__ should be set if it is missing. + module = imp.new_module('mod') + if hasattr(module, '__package__'): + delattr(module, '__package__') + self.verify(module, '') + + def test_leaving_alone(self): + # If __package__ is set and not None then leave it alone. + for value in (True, False): + module = imp.new_module('mod') + 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, + ResolveNameTests + ) + + +if __name__ == '__main__': + test_main() diff --git a/Lib/test/test_importlib/util.py b/Lib/test/test_importlib/util.py new file mode 100644 index 0000000..ef32f7d --- /dev/null +++ b/Lib/test/test_importlib/util.py @@ -0,0 +1,140 @@ +from contextlib import contextmanager +import imp +import os.path +from test import support +import unittest +import sys + + +CASE_INSENSITIVE_FS = True +# Windows is the only OS that is *always* case-insensitive +# (OS X *can* be case-sensitive). +if sys.platform not in ('win32', 'cygwin'): + changed_name = __file__.upper() + if changed_name == __file__: + changed_name = __file__.lower() + if not os.path.exists(changed_name): + CASE_INSENSITIVE_FS = False + + +def case_insensitive_tests(test): + """Class decorator that nullifies tests requiring a case-insensitive + file system.""" + return unittest.skipIf(not CASE_INSENSITIVE_FS, + "requires a case-insensitive filesystem")(test) + + +@contextmanager +def uncache(*names): + """Uncache a module from sys.modules. + + A basic sanity check is performed to prevent uncaching modules that either + cannot/shouldn't be uncached. + + """ + for name in names: + if name in ('sys', 'marshal', 'imp'): + raise ValueError( + "cannot uncache {0}".format(name)) + try: + del sys.modules[name] + except KeyError: + pass + try: + yield + finally: + for name in names: + try: + del sys.modules[name] + except KeyError: + pass + +@contextmanager +def import_state(**kwargs): + """Context manager to manage the various importers and stored state in the + sys module. + + The 'modules' attribute is not supported as the interpreter state stores a + pointer to the dict that the interpreter uses internally; + reassigning to sys.modules does not have the desired effect. + + """ + originals = {} + try: + for attr, default in (('meta_path', []), ('path', []), + ('path_hooks', []), + ('path_importer_cache', {})): + originals[attr] = getattr(sys, attr) + if attr in kwargs: + new_value = kwargs[attr] + del kwargs[attr] + else: + new_value = default + setattr(sys, attr, new_value) + if len(kwargs): + raise ValueError( + 'unrecognized arguments: {0}'.format(kwargs.keys())) + yield + finally: + for attr, value in originals.items(): + setattr(sys, attr, value) + + +class mock_modules: + + """A mock importer/loader.""" + + def __init__(self, *names, module_code={}): + self.modules = {} + self.module_code = {} + for name in names: + if not name.endswith('.__init__'): + import_name = name + else: + import_name = name[:-len('.__init__')] + if '.' not in name: + package = None + elif import_name == name: + package = name.rsplit('.', 1)[0] + else: + package = import_name + module = imp.new_module(import_name) + module.__loader__ = self + module.__file__ = '' + module.__package__ = package + module.attr = name + if import_name != name: + module.__path__ = [''] + self.modules[import_name] = module + if import_name in module_code: + self.module_code[import_name] = module_code[import_name] + + def __getitem__(self, name): + return self.modules[name] + + def find_module(self, fullname, path=None): + if fullname not in self.modules: + return None + else: + return self + + def load_module(self, fullname): + if fullname not in self.modules: + raise ImportError + else: + sys.modules[fullname] = self.modules[fullname] + if fullname in self.module_code: + try: + self.module_code[fullname]() + except Exception: + del sys.modules[fullname] + raise + return self.modules[fullname] + + def __enter__(self): + self._uncache = uncache(*self.modules.keys()) + self._uncache.__enter__() + return self + + def __exit__(self, *exc_info): + self._uncache.__exit__(None, None, None) diff --git a/Misc/NEWS b/Misc/NEWS index a09136d..48877fe 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -181,6 +181,8 @@ Documentation Tests ----- +- Issue #15168: Move importlib.test to test.test_importlib. + - Issue #15091: Reactivate a test on UNIX which was failing thanks to a forgotten importlib.invalidate_caches() call. -- cgit v0.12