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

Skip to content

Commit 100883f

Browse files
committed
Issue #17093,17566,17567: Methods from classes in importlib.abc now raise/return
the default exception/value when called instead of raising/returning NotimplementedError/NotImplemented (except where appropriate). This should allow for the ABCs to act as the bottom/end of the MRO with expected default results. As part of this work, also make importlib.abc.Loader.module_repr() optional instead of an abstractmethod.
1 parent 0f344b6 commit 100883f

7 files changed

Lines changed: 2317 additions & 2234 deletions

File tree

Doc/library/importlib.rst

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ ABC hierarchy::
153153
module. Originally specified in :pep:`302`, this method was meant
154154
for use in :data:`sys.meta_path` and in the path-based import subsystem.
155155

156+
.. versionchanged:: 3.4
157+
Returns ``None`` when called instead of raising
158+
:exc:`NotImplementedError`.
159+
156160

157161
.. class:: MetaPathFinder
158162

@@ -169,20 +173,27 @@ ABC hierarchy::
169173
will be the value of :attr:`__path__` from the parent
170174
package. If a loader cannot be found, ``None`` is returned.
171175

176+
.. versionchanged:: 3.4
177+
Returns ``None`` when called instead of raising
178+
:exc:`NotImplementedError`.
179+
172180
.. method:: invalidate_caches()
173181

174182
An optional method which, when called, should invalidate any internal
175183
cache used by the finder. Used by :func:`importlib.invalidate_caches`
176184
when invalidating the caches of all finders on :data:`sys.meta_path`.
177185

186+
.. versionchanged:: 3.4
187+
Returns ``None`` when called instead of ``NotImplemented``.
188+
178189

179190
.. class:: PathEntryFinder
180191

181192
An abstract base class representing a :term:`path entry finder`. Though
182193
it bears some similarities to :class:`MetaPathFinder`, ``PathEntryFinder``
183194
is meant for use only within the path-based import subsystem provided
184195
by :class:`PathFinder`. This ABC is a subclass of :class:`Finder` for
185-
compatibility.
196+
compatibility reasons only.
186197

187198
.. versionadded:: 3.3
188199

@@ -194,9 +205,12 @@ ABC hierarchy::
194205
package. The loader may be ``None`` while specifying ``portion`` to
195206
signify the contribution of the file system locations to a namespace
196207
package. An empty list can be used for ``portion`` to signify the loader
197-
is not part of a package. If ``loader`` is ``None`` and ``portion`` is
198-
the empty list then no loader or location for a namespace package were
199-
found (i.e. failure to find anything for the module).
208+
is not part of a namespace package. If ``loader`` is ``None`` and
209+
``portion`` is the empty list then no loader or location for a namespace
210+
package were found (i.e. failure to find anything for the module).
211+
212+
.. versionchanged:: 3.4
213+
Returns ``(None, [])`` instead of raising :exc:`NotImplementedError`.
200214

201215
.. method:: find_module(fullname):
202216

@@ -249,21 +263,29 @@ ABC hierarchy::
249263
- :attr:`__package__`
250264
The parent package for the module/package. If the module is
251265
top-level then it has a value of the empty string. The
252-
:func:`importlib.util.set_package` decorator can handle the details
253-
for :attr:`__package__`.
266+
:func:`importlib.util.module_for_loader` decorator can handle the
267+
details for :attr:`__package__`.
254268

255269
- :attr:`__loader__`
256-
The loader used to load the module.
257-
(This is not set by the built-in import machinery,
258-
but it should be set whenever a :term:`loader` is used.)
270+
The loader used to load the module. The
271+
:func:`importlib.util.module_for_loader` decorator can handle the
272+
details for :attr:`__package__`.
273+
274+
.. versionchanged:: 3.4
275+
Raise :exc:`ImportError` when called instead of
276+
:exc:`NotImplementedError`.
259277

260278
.. method:: module_repr(module)
261279

