3
3
import os
4
4
import sys
5
5
import imp
6
+ import importlib
6
7
import os .path
8
+ from warnings import warn
7
9
from types import ModuleType
8
10
9
11
__all__ = [
@@ -168,6 +170,8 @@ class ImpImporter:
168
170
"""
169
171
170
172
def __init__ (self , path = None ):
173
+ warn ("This emulation is deprecated, use 'importlib' instead" ,
174
+ DeprecationWarning )
171
175
self .path = path
172
176
173
177
def find_module (self , fullname , path = None ):
@@ -232,6 +236,8 @@ class ImpLoader:
232
236
code = source = None
233
237
234
238
def __init__ (self , fullname , file , filename , etc ):
239
+ warn ("This emulation is deprecated, use 'importlib' instead" ,
240
+ DeprecationWarning )
235
241
self .file = file
236
242
self .filename = filename
237
243
self .fullname = fullname
@@ -366,10 +372,6 @@ def get_importer(path_item):
366
372
The returned importer is cached in sys.path_importer_cache
367
373
if it was newly created by a path hook.
368
374
369
- If there is no importer, a wrapper around the basic import
370
- machinery is returned. This wrapper is never inserted into
371
- the importer cache (None is inserted instead).
372
-
373
375
The cache (or part of it) can be cleared manually if a
374
376
rescan of sys.path_hooks is necessary.
375
377
"""
@@ -384,66 +386,45 @@ def get_importer(path_item):
384
386
except ImportError :
385
387
pass
386
388
else :
387
- try :
388
- importer = ImpImporter (path_item )
389
- except ImportError :
390
- importer = None
389
+ importer = None
391
390
return importer
392
391
393
392
394
393
def iter_importers (fullname = "" ):
395
394
"""Yield PEP 302 importers for the given module name
396
395
397
396
If fullname contains a '.', the importers will be for the package
398
- containing fullname, otherwise they will be importers for sys.meta_path,
399
- sys.path, and Python's "classic" import machinery, in that order. If
400
- the named module is in a package, that package is imported as a side
401
- effect of invoking this function.
397
+ containing fullname, otherwise they will be all registered top level
398
+ importers (i.e. those on both sys.meta_path and sys.path_hooks).
402
399
403
- Non PEP 302 mechanisms (e.g. the Windows registry) used by the
404
- standard import machinery to find files in alternative locations
405
- are partially supported, but are searched AFTER sys.path. Normally,
406
- these locations are searched BEFORE sys.path, preventing sys.path
407
- entries from shadowing them.
408
-
409
- For this to cause a visible difference in behaviour, there must
410
- be a module or package name that is accessible via both sys.path
411
- and one of the non PEP 302 file system mechanisms. In this case,
412
- the emulation will find the former version, while the builtin
413
- import mechanism will find the latter.
400
+ If the named module is in a package, that package is imported as a side
401
+ effect of invoking this function.
414
402
415
- Items of the following types can be affected by this discrepancy:
416
- imp.C_EXTENSION, imp.PY_SOURCE, imp.PY_COMPILED, imp.PKG_DIRECTORY
403
+ If no module name is specified, all top level importers are produced.
417
404
"""
418
405
if fullname .startswith ('.' ):
419
- raise ImportError ("Relative module names not supported" )
406
+ msg = "Relative module name {!r} not supported" .format (fullname )
407
+ raise ImportError (msg )
420
408
if '.' in fullname :
421
409
# Get the containing package's __path__
422
- pkg = '.' .join (fullname .split ('.' )[:- 1 ])
423
- if pkg not in sys .modules :
424
- __import__ (pkg )
425
- path = getattr (sys .modules [pkg ], '__path__' , None ) or []
410
+ pkg_name = fullname .rpartition ("." )[0 ]
411
+ pkg = importlib .import_module (pkg )
412
+ path = getattr (sys .modules [pkg ], '__path__' , None )
413
+ if path is None :
414
+ return
426
415
else :
427
416
for importer in sys .meta_path :
428
417
yield importer
429
418
path = sys .path
430
419
for item in path :
431
420
yield get_importer (item )
432
- if '.' not in fullname :
433
- yield ImpImporter ()
434
421
435
422
def get_loader (module_or_name ):
436
423
"""Get a PEP 302 "loader" object for module_or_name
437
424
438
- If the module or package is accessible via the normal import
439
- mechanism, a wrapper around the relevant part of that machinery
440
- is returned. Returns None if the module cannot be found or imported.
425
+ Returns None if the module cannot be found or imported.
441
426
If the named module is not already imported, its containing package
442
427
(if any) is imported, in order to establish the package __path__.
443
-
444
- This function uses iter_importers(), and is thus subject to the same
445
- limitations regarding platform-specific special import locations such
446
- as the Windows registry.
447
428
"""
448
429
if module_or_name in sys .modules :
449
430
module_or_name = sys .modules [module_or_name ]
@@ -457,22 +438,33 @@ def get_loader(module_or_name):
457
438
fullname = module_or_name
458
439
return find_loader (fullname )
459
440
441
+
460
442
def find_loader (fullname ):
461
443
"""Find a PEP 302 "loader" object for fullname
462
444
463
- If fullname contains dots, path must be the containing package's __path__.
464
- Returns None if the module cannot be found or imported. This function uses
465
- iter_importers(), and is thus subject to the same limitations regarding
466
- platform-specific special import locations such as the Windows registry .
445
+ This is s convenience wrapper around :func:`importlib.find_loader` that
446
+ sets the *path* argument correctly when searching for submodules, and
447
+ also ensures parent packages (if any) are imported before searching for
448
+ submodules .
467
449
"""
468
- for importer in iter_importers (fullname ):
469
- if importer is None :
470
- continue
471
- loader = importer .find_module (fullname )
472
- if loader is not None :
473
- return loader
474
-
475
- return None
450
+ if fullname .startswith ('.' ):
451
+ msg = "Relative module name {!r} not supported" .format (fullname )
452
+ raise ImportError (msg )
453
+ path = None
454
+ pkg_name = fullname .rpartition ("." )[0 ]
455
+ if pkg_name :
456
+ pkg = importlib .import_module (pkg_name )
457
+ path = getattr (pkg , "__path__" , None )
458
+ if path is None :
459
+ return None
460
+ try :
461
+ return importlib .find_loader (fullname , path )
462
+ except (ImportError , AttributeError , TypeError , ValueError ) as ex :
463
+ # This hack fixes an impedance mismatch between pkgutil and
464
+ # importlib, where the latter throws other errors for cases where
465
+ # pkgutil previously threw ImportError
466
+ msg = "Error while finding loader for {!r} ({}: {})"
467
+ raise ImportError (msg .format (fullname , type (ex ), ex )) from ex
476
468
477
469
478
470
def extend_path (path , name ):
0 commit comments