From 228ab1ff6b5b02d8325a678b8afc140a153d4cf5 Mon Sep 17 00:00:00 2001 From: Eric Snow Date: Tue, 10 May 2016 16:21:03 -0600 Subject: [PATCH] Issue #21099: Switch applicable importlib tests to use PEP 451 API. --- .../extension/test_case_sensitivity.py | 2 - .../test_importlib/extension/test_finder.py | 1 - Lib/test/test_importlib/import_/test_path.py | 68 +++++++++++++++---- .../test_importlib/source/test_file_loader.py | 9 +-- .../test_importlib/source/test_path_hook.py | 11 ++- Lib/test/test_importlib/test_abc.py | 22 ++++-- Lib/test/test_importlib/test_api.py | 31 +++++++-- Misc/NEWS | 2 + 8 files changed, 108 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_importlib/extension/test_case_sensitivity.py b/Lib/test/test_importlib/extension/test_case_sensitivity.py index 42ddb3d2154..b74e9003910 100644 --- a/Lib/test/test_importlib/extension/test_case_sensitivity.py +++ b/Lib/test/test_importlib/extension/test_case_sensitivity.py @@ -7,8 +7,6 @@ from .. import util machinery = util.import_importlib('importlib.machinery') -# XXX find_spec tests - @unittest.skipIf(util.EXTENSIONS.filename is None, '_testcapi not available') @util.case_insensitive_tests class ExtensionModuleCaseSensitivityTest: diff --git a/Lib/test/test_importlib/extension/test_finder.py b/Lib/test/test_importlib/extension/test_finder.py index 71bf67febdf..c9b4a3772cc 100644 --- a/Lib/test/test_importlib/extension/test_finder.py +++ b/Lib/test/test_importlib/extension/test_finder.py @@ -6,7 +6,6 @@ machinery = util.import_importlib('importlib.machinery') import unittest import warnings -# XXX find_spec tests class FinderTests(abc.FinderTests): diff --git a/Lib/test/test_importlib/import_/test_path.py b/Lib/test/test_importlib/import_/test_path.py index b32a876f893..7aa26b0eee7 100644 --- a/Lib/test/test_importlib/import_/test_path.py +++ b/Lib/test/test_importlib/import_/test_path.py @@ -16,11 +16,14 @@ class FinderTests: """Tests for PathFinder.""" + find = None + check_found = None + def test_failure(self): # Test None returned upon not finding a suitable loader. module = '' with util.import_state(): - self.assertIsNone(self.machinery.PathFinder.find_module(module)) + self.assertIsNone(self.find(module)) def test_sys_path(self): # Test that sys.path is used when 'path' is None. @@ -30,8 +33,8 @@ class FinderTests: importer = util.mock_spec(module) with util.import_state(path_importer_cache={path: importer}, path=[path]): - loader = self.machinery.PathFinder.find_module(module) - self.assertIs(loader, importer) + found = self.find(module) + self.check_found(found, importer) def test_path(self): # Test that 'path' is used when set. @@ -40,8 +43,8 @@ class FinderTests: path = '' importer = util.mock_spec(module) with util.import_state(path_importer_cache={path: importer}): - loader = self.machinery.PathFinder.find_module(module, [path]) - self.assertIs(loader, importer) + found = self.find(module, [path]) + self.check_found(found, importer) def test_empty_list(self): # An empty list should not count as asking for sys.path. @@ -50,7 +53,7 @@ class FinderTests: importer = util.mock_spec(module) with util.import_state(path_importer_cache={path: importer}, path=[path]): - self.assertIsNone(self.machinery.PathFinder.find_module('module', [])) + self.assertIsNone(self.find('module', [])) def test_path_hooks(self): # Test that sys.path_hooks is used. @@ -60,8 +63,8 @@ class FinderTests: importer = util.mock_spec(module) hook = util.mock_path_hook(path, importer=importer) with util.import_state(path_hooks=[hook]): - loader = self.machinery.PathFinder.find_module(module, [path]) - self.assertIs(loader, importer) + found = self.find(module, [path]) + self.check_found(found, importer) self.assertIn(path, sys.path_importer_cache) self.assertIs(sys.path_importer_cache[path], importer) @@ -73,7 +76,7 @@ class FinderTests: path=[path_entry]): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') - self.assertIsNone(self.machinery.PathFinder.find_module('os')) + self.assertIsNone(self.find('os')) self.assertIsNone(sys.path_importer_cache[path_entry]) self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, ImportWarning)) @@ -85,8 +88,8 @@ class FinderTests: importer = util.mock_spec(module) hook = util.mock_path_hook(os.getcwd(), importer=importer) with util.import_state(path=[path], path_hooks=[hook]): - loader = self.machinery.PathFinder.find_module(module) - self.assertIs(loader, importer) + found = self.find(module) + self.check_found(found, importer) self.assertIn(os.getcwd(), sys.path_importer_cache) def test_None_on_sys_path(self): @@ -182,16 +185,33 @@ class FinderTests: self.assertIsNone(self.machinery.PathFinder.find_spec('whatever')) +class FindModuleTests(FinderTests): + def find(self, *args, **kwargs): + return self.machinery.PathFinder.find_module(*args, **kwargs) + def check_found(self, found, importer): + self.assertIs(found, importer) -(Frozen_FinderTests, - Source_FinderTests - ) = util.test_both(FinderTests, importlib=importlib, machinery=machinery) +(Frozen_FindModuleTests, + Source_FindModuleTests +) = util.test_both(FindModuleTests, importlib=importlib, machinery=machinery) + + +class FindSpecTests(FinderTests): + def find(self, *args, **kwargs): + return self.machinery.PathFinder.find_spec(*args, **kwargs) + def check_found(self, found, importer): + self.assertIs(found.loader, importer) + + +(Frozen_FindSpecTests, + Source_FindSpecTests + ) = util.test_both(FindSpecTests, importlib=importlib, machinery=machinery) class PathEntryFinderTests: - def test_finder_with_failing_find_module(self): + def test_finder_with_failing_find_spec(self): # PathEntryFinder with find_module() defined should work. # Issue #20763. class Finder: @@ -209,6 +229,24 @@ class PathEntryFinderTests: path_hooks=[Finder]): self.machinery.PathFinder.find_spec('importlib') + def test_finder_with_failing_find_module(self): + # PathEntryFinder with find_module() defined should work. + # Issue #20763. + class Finder: + path_location = 'test_finder_with_find_module' + def __init__(self, path): + if path != self.path_location: + raise ImportError + + @staticmethod + def find_module(fullname): + return None + + + with util.import_state(path=[Finder.path_location]+sys.path[:], + path_hooks=[Finder]): + self.machinery.PathFinder.find_module('importlib') + (Frozen_PEFTests, Source_PEFTests diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py index 73f4c620706..a151149f31a 100644 --- a/Lib/test/test_importlib/source/test_file_loader.py +++ b/Lib/test/test_importlib/source/test_file_loader.py @@ -217,7 +217,7 @@ class SimpleTest(abc.LoaderTests): # PEP 302 with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) - mod = loader.load_module('_temp') # XXX + mod = loader.load_module('_temp') # Sanity checks. self.assertEqual(mod.__cached__, compiled) self.assertEqual(mod.x, 5) @@ -245,12 +245,7 @@ class SimpleTest(abc.LoaderTests): class BadBytecodeTest: def import_(self, file, module_name): - loader = self.loader(module_name, file) - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - # XXX Change to use exec_module(). - module = loader.load_module(module_name) - self.assertIn(module_name, sys.modules) + raise NotImplementedError def manipulate_bytecode(self, name, mapping, manipulator, *, del_source=False): diff --git a/Lib/test/test_importlib/source/test_path_hook.py b/Lib/test/test_importlib/source/test_path_hook.py index e6a2415bda4..795d436c3b9 100644 --- a/Lib/test/test_importlib/source/test_path_hook.py +++ b/Lib/test/test_importlib/source/test_path_hook.py @@ -16,9 +16,18 @@ class PathHookTest: def test_success(self): with util.create_modules('dummy') as mapping: self.assertTrue(hasattr(self.path_hook()(mapping['.root']), - 'find_module')) + 'find_spec')) + + def test_success_legacy(self): + with 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_spec')) + + def test_empty_string_legacy(self): # The empty string represents the cwd. self.assertTrue(hasattr(self.path_hook()(''), 'find_module')) diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py index d4bf9153e93..c86248047fd 100644 --- a/Lib/test/test_importlib/test_abc.py +++ b/Lib/test/test_importlib/test_abc.py @@ -207,6 +207,10 @@ class LoaderDefaultsTests(ABCTestHarness): SPLIT = make_abc_subclasses(Loader) + def test_create_module(self): + spec = 'a spec' + self.assertIsNone(self.ins.create_module(spec)) + def test_load_module(self): with self.assertRaises(ImportError): self.ins.load_module('something') @@ -519,6 +523,12 @@ class InspectLoaderLoadModuleTests: support.unload(self.module_name) self.addCleanup(support.unload, self.module_name) + def load(self, loader): + spec = self.util.spec_from_loader(self.module_name, loader) + with warnings.catch_warnings(): + warnings.simplefilter('ignore', DeprecationWarning) + return self.init._bootstrap._load_unlocked(spec) + def mock_get_code(self): return mock.patch.object(self.InspectLoaderSubclass, 'get_code') @@ -528,9 +538,7 @@ class InspectLoaderLoadModuleTests: mocked_get_code.side_effect = ImportError with self.assertRaises(ImportError): loader = self.InspectLoaderSubclass() - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - loader.load_module(self.module_name) + self.load(loader) def test_get_code_None(self): # If get_code() returns None, raise ImportError. @@ -538,7 +546,7 @@ class InspectLoaderLoadModuleTests: mocked_get_code.return_value = None with self.assertRaises(ImportError): loader = self.InspectLoaderSubclass() - loader.load_module(self.module_name) + self.load(loader) def test_module_returned(self): # The loaded module should be returned. @@ -546,14 +554,16 @@ class InspectLoaderLoadModuleTests: with self.mock_get_code() as mocked_get_code: mocked_get_code.return_value = code loader = self.InspectLoaderSubclass() - module = loader.load_module(self.module_name) + module = self.load(loader) self.assertEqual(module, sys.modules[self.module_name]) (Frozen_ILLoadModuleTests, Source_ILLoadModuleTests ) = test_util.test_both(InspectLoaderLoadModuleTests, - InspectLoaderSubclass=SPLIT_IL) + InspectLoaderSubclass=SPLIT_IL, + init=init, + util=util) ##### ExecutionLoader concrete methods ######################################### diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index 6bc3c564a58..b0a94aaff5b 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -99,9 +99,7 @@ class ImportModuleTests: class FindLoaderTests: - class FakeMetaFinder: - @staticmethod - def find_module(name, path=None): return name, path + FakeMetaFinder = None def test_sys_modules(self): # If a module with __loader__ is in sys.modules, then return it. @@ -171,9 +169,30 @@ class FindLoaderTests: self.assertIsNone(self.init.find_loader('nevergoingtofindthismodule')) -(Frozen_FindLoaderTests, - Source_FindLoaderTests - ) = test_util.test_both(FindLoaderTests, init=init) +class FindLoaderPEP451Tests(FindLoaderTests): + + class FakeMetaFinder: + @staticmethod + def find_spec(name, path=None, target=None): + return machinery['Source'].ModuleSpec(name, (name, path)) + + +(Frozen_FindLoaderPEP451Tests, + Source_FindLoaderPEP451Tests + ) = test_util.test_both(FindLoaderPEP451Tests, init=init) + + +class FindLoaderPEP302Tests(FindLoaderTests): + + class FakeMetaFinder: + @staticmethod + def find_module(name, path=None): + return name, path + + +(Frozen_FindLoaderPEP302Tests, + Source_FindLoaderPEP302Tests + ) = test_util.test_both(FindLoaderPEP302Tests, init=init) class ReloadTests: diff --git a/Misc/NEWS b/Misc/NEWS index 15d278b8ead..8d469e23108 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -59,6 +59,8 @@ Core and Builtins - Issue #19711: Add tests for reloading namespace packages. +- Issue #21099: Switch applicable importlib tests to use PEP 451 API. + - Issue #26563: Debug hooks on Python memory allocators now raise a fatal error if functions of the :c:func:`PyMem_Malloc` family are called without holding the GIL.