@@ -173,7 +173,13 @@ def inner(self, name, *args, **kwargs):
173173 return inner
174174
175175
176- # Finders/loaders #############################################################
176+ def _suffix_list (suffix_type ):
177+ """Return a list of file suffixes based on the imp file type."""
178+ return [suffix [0 ] for suffix in imp .get_suffixes ()
179+ if suffix [2 ] == suffix_type ]
180+
181+
182+ # Loaders #####################################################################
177183
178184class BuiltinImporter :
179185
@@ -241,100 +247,6 @@ def load_module(cls, fullname):
241247 raise
242248
243249
244- def _chained_path_hook (* path_hooks ):
245- """Create a closure which sequentially checks path hooks to see which ones
246- (if any) can work with a path."""
247- def path_hook (entry ):
248- """Check to see if 'entry' matches any of the enclosed path hooks."""
249- finders = []
250- for hook in path_hooks :
251- try :
252- finder = hook (entry )
253- except ImportError :
254- continue
255- else :
256- finders .append (finder )
257- if not finders :
258- raise ImportError ("no finder found" )
259- else :
260- return _ChainedFinder (* finders )
261-
262- return path_hook
263-
264-
265- class _ChainedFinder :
266-
267- """Finder that sequentially calls other finders."""
268-
269- def __init__ (self , * finders ):
270- self ._finders = finders
271-
272- def find_module (self , fullname , path = None ):
273- for finder in self ._finders :
274- result = finder .find_module (fullname , path )
275- if result :
276- return result
277- else :
278- return None
279-
280-
281-
282- class _ExtensionFileLoader :
283-
284- """Loader for extension modules.
285-
286- The constructor is designed to work with FileFinder.
287-
288- """
289-
290- def __init__ (self , name , path , is_pkg ):
291- """Initialize the loader.
292-
293- If is_pkg is True then an exception is raised as extension modules
294- cannot be the __init__ module for an extension module.
295-
296- """
297- self ._name = name
298- self ._path = path
299- if is_pkg :
300- raise ValueError ("extension modules cannot be packages" )
301-
302- @_check_name
303- @set_package
304- @set_loader
305- def load_module (self , fullname ):
306- """Load an extension module."""
307- is_reload = fullname in sys .modules
308- try :
309- return imp .load_dynamic (fullname , self ._path )
310- except :
311- if not is_reload and fullname in sys .modules :
312- del sys .modules [fullname ]
313- raise
314-
315- @_check_name
316- def is_package (self , fullname ):
317- """Return False as an extension module can never be a package."""
318- return False
319-
320- @_check_name
321- def get_code (self , fullname ):
322- """Return None as an extension module cannot create a code object."""
323- return None
324-
325- @_check_name
326- def get_source (self , fullname ):
327- """Return None as extension modules have no source code."""
328- return None
329-
330-
331- def _suffix_list (suffix_type ):
332- """Return a list of file suffixes based on the imp file type."""
333- return [suffix [0 ] for suffix in imp .get_suffixes ()
334- if suffix [2 ] == suffix_type ]
335-
336-
337-
338250class PyLoader :
339251
340252 """Loader base class for Python source.
@@ -584,6 +496,136 @@ def write_bytecode(self, name, data):
584496 raise
585497
586498
499+ class _ExtensionFileLoader :
500+
501+ """Loader for extension modules.
502+
503+ The constructor is designed to work with FileFinder.
504+
505+ """
506+
507+ def __init__ (self , name , path , is_pkg ):
508+ """Initialize the loader.
509+
510+ If is_pkg is True then an exception is raised as extension modules
511+ cannot be the __init__ module for an extension module.
512+
513+ """
514+ self ._name = name
515+ self ._path = path
516+ if is_pkg :
517+ raise ValueError ("extension modules cannot be packages" )
518+
519+ @_check_name
520+ @set_package
521+ @set_loader
522+ def load_module (self , fullname ):
523+ """Load an extension module."""
524+ is_reload = fullname in sys .modules
525+ try :
526+ return imp .load_dynamic (fullname , self ._path )
527+ except :
528+ if not is_reload and fullname in sys .modules :
529+ del sys .modules [fullname ]
530+ raise
531+
532+ @_check_name
533+ def is_package (self , fullname ):
534+ """Return False as an extension module can never be a package."""
535+ return False
536+
537+ @_check_name
538+ def get_code (self , fullname ):
539+ """Return None as an extension module cannot create a code object."""
540+ return None
541+
542+ @_check_name
543+ def get_source (self , fullname ):
544+ """Return None as extension modules have no source code."""
545+ return None
546+
547+
548+ # Finders #####################################################################
549+
550+ class PathFinder :
551+
552+ """Meta path finder for sys.(path|path_hooks|path_importer_cache)."""
553+
554+ @classmethod
555+ def _path_hooks (cls , path , hooks = None ):
556+ """Search sequence of hooks for a finder for 'path'.
557+
558+ If 'hooks' is false then use sys.path_hooks.
559+
560+ """
561+ if not hooks :
562+ hooks = sys .path_hooks
563+ for hook in hooks :
564+ try :
565+ return hook (path )
566+ except ImportError :
567+ continue
568+ else :
569+ raise ImportError ("no path hook found for {0}" .format (path ))
570+
571+ @classmethod
572+ def _path_importer_cache (cls , path , default = None ):
573+ """Get the finder for the path from sys.path_importer_cache.
574+
575+ If the path is not in the cache, find the appropriate finder and cache
576+ it. If None is cached, get the default finder and cache that
577+ (if applicable).
578+
579+ Because of NullImporter, some finder should be returned. The only
580+ explicit fail case is if None is cached but the path cannot be used for
581+ the default hook, for which ImportError is raised.
582+
583+ """
584+ try :
585+ finder = sys .path_importer_cache [path ]
586+ except KeyError :
587+ finder = cls ._path_hooks (path )
588+ sys .path_importer_cache [path ] = finder
589+ else :
590+ if finder is None and default :
591+ # Raises ImportError on failure.
592+ finder = default (path )
593+ sys .path_importer_cache [path ] = finder
594+ return finder
595+
596+ @classmethod
597+ def find_module (cls , fullname , path = None ):
598+ """Find the module on sys.path or 'path'."""
599+ if not path :
600+ path = sys .path
601+ for entry in path :
602+ try :
603+ finder = cls ._path_importer_cache (entry )
604+ except ImportError :
605+ continue
606+ loader = finder .find_module (fullname )
607+ if loader :
608+ return loader
609+ else :
610+ return None
611+
612+
613+ class _ChainedFinder :
614+
615+ """Finder that sequentially calls other finders."""
616+
617+ def __init__ (self , * finders ):
618+ self ._finders = finders
619+
620+ def find_module (self , fullname , path = None ):
621+ for finder in self ._finders :
622+ result = finder .find_module (fullname , path )
623+ if result :
624+ return result
625+ else :
626+ return None
627+
628+
587629class FileFinder :
588630
589631 """Base class for file finders.
@@ -643,20 +685,6 @@ def find_module(self, fullname, path=None):
643685 return None
644686
645687
646- class ExtensionFileFinder (FileFinder ):
647-
648- """Importer for extension files."""
649-
650- _possible_package = False
651- _loader = _ExtensionFileLoader
652-
653- def __init__ (self , path_entry ):
654- # Assigning to _suffixes here instead of at the class level because
655- # imp is not imported at the time of class creation.
656- self ._suffixes = _suffix_list (imp .C_EXTENSION )
657- super ().__init__ (path_entry )
658-
659-
660688class PyFileFinder (FileFinder ):
661689
662690 """Importer for source/bytecode files."""
@@ -683,82 +711,43 @@ def __init__(self, path_entry):
683711 self ._suffixes += _suffix_list (imp .PY_COMPILED )
684712
685713
686- class PathFinder :
687714
688- """Meta path finder for sys.(path|path_hooks|path_importer_cache)."""
689715
690- @classmethod
691- def _path_hooks (cls , path , hooks = None ):
692- """Search sequence of hooks for a finder for 'path'.
693-
694- If 'hooks' is false then use sys.path_hooks.
716+ class ExtensionFileFinder (FileFinder ):
695717
696- """
697- if not hooks :
698- hooks = sys .path_hooks
699- for hook in hooks :
700- try :
701- return hook (path )
702- except ImportError :
703- continue
704- else :
705- raise ImportError ("no path hook found for {0}" .format (path ))
718+ """Importer for extension files."""
706719
707- @classmethod
708- def _path_importer_cache (cls , path , default = None ):
709- """Get the finder for the path from sys.path_importer_cache.
720+ _possible_package = False
721+ _loader = _ExtensionFileLoader
710722
711- If the path is not in the cache, find the appropriate finder and cache
712- it. If None is cached, get the default finder and cache that
713- (if applicable).
723+ def __init__ (self , path_entry ):
724+ # Assigning to _suffixes here instead of at the class level because
725+ # imp is not imported at the time of class creation.
726+ self ._suffixes = _suffix_list (imp .C_EXTENSION )
727+ super ().__init__ (path_entry )
714728
715- Because of NullImporter, some finder should be returned. The only
716- explicit fail case is if None is cached but the path cannot be used for
717- the default hook, for which ImportError is raised.
718729
719- """
720- try :
721- finder = sys .path_importer_cache [path ]
722- except KeyError :
723- finder = cls ._path_hooks (path )
724- sys .path_importer_cache [path ] = finder
725- else :
726- if finder is None and default :
727- # Raises ImportError on failure.
728- finder = default (path )
729- sys .path_importer_cache [path ] = finder
730- return finder
730+ # Import itself ###############################################################
731731
732- @classmethod
733- def find_module (cls , fullname , path = None ):
734- """Find the module on sys.path or 'path'."""
735- if not path :
736- path = sys .path
737- for entry in path :
732+ def _chained_path_hook (* path_hooks ):
733+ """Create a closure which sequentially checks path hooks to see which ones
734+ (if any) can work with a path."""
735+ def path_hook (entry ):
736+ """Check to see if 'entry' matches any of the enclosed path hooks."""
737+ finders = []
738+ for hook in path_hooks :
738739 try :
739- finder = cls . _path_importer_cache (entry )
740+ finder = hook (entry )
740741 except ImportError :
741742 continue
742- loader = finder .find_module (fullname )
743- if loader :
744- return loader
743+ else :
744+ finders .append (finder )
745+ if not finders :
746+ raise ImportError ("no finder found" )
745747 else :
746- return None
747-
748-
749- # Import itself ###############################################################
750-
751- class _ImportLockContext :
752-
753- """Context manager for the import lock."""
754-
755- def __enter__ (self ):
756- """Acquire the import lock."""
757- imp .acquire_lock ()
748+ return _ChainedFinder (* finders )
758749
759- def __exit__ (self , exc_type , exc_value , exc_traceback ):
760- """Release the import lock regardless of any raised exceptions."""
761- imp .release_lock ()
750+ return path_hook
762751
763752
764753_DEFAULT_PATH_HOOK = _chained_path_hook (ExtensionFileFinder , PyPycFileFinder )
@@ -784,6 +773,18 @@ def _path_importer_cache(cls, path):
784773 return super ()._path_importer_cache (path , _DEFAULT_PATH_HOOK )
785774
786775
776+ class _ImportLockContext :
777+
778+ """Context manager for the import lock."""
779+
780+ def __enter__ (self ):
781+ """Acquire the import lock."""
782+ imp .acquire_lock ()
783+
784+ def __exit__ (self , exc_type , exc_value , exc_traceback ):
785+ """Release the import lock regardless of any raised exceptions."""
786+ imp .release_lock ()
787+
787788
788789_IMPLICIT_META_PATH = [BuiltinImporter , FrozenImporter , _DefaultPathFinder ]
789790
0 commit comments