Issue #13959: Have
importlib.abc.FileLoader.load_module()/get_filename() and importlib.machinery.ExtensionFileLoader.load_module() have their single argument be optional as the loader's constructor has all the ncessary information. This allows for the deprecation of imp.load_source()/load_compile()/load_package().
This commit is contained in:
parent
0c59b039b8
commit
c049952de7
|
@ -256,9 +256,14 @@ are also provided to help in implementing the core ABCs.
|
||||||
|
|
||||||
Path to the file of the module.
|
Path to the file of the module.
|
||||||
|
|
||||||
|
.. method:: load_module(fullname=None)
|
||||||
|
|
||||||
|
Calls
|
||||||
|
``super().load_module(fullname if fullname is not None else self.name)``.
|
||||||
|
|
||||||
.. method:: get_filename(fullname)
|
.. method:: get_filename(fullname)
|
||||||
|
|
||||||
Returns :attr:`path`.
|
Returns :attr:`path` when ``fullname`` equals :attr:`name` or ``None``.
|
||||||
|
|
||||||
.. method:: get_data(path)
|
.. method:: get_data(path)
|
||||||
|
|
||||||
|
@ -638,10 +643,6 @@ find and load modules.
|
||||||
|
|
||||||
Concrete implementation of :meth:`importlib.abc.SourceLoader.set_data`.
|
Concrete implementation of :meth:`importlib.abc.SourceLoader.set_data`.
|
||||||
|
|
||||||
.. method:: load_module(fullname)
|
|
||||||
|
|
||||||
Load the specified module if it is the same as :attr:`name`.
|
|
||||||
|
|
||||||
|
|
||||||
.. class:: SourcelessFileLoader(fullname, path)
|
.. class:: SourcelessFileLoader(fullname, path)
|
||||||
|
|
||||||
|
@ -676,10 +677,6 @@ find and load modules.
|
||||||
Returns ``None`` as bytecode files have no source when this loader is
|
Returns ``None`` as bytecode files have no source when this loader is
|
||||||
used.
|
used.
|
||||||
|
|
||||||
.. method:: load_module(fullname)
|
|
||||||
|
|
||||||
Loads the specified module if it is the same as :attr:`name`.
|
|
||||||
|
|
||||||
|
|
||||||
.. class:: ExtensionFileLoader(fullname, path)
|
.. class:: ExtensionFileLoader(fullname, path)
|
||||||
|
|
||||||
|
@ -699,10 +696,10 @@ find and load modules.
|
||||||
|
|
||||||
Path to the extension module.
|
Path to the extension module.
|
||||||
|
|
||||||
.. method:: load_module(fullname)
|
.. method:: load_module(fullname=None)
|
||||||
|
|
||||||
Loads the extension module if and only if *fullname** is the same as
|
Loads the extension module if and only if *fullname* is the same as
|
||||||
:attr:`name`.
|
:attr:`name` or is ``None``.
|
||||||
|
|
||||||
.. method:: is_package(fullname)
|
.. method:: is_package(fullname)
|
||||||
|
|
||||||
|
|
60
Lib/imp.py
60
Lib/imp.py
|
@ -24,8 +24,7 @@ import tokenize
|
||||||
import warnings
|
import warnings
|
||||||
|
|
||||||
|
|
||||||
# XXX "deprecate" once find_module(), load_module(), and get_suffixes() are
|
# DEPRECATED
|
||||||
# deprecated.
|
|
||||||
SEARCH_ERROR = 0
|
SEARCH_ERROR = 0
|
||||||
PY_SOURCE = 1
|
PY_SOURCE = 1
|
||||||
PY_COMPILED = 2
|
PY_COMPILED = 2
|
||||||
|
@ -112,8 +111,11 @@ class _LoadSourceCompatibility(_HackedGetData, _bootstrap.SourceFileLoader):
|
||||||
"""Compatibility support for implementing load_source()."""
|
"""Compatibility support for implementing load_source()."""
|
||||||
|
|
||||||
|
|
||||||
# XXX deprecate after better API exposed in importlib
|
|
||||||
def load_source(name, pathname, file=None):
|
def load_source(name, pathname, file=None):
|
||||||
|
msg = ('imp.load_source() is deprecated; use '
|
||||||
|
'importlib.machinery.SourceFileLoader(name, pathname).load_module()'
|
||||||
|
' instead')
|
||||||
|
warnings.warn(msg, DeprecationWarning, 2)
|
||||||
return _LoadSourceCompatibility(name, pathname, file).load_module(name)
|
return _LoadSourceCompatibility(name, pathname, file).load_module(name)
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,15 +125,22 @@ class _LoadCompiledCompatibility(_HackedGetData,
|
||||||
"""Compatibility support for implementing load_compiled()."""
|
"""Compatibility support for implementing load_compiled()."""
|
||||||
|
|
||||||
|
|
||||||
# XXX deprecate
|
|
||||||
def load_compiled(name, pathname, file=None):
|
def load_compiled(name, pathname, file=None):
|
||||||
|
msg = ('imp.load_compiled() is deprecated; use '
|
||||||
|
'importlib.machinery.SourcelessFileLoader(name, pathname).'
|
||||||
|
'load_module() instead ')
|
||||||
|
warnings.warn(msg, DeprecationWarning, 2)
|
||||||
return _LoadCompiledCompatibility(name, pathname, file).load_module(name)
|
return _LoadCompiledCompatibility(name, pathname, file).load_module(name)
|
||||||
|
|
||||||
|
|
||||||
# XXX deprecate
|
|
||||||
def load_package(name, path):
|
def load_package(name, path):
|
||||||
|
msg = ('imp.load_package() is deprecated; use either '
|
||||||
|
'importlib.machinery.SourceFileLoader() or '
|
||||||
|
'importlib.machinery.SourcelessFileLoader() instead')
|
||||||
|
warnings.warn(msg, DeprecationWarning, 2)
|
||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
extensions = machinery.SOURCE_SUFFIXES[:] + [machinery.BYTECODE_SUFFIXES]
|
extensions = (machinery.SOURCE_SUFFIXES[:] +
|
||||||
|
machinery.BYTECODE_SUFFIXES[:])
|
||||||
for extension in extensions:
|
for extension in extensions:
|
||||||
path = os.path.join(path, '__init__'+extension)
|
path = os.path.join(path, '__init__'+extension)
|
||||||
if os.path.exists(path):
|
if os.path.exists(path):
|
||||||
|
@ -149,26 +158,29 @@ def load_module(name, file, filename, details):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
suffix, mode, type_ = details
|
suffix, mode, type_ = details
|
||||||
if mode and (not mode.startswith(('r', 'U')) or '+' in mode):
|
with warnings.catch_warnings():
|
||||||
raise ValueError('invalid file open mode {!r}'.format(mode))
|
warnings.simplefilter('ignore')
|
||||||
elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
|
if mode and (not mode.startswith(('r', 'U')) or '+' in mode):
|
||||||
msg = 'file object required for import (type code {})'.format(type_)
|
raise ValueError('invalid file open mode {!r}'.format(mode))
|
||||||
raise ValueError(msg)
|
elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
|
||||||
elif type_ == PY_SOURCE:
|
msg = 'file object required for import (type code {})'.format(type_)
|
||||||
return load_source(name, filename, file)
|
raise ValueError(msg)
|
||||||
elif type_ == PY_COMPILED:
|
elif type_ == PY_SOURCE:
|
||||||
return load_compiled(name, filename, file)
|
return load_source(name, filename, file)
|
||||||
elif type_ == PKG_DIRECTORY:
|
elif type_ == PY_COMPILED:
|
||||||
return load_package(name, filename)
|
return load_compiled(name, filename, file)
|
||||||
elif type_ == C_BUILTIN:
|
elif type_ == PKG_DIRECTORY:
|
||||||
return init_builtin(name)
|
return load_package(name, filename)
|
||||||
elif type_ == PY_FROZEN:
|
elif type_ == C_BUILTIN:
|
||||||
return init_frozen(name)
|
return init_builtin(name)
|
||||||
else:
|
elif type_ == PY_FROZEN:
|
||||||
msg = "Don't know how to import {} (type code {}".format(name, type_)
|
return init_frozen(name)
|
||||||
raise ImportError(msg, name=name)
|
else:
|
||||||
|
msg = "Don't know how to import {} (type code {}".format(name, type_)
|
||||||
|
raise ImportError(msg, name=name)
|
||||||
|
|
||||||
|
|
||||||
|
# XXX deprecate
|
||||||
def find_module(name, path=None):
|
def find_module(name, path=None):
|
||||||
"""Search for a module.
|
"""Search for a module.
|
||||||
|
|
||||||
|
|
|
@ -282,8 +282,10 @@ def _check_name(method):
|
||||||
compared against. If the comparison fails then ImportError is raised.
|
compared against. If the comparison fails then ImportError is raised.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def _check_name_wrapper(self, name, *args, **kwargs):
|
def _check_name_wrapper(self, name=None, *args, **kwargs):
|
||||||
if self.name != name:
|
if name is None:
|
||||||
|
name = self.name
|
||||||
|
elif self.name != name:
|
||||||
raise ImportError("loader cannot handle %s" % name, name=name)
|
raise ImportError("loader cannot handle %s" % name, name=name)
|
||||||
return method(self, name, *args, **kwargs)
|
return method(self, name, *args, **kwargs)
|
||||||
_wrap(_check_name_wrapper, method)
|
_wrap(_check_name_wrapper, method)
|
||||||
|
@ -613,6 +615,11 @@ class FileLoader:
|
||||||
self.name = fullname
|
self.name = fullname
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
|
@_check_name
|
||||||
|
def load_module(self, fullname):
|
||||||
|
"""Load a module from a file."""
|
||||||
|
return super().load_module(fullname)
|
||||||
|
|
||||||
@_check_name
|
@_check_name
|
||||||
def get_filename(self, fullname):
|
def get_filename(self, fullname):
|
||||||
"""Return the path to the source file as found by the finder."""
|
"""Return the path to the source file as found by the finder."""
|
||||||
|
@ -713,17 +720,14 @@ class ExtensionFileLoader:
|
||||||
del sys.modules[fullname]
|
del sys.modules[fullname]
|
||||||
raise
|
raise
|
||||||
|
|
||||||
@_check_name
|
|
||||||
def is_package(self, fullname):
|
def is_package(self, fullname):
|
||||||
"""Return False as an extension module can never be a package."""
|
"""Return False as an extension module can never be a package."""
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@_check_name
|
|
||||||
def get_code(self, fullname):
|
def get_code(self, fullname):
|
||||||
"""Return None as an extension module cannot create a code object."""
|
"""Return None as an extension module cannot create a code object."""
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@_check_name
|
|
||||||
def get_source(self, fullname):
|
def get_source(self, fullname):
|
||||||
"""Return None as extension modules have no source code."""
|
"""Return None as extension modules have no source code."""
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from importlib import _bootstrap
|
from importlib import machinery
|
||||||
from . import util as ext_util
|
from . import util as ext_util
|
||||||
from .. import abc
|
from .. import abc
|
||||||
from .. import util
|
from .. import util
|
||||||
|
@ -11,10 +11,20 @@ class LoaderTests(abc.LoaderTests):
|
||||||
|
|
||||||
"""Test load_module() for extension modules."""
|
"""Test load_module() for extension modules."""
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.loader = machinery.ExtensionFileLoader(ext_util.NAME,
|
||||||
|
ext_util.FILEPATH)
|
||||||
|
|
||||||
def load_module(self, fullname):
|
def load_module(self, fullname):
|
||||||
loader = _bootstrap.ExtensionFileLoader(ext_util.NAME,
|
return self.loader.load_module(fullname)
|
||||||
ext_util.FILEPATH)
|
|
||||||
return 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):
|
def test_module(self):
|
||||||
with util.uncache(ext_util.NAME):
|
with util.uncache(ext_util.NAME):
|
||||||
|
@ -25,7 +35,7 @@ class LoaderTests(abc.LoaderTests):
|
||||||
self.assertEqual(getattr(module, attr), value)
|
self.assertEqual(getattr(module, attr), value)
|
||||||
self.assertTrue(ext_util.NAME in sys.modules)
|
self.assertTrue(ext_util.NAME in sys.modules)
|
||||||
self.assertTrue(isinstance(module.__loader__,
|
self.assertTrue(isinstance(module.__loader__,
|
||||||
_bootstrap.ExtensionFileLoader))
|
machinery.ExtensionFileLoader))
|
||||||
|
|
||||||
def test_package(self):
|
def test_package(self):
|
||||||
# Extensions are not found in packages.
|
# Extensions are not found in packages.
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from ... import _bootstrap
|
from ... import _bootstrap
|
||||||
import importlib
|
import importlib
|
||||||
|
import importlib.abc
|
||||||
from .. import abc
|
from .. import abc
|
||||||
from .. import util
|
from .. import util
|
||||||
from . import util as source_util
|
from . import util as source_util
|
||||||
|
@ -24,6 +25,40 @@ class SimpleTest(unittest.TestCase):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def test_load_module_API(self):
|
||||||
|
# If fullname is not specified that assume self.name is desired.
|
||||||
|
class TesterMixin(importlib.abc.Loader):
|
||||||
|
def load_module(self, fullname): return fullname
|
||||||
|
|
||||||
|
class Tester(importlib.abc.FileLoader, TesterMixin):
|
||||||
|
def get_code(self, _): pass
|
||||||
|
def get_source(self, _): pass
|
||||||
|
def is_package(self, _): pass
|
||||||
|
|
||||||
|
name = 'mod_name'
|
||||||
|
loader = Tester(name, 'some_path')
|
||||||
|
self.assertEqual(name, loader.load_module())
|
||||||
|
self.assertEqual(name, loader.load_module(None))
|
||||||
|
self.assertEqual(name, loader.load_module(name))
|
||||||
|
with self.assertRaises(ImportError):
|
||||||
|
loader.load_module(loader.name + 'XXX')
|
||||||
|
|
||||||
|
def test_get_filename_API(self):
|
||||||
|
# If fullname is not set then assume self.path is desired.
|
||||||
|
class Tester(importlib.abc.FileLoader):
|
||||||
|
def get_code(self, _): pass
|
||||||
|
def get_source(self, _): pass
|
||||||
|
def is_package(self, _): pass
|
||||||
|
|
||||||
|
path = 'some_path'
|
||||||
|
name = 'some_name'
|
||||||
|
loader = Tester(name, path)
|
||||||
|
self.assertEqual(path, loader.get_filename(name))
|
||||||
|
self.assertEqual(path, loader.get_filename())
|
||||||
|
self.assertEqual(path, loader.get_filename(None))
|
||||||
|
with self.assertRaises(ImportError):
|
||||||
|
loader.get_filename(name + 'XXX')
|
||||||
|
|
||||||
# [basic]
|
# [basic]
|
||||||
def test_module(self):
|
def test_module(self):
|
||||||
with source_util.create_modules('_temp') as mapping:
|
with source_util.create_modules('_temp') as mapping:
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import imp
|
import imp
|
||||||
|
import importlib
|
||||||
import os
|
import os
|
||||||
import os.path
|
import os.path
|
||||||
import shutil
|
import shutil
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
|
||||||
from test import support
|
from test import support
|
||||||
import importlib
|
import unittest
|
||||||
|
import warnings
|
||||||
|
|
||||||
class LockTests(unittest.TestCase):
|
class LockTests(unittest.TestCase):
|
||||||
|
|
||||||
|
@ -154,18 +155,24 @@ class ImportTests(unittest.TestCase):
|
||||||
mod = imp.load_module(temp_mod_name, file, filename, info)
|
mod = imp.load_module(temp_mod_name, file, filename, info)
|
||||||
self.assertEqual(mod.a, 1)
|
self.assertEqual(mod.a, 1)
|
||||||
|
|
||||||
mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore')
|
||||||
|
mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
|
||||||
self.assertEqual(mod.a, 1)
|
self.assertEqual(mod.a, 1)
|
||||||
|
|
||||||
mod = imp.load_compiled(
|
with warnings.catch_warnings():
|
||||||
temp_mod_name, imp.cache_from_source(temp_mod_name + '.py'))
|
warnings.simplefilter('ignore')
|
||||||
|
mod = imp.load_compiled(
|
||||||
|
temp_mod_name, imp.cache_from_source(temp_mod_name + '.py'))
|
||||||
self.assertEqual(mod.a, 1)
|
self.assertEqual(mod.a, 1)
|
||||||
|
|
||||||
if not os.path.exists(test_package_name):
|
if not os.path.exists(test_package_name):
|
||||||
os.mkdir(test_package_name)
|
os.mkdir(test_package_name)
|
||||||
with open(init_file_name, 'w') as file:
|
with open(init_file_name, 'w') as file:
|
||||||
file.write('b = 2\n')
|
file.write('b = 2\n')
|
||||||
package = imp.load_package(test_package_name, test_package_name)
|
with warnings.catch_warnings():
|
||||||
|
warnings.simplefilter('ignore')
|
||||||
|
package = imp.load_package(test_package_name, test_package_name)
|
||||||
self.assertEqual(package.b, 2)
|
self.assertEqual(package.b, 2)
|
||||||
finally:
|
finally:
|
||||||
del sys.path[0]
|
del sys.path[0]
|
||||||
|
|
|
@ -6,7 +6,7 @@ Tools directory of a Python checkout or tarball, such as reindent.py.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import imp
|
import importlib.machinery
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
import sysconfig
|
import sysconfig
|
||||||
|
@ -80,7 +80,8 @@ class PdepsTests(unittest.TestCase):
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpClass(self):
|
def setUpClass(self):
|
||||||
path = os.path.join(scriptsdir, 'pdeps.py')
|
path = os.path.join(scriptsdir, 'pdeps.py')
|
||||||
self.pdeps = imp.load_source('pdeps', path)
|
loader = importlib.machinery.SourceFileLoader('pdeps', path)
|
||||||
|
self.pdeps = loader.load_module()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def tearDownClass(self):
|
def tearDownClass(self):
|
||||||
|
@ -104,7 +105,8 @@ class Gprof2htmlTests(unittest.TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
path = os.path.join(scriptsdir, 'gprof2html.py')
|
path = os.path.join(scriptsdir, 'gprof2html.py')
|
||||||
self.gprof = imp.load_source('gprof2html', path)
|
loader = importlib.machinery.SourceFileLoader('gprof2html', path)
|
||||||
|
self.gprof = loader.load_module()
|
||||||
oldargv = sys.argv
|
oldargv = sys.argv
|
||||||
def fixup():
|
def fixup():
|
||||||
sys.argv = oldargv
|
sys.argv = oldargv
|
||||||
|
|
|
@ -23,6 +23,11 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #13959: Make importlib.abc.FileLoader.load_module()/get_filename() and
|
||||||
|
importlib.machinery.ExtensionFileLoader.load_module() have their single
|
||||||
|
argument be optional. Allows for the replacement (and thus deprecation) of
|
||||||
|
imp.load_source()/load_package()/load_compiled().
|
||||||
|
|
||||||
- Issue #13959: imp.get_suffixes() has been deprecated in favour of the new
|
- Issue #13959: imp.get_suffixes() has been deprecated in favour of the new
|
||||||
attributes on importlib.machinery: SOURCE_SUFFIXES, DEBUG_BYTECODE_SUFFIXES,
|
attributes on importlib.machinery: SOURCE_SUFFIXES, DEBUG_BYTECODE_SUFFIXES,
|
||||||
OPTIMIZED_BYTECODE_SUFFIXES, BYTECODE_SUFFIXES, and EXTENSION_SUFFIXES. This
|
OPTIMIZED_BYTECODE_SUFFIXES, BYTECODE_SUFFIXES, and EXTENSION_SUFFIXES. This
|
||||||
|
|
4695
Python/importlib.h
4695
Python/importlib.h
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue