diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py index 4682d22366c..405a03dc70f 100644 --- a/Lib/pkgutil.py +++ b/Lib/pkgutil.py @@ -16,6 +16,21 @@ __all__ = [ 'ImpImporter', 'ImpLoader', 'read_code', 'extend_path', ] + +def _get_spec(finder, name): + """Return the finder-specific module spec.""" + # Works with legacy finders. + try: + find_spec = finder.find_spec + except AttributeError: + loader = finder.find_module(name) + if loader is None: + return None + return importlib.util.spec_from_loader(name, loader) + else: + return find_spec(name) + + def read_code(stream): # This helper is needed in order for the PEP 302 emulation to # correctly handle compiled files @@ -326,9 +341,10 @@ class ImpLoader: self.source = self._get_delegate().get_source() return self.source - def _get_delegate(self): - return ImpImporter(self.filename).find_module('__init__') + finder = ImpImporter(self.filename) + spec = _get_spec(finder, '__init__') + return spec.loader def get_filename(self, fullname=None): fullname = self._fix_name(fullname) diff --git a/Lib/test/test_pkgutil.py b/Lib/test/test_pkgutil.py index d73b2117d3c..aaa9d8df6b4 100644 --- a/Lib/test/test_pkgutil.py +++ b/Lib/test/test_pkgutil.py @@ -2,6 +2,7 @@ from test.support import run_unittest, unload, check_warnings import unittest import sys import importlib +from importlib.util import spec_from_file_location import pkgutil import os import os.path @@ -103,23 +104,20 @@ class PkgutilTests(unittest.TestCase): class PkgutilPEP302Tests(unittest.TestCase): class MyTestLoader(object): - def load_module(self, fullname): - # Create an empty module - mod = sys.modules.setdefault(fullname, types.ModuleType(fullname)) - mod.__file__ = "<%s>" % self.__class__.__name__ - mod.__loader__ = self - # Make it a package - mod.__path__ = [] + def exec_module(self, mod): # Count how many times the module is reloaded - mod.__dict__['loads'] = mod.__dict__.get('loads',0) + 1 - return mod + mod.__dict__['loads'] = mod.__dict__.get('loads', 0) + 1 def get_data(self, path): return "Hello, world!" class MyTestImporter(object): - def find_module(self, fullname, path=None): - return PkgutilPEP302Tests.MyTestLoader() + def find_spec(self, fullname, path=None, target=None): + loader = PkgutilPEP302Tests.MyTestLoader() + return spec_from_file_location(fullname, + '<%s>' % loader.__class__.__name__, + loader=loader, + submodule_search_locations=[]) def setUp(self): sys.meta_path.insert(0, self.MyTestImporter()) @@ -210,7 +208,8 @@ class ExtendPathTests(unittest.TestCase): importers = list(iter_importers(fullname)) expected_importer = get_importer(pathitem) for finder in importers: - loader = finder.find_module(fullname) + spec = pkgutil._get_spec(finder, fullname) + loader = spec.loader try: loader = loader.loader except AttributeError: @@ -221,7 +220,7 @@ class ExtendPathTests(unittest.TestCase): self.assertEqual(finder, expected_importer) self.assertIsInstance(loader, importlib.machinery.SourceFileLoader) - self.assertIsNone(finder.find_module(pkgname)) + self.assertIsNone(pkgutil._get_spec(finder, pkgname)) with self.assertRaises(ImportError): list(iter_importers('invalid.module')) diff --git a/Misc/NEWS b/Misc/NEWS index e0488883c04..841d420ebfa 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -257,6 +257,8 @@ Library - Issue #19713: Move away from using find_module/load_module. +- Issue #19708: Update pkgutil to use the new importer APIs. + - Issue #19851: Fixed a regression in reloading sub-modules. - ssl.create_default_context() sets OP_NO_COMPRESSION to prevent CRIME.