262-
An abstract method which when implemented calculates and returns the
263-
given module's repr, as a string.
280+
An optional method which when implemented calculates and returns the
281+
given module's repr, as a string. The module type's default repr() will
282+
use the result of this method as appropriate.
264283

265284
.. versionadded: 3.3
266285
286+
.. versionchanged:: 3.4
287+
Made optional instead of an abstractmethod.
288+
267289

268290
.. class:: ResourceLoader
269291

@@ -281,6 +303,9 @@ ABC hierarchy::
281303
be found. The *path* is expected to be constructed using a module's
282304
:attr:`__file__` attribute or an item from a package's :attr:`__path__`.
283305

306+
.. versionchanged:: 3.4
307+
Raises :exc:`IOError` instead of :exc:`NotImplementedError`.
308+
284309

285310
.. class:: InspectLoader
286311

@@ -297,6 +322,9 @@ ABC hierarchy::
297322
.. index::
298323
single: universal newlines; importlib.abc.InspectLoader.get_source method
299324

325+
.. versionchanged:: 3.4
326+
Raises :exc:`ImportError` instead of :exc:`NotImplementedError`.
327+
300328
.. method:: get_source(fullname)
301329

302330
An abstract method to return the source of a module. It is returned as
@@ -305,12 +333,18 @@ ABC hierarchy::
305333
if no source is available (e.g. a built-in module). Raises
306334
:exc:`ImportError` if the loader cannot find the module specified.
307335

336+
.. versionchanged:: 3.4
337+
Raises :exc:`ImportError` instead of :exc:`NotImplementedError`.
338+
308339
.. method:: is_package(fullname)
309340

310341
An abstract method to return a true value if the module is a package, a
311342
false value otherwise. :exc:`ImportError` is raised if the
312343
:term:`loader` cannot find the module.
313344

345+
.. versionchanged:: 3.4
346+
Raises :exc:`ImportError` instead of :exc:`NotImplementedError`.
347+
314348

315349
.. class:: ExecutionLoader
316350

@@ -328,6 +362,9 @@ ABC hierarchy::
328362
the source file, regardless of whether a bytecode was used to load the
329363
module.
330364

365+
.. versionchanged:: 3.4
366+
Raises :exc:`ImportError` instead of :exc:`NotImplementedError`.
367+
331368

332369
.. class:: FileLoader(fullname, path)
333370

@@ -392,10 +429,13 @@ ABC hierarchy::
392429
- ``'size'`` (optional): the size in bytes of the source code.
393430

394431
Any other keys in the dictionary are ignored, to allow for future
395-
extensions.
432+
extensions. If the path cannot be handled, :exc:`IOError` is raised.
396433

397434
.. versionadded:: 3.3
398435

436+
.. versionchanged:: 3.4
437+
Raise :exc:`IOError` instead of :exc:`NotImplementedError`.
438+
399439
.. method:: path_mtime(path)
400440

401441
Optional abstract method which returns the modification time for the
@@ -404,7 +444,10 @@ ABC hierarchy::
404444
.. deprecated:: 3.3
405445
This method is deprecated in favour of :meth:`path_stats`. You don't
406446
have to implement it, but it is still available for compatibility
407-
purposes.
447+
purposes. Raise :exc:`IOError` if the path cannot be handled.
448+
449+
.. versionchanged:: 3.4
450+
Raise :exc:`IOError` instead of :exc:`NotImplementedError`.
408451

409452
.. method:: set_data(path, data)
410453

@@ -415,6 +458,9 @@ ABC hierarchy::
415458
When writing to the path fails because the path is read-only
416459
(:attr:`errno.EACCES`), do not propagate the exception.
417460

461+
.. versionchanged:: 3.4
462+
No longer raises :exc:`NotImplementedError` when called.
463+
418464
.. method:: source_to_code(data, path)
419465

420466
Create a code object from Python source.

Lib/importlib/_bootstrap.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -893,8 +893,10 @@ class SourceLoader(_LoaderBasics):
893893
def path_mtime(self, path):
894894
"""Optional method that returns the modification time (an int) for the
895895
specified path, where path is a str.
896+
897+
Raises IOError when the path cannot be handled.
896898
"""
897-
raise NotImplementedError
899+
raise IOError
898900

899901
def path_stats(self, path):
900902
"""Optional method returning a metadata dict for the specified path
@@ -905,6 +907,7 @@ def path_stats(self, path):
905907
- 'size' (optional) is the size in bytes of the source code.
906908
907909
Implementing this method allows the loader to read bytecode files.
910+
Raises IOError when the path cannot be handled.
908911
"""
909912
return {'mtime': self.path_mtime(path)}
910913

@@ -922,9 +925,7 @@ def set_data(self, path, data):
922925
"""Optional method which writes data (bytes) to a file path (a str).
923926
924927
Implementing this method allows for the writing of bytecode files.
925-
926928
"""
927-
raise NotImplementedError
928929

929930

930931
def get_source(self, fullname):
@@ -973,7 +974,7 @@ def get_code(self, fullname):
973974
else:
974975
try:
975976
st = self.path_stats(source_path)
976-
except NotImplementedError:
977+
except IOError:
977978
pass
978979
else:
979980
source_mtime = int(st['mtime'])

Lib/importlib/abc.py

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ class Finder(metaclass=abc.ABCMeta):
3737
def find_module(self, fullname, path=None):
3838
"""An abstract method that should find a module.
3939
The fullname is a str and the optional path is a str or None.
40-
Returns a Loader object.
40+
Returns a Loader object or None.
4141
"""
42-
raise NotImplementedError
4342

4443

4544
class MetaPathFinder(Finder):
@@ -49,16 +48,14 @@ class MetaPathFinder(Finder):
4948
@abc.abstractmethod
5049
def find_module(self, fullname, path):
5150
"""Abstract method which, when implemented, should find a module.
52-
The fullname is a str and the path is a str or None.
53-
Returns a Loader object.
51+
The fullname is a str and the path is a list of strings or None.
52+
Returns a Loader object or None.
5453
"""
55-
raise NotImplementedError
5654

5755
def invalidate_caches(self):
5856
"""An optional method for clearing the finder's cache, if any.
5957
This method is used by importlib.invalidate_caches().
6058
"""
61-
return NotImplemented
6259

6360
_register(MetaPathFinder, machinery.BuiltinImporter, machinery.FrozenImporter,
6461
machinery.PathFinder, machinery.WindowsRegistryFinder)
@@ -70,39 +67,49 @@ class PathEntryFinder(Finder):
7067

7168
@abc.abstractmethod
7269
def find_loader(self, fullname):
73-
"""Abstract method which, when implemented, returns a module loader.
70+
"""Abstract method which, when implemented, returns a module loader or
71+
a possible part of a namespace.
7472
The fullname is a str. Returns a 2-tuple of (Loader, portion) where
7573
portion is a sequence of file system locations contributing to part of
7674
a namespace package. The sequence may be empty and the loader may be
7775
None.
7876
"""
79-
raise NotImplementedError
77+
return None, []
8078

8179
find_module = _bootstrap._find_module_shim
8280

8381
def invalidate_caches(self):
8482
"""An optional method for clearing the finder's cache, if any.
8583
This method is used by PathFinder.invalidate_caches().
8684
"""
87-
return NotImplemented
8885

8986
_register(PathEntryFinder, machinery.FileFinder)
9087

9188

9289
class Loader(metaclass=abc.ABCMeta):
9390

94-
"""Abstract base class for import loaders."""
91+
"""Abstract base class for import loaders.
92+
93+
The optional method module_repr(module) may be defined to provide a
94+
repr for a module when appropriate (see PEP 420). The __repr__() method on
95+
the module type will use the method as appropriate.
96+
97+
"""
9598

9699
@abc.abstractmethod
97100
def load_module(self, fullname):
98101
"""Abstract method which when implemented should load a module.
99-
The fullname is a str."""
100-
raise NotImplementedError
102+
The fullname is a str.
103+
104+
ImportError is raised on failure.
105+
"""
106+
raise ImportError
101107

