hgdemandimport/demandimportpy3.py
changeset 44118 f81c17ec303c
parent 44117 c5e0a9b97b8a
child 44819 a6e12d477595
equal deleted inserted replaced
44117:c5e0a9b97b8a 44118:f81c17ec303c
    25 
    25 
    26 # This line is unnecessary, but it satisfies test-check-py3-compat.t.
    26 # This line is unnecessary, but it satisfies test-check-py3-compat.t.
    27 from __future__ import absolute_import
    27 from __future__ import absolute_import
    28 
    28 
    29 import contextlib
    29 import contextlib
    30 import importlib.abc
       
    31 import importlib.machinery
       
    32 import importlib.util
    30 import importlib.util
    33 import sys
    31 import sys
    34 
    32 
    35 from . import tracing
    33 from . import tracing
    36 
    34 
    55                 self.loader.exec_module(module)
    53                 self.loader.exec_module(module)
    56             else:
    54             else:
    57                 super().exec_module(module)
    55                 super().exec_module(module)
    58 
    56 
    59 
    57 
    60 _extensions_loader = _lazyloaderex.factory(
    58 class LazyFinder(object):
    61     importlib.machinery.ExtensionFileLoader
    59     """A wrapper around a ``MetaPathFinder`` that makes loaders lazy.
    62 )
       
    63 _bytecode_loader = _lazyloaderex.factory(
       
    64     importlib.machinery.SourcelessFileLoader
       
    65 )
       
    66 _source_loader = _lazyloaderex.factory(importlib.machinery.SourceFileLoader)
       
    67 
    60 
       
    61     ``sys.meta_path`` finders have their ``find_spec()`` called to locate a
       
    62     module. This returns a ``ModuleSpec`` if found or ``None``. The
       
    63     ``ModuleSpec`` has a ``loader`` attribute, which is called to actually
       
    64     load a module.
    68 
    65 
    69 def _makefinder(path):
    66     Our class wraps an existing finder and overloads its ``find_spec()`` to
    70     return importlib.machinery.FileFinder(
    67     replace the ``loader`` with our lazy loader proxy.
    71         path,
    68 
    72         # This is the order in which loaders are passed in in core Python.
    69     We have to use __getattribute__ to proxy the instance because some meta
    73         (_extensions_loader, importlib.machinery.EXTENSION_SUFFIXES),
    70     path finders don't support monkeypatching.
    74         (_source_loader, importlib.machinery.SOURCE_SUFFIXES),
    71     """
    75         (_bytecode_loader, importlib.machinery.BYTECODE_SUFFIXES),
    72 
    76     )
    73     __slots__ = ("_finder",)
       
    74 
       
    75     def __init__(self, finder):
       
    76         object.__setattr__(self, "_finder", finder)
       
    77 
       
    78     def __repr__(self):
       
    79         return "<LazyFinder for %r>" % object.__getattribute__(self, "_finder")
       
    80 
       
    81     # __bool__ is canonical Python 3. But check-code insists on __nonzero__ being
       
    82     # defined via `def`.
       
    83     def __nonzero__(self):
       
    84         return bool(object.__getattribute__(self, "_finder"))
       
    85 
       
    86     __bool__ = __nonzero__
       
    87 
       
    88     def __getattribute__(self, name):
       
    89         if name in ("_finder", "find_spec"):
       
    90             return object.__getattribute__(self, name)
       
    91 
       
    92         return getattr(object.__getattribute__(self, "_finder"), name)
       
    93 
       
    94     def __delattr__(self, name):
       
    95         return delattr(object.__getattribute__(self, "_finder"))
       
    96 
       
    97     def __setattr__(self, name, value):
       
    98         return setattr(object.__getattribute__(self, "_finder"), name, value)
       
    99 
       
   100     def find_spec(self, *args, **kwargs):
       
   101         finder = object.__getattribute__(self, "_finder")
       
   102         spec = finder.find_spec(*args, **kwargs)
       
   103 
       
   104         # Lazy loader requires exec_module().
       
   105         if (
       
   106             spec is not None
       
   107             and spec.loader is not None
       
   108             and getattr(spec.loader, "exec_module")
       
   109         ):
       
   110             spec.loader = _lazyloaderex(spec.loader)
       
   111 
       
   112         return spec
    77 
   113 
    78 
   114 
    79 ignores = set()
   115 ignores = set()
    80 
   116 
    81 
   117 
    83     global ignores
   119     global ignores
    84     ignores = ignoreset
   120     ignores = ignoreset
    85 
   121 
    86 
   122 
    87 def isenabled():
   123 def isenabled():
    88     return _makefinder in sys.path_hooks and not _deactivated
   124     return not _deactivated and any(
       
   125         isinstance(finder, LazyFinder) for finder in sys.meta_path
       
   126     )
    89 
   127 
    90 
   128 
    91 def disable():
   129 def disable():
    92     try:
   130     new_finders = []
    93         while True:
   131     for finder in sys.meta_path:
    94             sys.path_hooks.remove(_makefinder)
   132         new_finders.append(
    95     except ValueError:
   133             finder._finder if isinstance(finder, LazyFinder) else finder
    96         pass
   134         )
       
   135     sys.meta_path[:] = new_finders
    97 
   136 
    98 
   137 
    99 def enable():
   138 def enable():
   100     if not _supported:
   139     if not _supported:
   101         return
   140         return
   102 
   141 
   103     sys.path_hooks.insert(0, _makefinder)
   142     new_finders = []
       
   143     for finder in sys.meta_path:
       
   144         new_finders.append(
       
   145             LazyFinder(finder) if not isinstance(finder, LazyFinder) else finder
       
   146         )
       
   147     sys.meta_path[:] = new_finders
   104 
   148 
   105 
   149 
   106 @contextlib.contextmanager
   150 @contextlib.contextmanager
   107 def deactivated():
   151 def deactivated():
   108     # This implementation is a bit different from Python 2's. Python 3
   152     # This implementation is a bit different from Python 2's. Python 3