Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c049952

Browse files
committed
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().
1 parent 0c59b03 commit c049952

9 files changed

Lines changed: 2459 additions & 2366 deletions

File tree

Doc/library/importlib.rst

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,9 +256,14 @@ are also provided to help in implementing the core ABCs.
256256

257257
Path to the file of the module.
258258

259+
.. method:: load_module(fullname=None)
260+
261+
Calls
262+
``super().load_module(fullname if fullname is not None else self.name)``.
263+
259264
.. method:: get_filename(fullname)
260265

261-
Returns :attr:`path`.
266+
Returns :attr:`path` when ``fullname`` equals :attr:`name` or ``None``.
262267

263268
.. method:: get_data(path)
264269

@@ -638,10 +643,6 @@ find and load modules.
638643

639644
Concrete implementation of :meth:`importlib.abc.SourceLoader.set_data`.
640645

641-
.. method:: load_module(fullname)
642-
643-
Load the specified module if it is the same as :attr:`name`.
644-
645646

646647
.. class:: SourcelessFileLoader(fullname, path)
647648

@@ -676,10 +677,6 @@ find and load modules.
676677
Returns ``None`` as bytecode files have no source when this loader is
677678
used.
678679

679-
.. method:: load_module(fullname)
680-
681-
Loads the specified module if it is the same as :attr:`name`.
682-
683680

684681
.. class:: ExtensionFileLoader(fullname, path)
685682

@@ -699,10 +696,10 @@ find and load modules.
699696

700697
Path to the extension module.
701698

702-
.. method:: load_module(fullname)
699+
.. method:: load_module(fullname=None)
703700

704-
Loads the extension module if and only if *fullname** is the same as
705-
:attr:`name`.
701+
Loads the extension module if and only if *fullname* is the same as
702+
:attr:`name` or is ``None``.
706703

707704
.. method:: is_package(fullname)
708705

Lib/imp.py

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
import warnings
2525

2626

27-
# XXX "deprecate" once find_module(), load_module(), and get_suffixes() are
28-
# deprecated.
27+
# DEPRECATED
2928
SEARCH_ERROR = 0
3029
PY_SOURCE = 1
3130
PY_COMPILED = 2
@@ -112,8 +111,11 @@ class _LoadSourceCompatibility(_HackedGetData, _bootstrap.SourceFileLoader):
112111
"""Compatibility support for implementing load_source()."""
113112

114113

115-
# XXX deprecate after better API exposed in importlib
116114
def load_source(name, pathname, file=None):
115+
msg = ('imp.load_source() is deprecated; use '
116+
'importlib.machinery.SourceFileLoader(name, pathname).load_module()'
117+
' instead')
118+
warnings.warn(msg, DeprecationWarning, 2)
117119
return _LoadSourceCompatibility(name, pathname, file).load_module(name)
118120

119121