102-
@abc.abstractmethod
103108
def module_repr(self, module):
104-
"""Abstract method which when implemented calculates and returns the
105-
given module's repr."""
109+
"""Return a module's repr.
110+
111+
Used by the module type when implemented without raising an exception.
112+
"""
106113
raise NotImplementedError
107114

108115

@@ -119,7 +126,7 @@ class ResourceLoader(Loader):
119126
def get_data(self, path):
120127
"""Abstract method which when implemented should return the bytes for
121128
the specified path. The path must be a str."""
122-
raise NotImplementedError
129+
raise IOError
123130

124131

125132
class InspectLoader(Loader):
@@ -134,20 +141,29 @@ class InspectLoader(Loader):
134141
@abc.abstractmethod
135142
def is_package(self, fullname):
136143
"""Abstract method which when implemented should return whether the
137-
module is a package. The fullname is a str. Returns a bool."""
138-
raise NotImplementedError
144+
module is a package. The fullname is a str. Returns a bool.
145+
146+
Raises ImportError is the module cannot be found.
147+
"""
148+
raise ImportError
139149

140150
@abc.abstractmethod
141151
def get_code(self, fullname):
142152
"""Abstract method which when implemented should return the code object
143-
for the module. The fullname is a str. Returns a types.CodeType."""
144-
raise NotImplementedError
153+
for the module. The fullname is a str. Returns a types.CodeType.
154+
155+
Raises ImportError if the module cannot be found.
156+
"""
157+
raise ImportError
145158

146159
@abc.abstractmethod
147160
def get_source(self, fullname):
148161
"""Abstract method which should return the source code for the
149-
module. The fullname is a str. Returns a str."""
150-
raise NotImplementedError
162+
module. The fullname is a str. Returns a str.
163+
164+
Raises ImportError if the module cannot be found.
165+
"""
166+
raise ImportError
151167

152168
_register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter,
153169
machinery.ExtensionFileLoader)
@@ -165,8 +181,11 @@ class ExecutionLoader(InspectLoader):
165181
@abc.abstractmethod
166182
def get_filename(self, fullname):
167183
"""Abstract method which should return the value that __file__ is to be
168-
set to."""
169-
raise NotImplementedError
184+
set to.
185+
186+
Raises ImportError if the module cannot be found.
187+
"""
188+
raise ImportError
170189

171190

172191
class FileLoader(_bootstrap.FileLoader, ResourceLoader, ExecutionLoader):
@@ -198,7 +217,7 @@ class SourceLoader(_bootstrap.SourceLoader, ResourceLoader, ExecutionLoader):
198217
def path_mtime(self, path):
199218
"""Return the (int) modification time for the path (str)."""
200219
if self.path_stats.__func__ is SourceLoader.path_stats:
201-
raise NotImplementedError
220+
raise IOError
202221
return int(self.path_stats(path)['mtime'])
203222

204223
def path_stats(self, path):
@@ -209,7 +228,7 @@ def path_stats(self, path):
209228
- 'size' (optional) is the size in bytes of the source code.
210229
"""
211230
if self.path_mtime.__func__ is SourceLoader.path_mtime:
212-
raise NotImplementedError
231+
raise IOError
213232
return {'mtime': self.path_mtime(path)}
214233

215234
def set_data(self, path, data):
@@ -220,8 +239,6 @@ def set_data(self, path, data):
220239
Any needed intermediary directories are to be created. If for some
221240
reason the file cannot be written because of permissions, fail
222241
silently.
223-
224242
"""
225-
raise NotImplementedError
226243

227244
_register(SourceLoader, machinery.SourceFileLoader)

0 commit comments

Comments
 (0)