@@ -123,15 +125,22 @@ class _LoadCompiledCompatibility(_HackedGetData,
123125
"""Compatibility support for implementing load_compiled()."""
124126

125127

126-
# XXX deprecate
127128
def load_compiled(name, pathname, file=None):
129+
msg = ('imp.load_compiled() is deprecated; use '
130+
'importlib.machinery.SourcelessFileLoader(name, pathname).'
131+
'load_module() instead ')
132+
warnings.warn(msg, DeprecationWarning, 2)
128133
return _LoadCompiledCompatibility(name, pathname, file).load_module(name)
129134

130135

131-
# XXX deprecate
132136
def load_package(name, path):
137+
msg = ('imp.load_package() is deprecated; use either '
138+
'importlib.machinery.SourceFileLoader() or '
139+
'importlib.machinery.SourcelessFileLoader() instead')
140+
warnings.warn(msg, DeprecationWarning, 2)
133141
if os.path.isdir(path):
134-
extensions = machinery.SOURCE_SUFFIXES[:] + [machinery.BYTECODE_SUFFIXES]
142+
extensions = (machinery.SOURCE_SUFFIXES[:] +
143+
machinery.BYTECODE_SUFFIXES[:])
135144
for extension in extensions:
136145
path = os.path.join(path, '__init__'+extension)
137146
if os.path.exists(path):
@@ -149,26 +158,29 @@ def load_module(name, file, filename, details):
149158
150159
"""
151160
suffix, mode, type_ = details
152-
if mode and (not mode.startswith(('r', 'U')) or '+' in mode):
153-
raise ValueError('invalid file open mode {!r}'.format(mode))
154-
elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
155-
msg = 'file object required for import (type code {})'.format(type_)
156-
raise ValueError(msg)
157-
elif type_ == PY_SOURCE:
158-
return load_source(name, filename, file)
159-
elif type_ == PY_COMPILED:
160-
return load_compiled(name, filename, file)
161-
elif type_ == PKG_DIRECTORY:
162-
return load_package(name, filename)
163-
elif type_ == C_BUILTIN:
164-
return init_builtin(name)
165-
elif type_ == PY_FROZEN:
166-
return init_frozen(name)
167-
else:
168-
msg = "Don't know how to import {} (type code {}".format(name, type_)
169-
raise ImportError(msg, name=name)
161+
with warnings.catch_warnings():
162+
warnings.simplefilter('ignore')
163+
if mode and (not mode.startswith(('r', 'U')) or '+' in mode):
164+
raise ValueError('invalid file open mode {!r}'.format(mode))
165+
elif file is None and type_ in {PY_SOURCE, PY_COMPILED}:
166+
msg = 'file object required for import (type code {})'.format(type_)
167+
raise ValueError(msg)
168+
elif type_ == PY_SOURCE:
169+
return load_source(name, filename, file)
170+
elif type_ == PY_COMPILED:
171+
return load_compiled(name, filename, file)
172+
elif type_ == PKG_DIRECTORY:
173+
return load_package(name, filename)
174+
elif type_ == C_BUILTIN:
175+
return init_builtin(name)
176+
elif type_ == PY_FROZEN:
177+
return init_frozen(name)
178+
else:
179+
msg = "Don't know how to import {} (type code {}".format(name, type_)
180+
raise ImportError(msg, name=name)
170181

171182

183+
# XXX deprecate
172184
def find_module(name, path=None):
173185
"""Search for a module.
174186

Lib/importlib/_bootstrap.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,10 @@ def _check_name(method):
282282
compared against. If the comparison fails then ImportError is raised.
283283
284284
"""
285-
def _check_name_wrapper(self, name, *args, **kwargs):
286-
if self.name != name:
285+
def _check_name_wrapper(self, name=None, *args, **kwargs):
286+
if name is None:
287+
name = self.name
288+
elif self.name != name:
287289
raise ImportError("loader cannot handle %s" % name, name=name)
288290
return method(self, name, *args, **kwargs)
289291
_wrap(_check_name_wrapper, method)
@@ -613,6 +615,11 @@ def __init__(self, fullname, path):
613615
self.name = fullname
614616
self.path = path
615617

618+
@_check_name
619+
def load_module(self, fullname):
620+
"""Load a module from a file."""
621+
return super().load_module(fullname)
622+
616623
@_check_name
617624
def get_filename(self, fullname):
618625
"""Return the path to the source file as found by the finder."""
@@ -713,17 +720,14 @@ def load_module(self, fullname):
713720
del sys.modules[fullname]
714721
raise
715722

716-
@_check_name
717723
def is_package(self, fullname):
718724
"""Return False as an extension module can never be a package."""
719725
return False
720726

721-
@_check_name
722727
def get_code(self, fullname):
723728
"""Return None as an extension module cannot create a code object."""
724729
return None
725730

726-
@_check_name
727731
def get_source(self, fullname):
728732
"""Return None as extension modules have no source code."""
729733
return None

Lib/importlib/test/extension/test_loader.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from importlib import _bootstrap
1+
from importlib import machinery
22
from . import util as ext_util
33
from .. import abc
44
from .. import util
@@ -11,10 +11,20 @@ class LoaderTests(abc.LoaderTests):
1111

1212
"""Test load_module() for extension modules."""
1313

14+
def setUp(self):
15+
self.loader = machinery.ExtensionFileLoader(ext_util.NAME,
16+
ext_util.FILEPATH)
17+
1418
def load_module(self, fullname):
15-
loader = _bootstrap.ExtensionFileLoader(ext_util.NAME,
16-
ext_util.FILEPATH)
17-
return loader.load_module(fullname)
19+
return self.loader.load_module(fullname)
20+
21+
def test_load_module_API(self):
22+
# Test the default argument for load_module().
23+
self.loader.load_module()
24+
self.loader.load_module(None)
25+
with self.assertRaises(ImportError):
26+
self.load_module('XXX')
27+
1828

1929
def test_module(self):
2030
with util.uncache(ext_util.NAME):
@@ -25,7 +35,7 @@ def test_module(self):
2535
self.assertEqual(getattr(module, attr), value)
2636
self.assertTrue(ext_util.NAME in sys.modules)
2737
self.assertTrue(isinstance(module.__loader__,
28-
_bootstrap.ExtensionFileLoader))
38+
machinery.ExtensionFileLoader))
2939

3040
def test_package(self):
3141
# Extensions are not found in packages.

Lib/importlib/test/source/test_file_loader.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from ... import _bootstrap
22
import importlib
3+
import importlib.abc
34
from .. import abc
45
from .. import util
56
from . import util as source_util
@@ -24,6 +25,40 @@ class SimpleTest(unittest.TestCase):
2425
2526
"""
2627

28+
def test_load_module_API(self):
29+
# If fullname is not specified that assume self.name is desired.
30+
class TesterMixin(importlib.abc.Loader):
31+
def load_module(self, fullname): return fullname
32+
33+
class Tester(importlib.abc.FileLoader, TesterMixin):
34+
def get_code(self, _): pass
35+
def get_source(self, _): pass
36+
def is_package(self, _): pass
37+
38+
name = 'mod_name'
39+
loader = Tester(name, 'some_path')
40+
self.assertEqual(name, loader.load_module())
41+
self.assertEqual(name, loader.load_module(None))
42+
self.assertEqual(name, loader.load_module(name))
43+
with self.assertRaises(ImportError):
44+
loader.load_module(loader.name + 'XXX')
45+
46+
def test_get_filename_API(self):
47+
# If fullname is not set then assume self.path is desired.
48+
class Tester(importlib.abc.FileLoader):
49+
def get_code(self, _): pass
50+
def get_source(self, _): pass
51+
def is_package(self, _): pass
52+
53+
path = 'some_path'
54+
name = 'some_name'
55+
loader = Tester(name, path)
56+
self.assertEqual(path, loader.get_filename(name))
57+
self.assertEqual(path, loader.get_filename())
58+
self.assertEqual(path, loader.get_filename(None))
59+
with self.assertRaises(ImportError):
60+
loader.get_filename(name + 'XXX')
61+
2762
# [basic]
2863
def test_module(self):
2964
with source_util.create_modules('_temp') as mapping:

Lib/test/test_imp.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import imp
2+
import importlib
23
import os
34
import os.path
45
import shutil
56
import sys
6-
import unittest
77
from test import support
8-
import importlib
8+
import unittest
9+
import warnings
910

1011
class LockTests(unittest.TestCase):
1112

@@ -154,18 +155,24 @@ def test_issue5604(self):
154155
mod = imp.load_module(temp_mod_name, file, filename, info)
155156
self.assertEqual(mod.a, 1)
156157

157-
mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
158+
with warnings.catch_warnings():
159+
warnings.simplefilter('ignore')
160+
mod = imp.load_source(temp_mod_name, temp_mod_name + '.py')
158161
self.assertEqual(mod.a, 1)
159162

160-
mod = imp.load_compiled(
161-
temp_mod_name, imp.cache_from_source(temp_mod_name + '.py'))
163+
with warnings.catch_warnings():
164+
warnings.simplefilter('ignore')
165+
mod = imp.load_compiled(
166+
temp_mod_name, imp.cache_from_source(temp_mod_name + '.py'))
162167
self.assertEqual(mod.a, 1)
163168

164169
if not os.path.exists(test_package_name):
165170
os.mkdir(test_package_name)
166171
with open(init_file_name, 'w') as file:
167172
file.write('b = 2\n')
168-
package = imp.load_package(test_package_name, test_package_name)
173+
with warnings.catch_warnings():
174+
warnings.simplefilter('ignore')
175+
package = imp.load_package(test_package_name, test_package_name)
169176
self.assertEqual(package.b, 2)
170177
finally:
171178
del sys.path[0]

Lib/test/test_tools.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import os
88
import sys
9-
import imp
9+
import importlib.machinery
1010
import unittest
1111
from unittest import mock
1212
import sysconfig
@@ -80,7 +80,8 @@ class PdepsTests(unittest.TestCase):
8080
@classmethod
8181
def setUpClass(self):
8282
path = os.path.join(scriptsdir, 'pdeps.py')
83-
self.pdeps = imp.load_source('pdeps', path)
83+
loader = importlib.machinery.SourceFileLoader('pdeps', path)
84+
self.pdeps = loader.load_module()
8485

8586
@classmethod
8687
def tearDownClass(self):
@@ -104,7 +105,8 @@ class Gprof2htmlTests(unittest.TestCase):
104105

105106
def setUp(self):
106107
path = os.path.join(scriptsdir, 'gprof2html.py')
107-
self.gprof = imp.load_source('gprof2html', path)
108+
loader = importlib.machinery.SourceFileLoader('gprof2html', path)
109+
self.gprof = loader.load_module()
108110
oldargv = sys.argv
109111
def fixup():
110112
sys.argv = oldargv

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ Core and Builtins
2323
Library
2424
-------
2525

26+
- Issue #13959: Make importlib.abc.FileLoader.load_module()/get_filename() and
27+
importlib.machinery.ExtensionFileLoader.load_module() have their single
28+
argument be optional. Allows for the replacement (and thus deprecation) of
29+
imp.load_source()/load_package()/load_compiled().
30+
2631
- Issue #13959: imp.get_suffixes() has been deprecated in favour of the new
2732
attributes on importlib.machinery: SOURCE_SUFFIXES, DEBUG_BYTECODE_SUFFIXES,
2833
OPTIMIZED_BYTECODE_SUFFIXES, BYTECODE_SUFFIXES, and EXTENSION_SUFFIXES. This

0 commit comments

Comments
 (0)