##// END OF EJS Templates
manifest: add some documentation to _lazymanifest python code...
manifest: add some documentation to _lazymanifest python code It was not particularly easy figuring out the design of this class and keeping track of how the pieces work. So might as well write some of it down for the next person.

File last commit:

r37862:670eb4fa default
r42570:c3484ddb 5.0.1 stable
Show More
demandimportpy3.py
109 lines | 3.4 KiB | text/x-python | PythonLexer
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 # demandimportpy3 - global demand-loading of modules for Mercurial
#
# Copyright 2017 Facebook Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""Lazy loading for Python 3.6 and above.
This uses the new importlib finder/loader functionality available in Python 3.5
and up. The code reuses most of the mechanics implemented inside importlib.util,
but with a few additions:
* Allow excluding certain modules from lazy imports.
* Expose an interface that's substantially the same as demandimport for
Python 2.
This also has some limitations compared to the Python 2 implementation:
* Much of the logic is per-package, not per-module, so any packages loaded
before demandimport is enabled will not be lazily imported in the future. In
practice, we only expect builtins to be loaded before demandimport is
enabled.
"""
# This line is unnecessary, but it satisfies test-check-py3-compat.t.
from __future__ import absolute_import
import contextlib
import importlib.abc
import importlib.machinery
import importlib.util
Augie Fackler
demandimportpy3: update to pass import checker
r33899 import sys
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
_deactivated = False
class _lazyloaderex(importlib.util.LazyLoader):
"""This is a LazyLoader except it also follows the _deactivated global and
the ignore list.
"""
def exec_module(self, module):
"""Make the module load lazily."""
Gregory Szorc
demandimport: make module ignores a set (API)...
r37862 if _deactivated or module.__name__ in ignores:
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 self.loader.exec_module(module)
else:
super().exec_module(module)
# This is 3.6+ because with Python 3.5 it isn't possible to lazily load
Pulkit Goyal
hgdemandimport: use correct hyperlink to python-bug in comments (issue5765)...
r35542 # extensions. See the discussion in https://bugs.python.org/issue26186 for more.
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423 _extensions_loader = _lazyloaderex.factory(
importlib.machinery.ExtensionFileLoader)
_bytecode_loader = _lazyloaderex.factory(
importlib.machinery.SourcelessFileLoader)
_source_loader = _lazyloaderex.factory(importlib.machinery.SourceFileLoader)
def _makefinder(path):
return importlib.machinery.FileFinder(
path,
# This is the order in which loaders are passed in in core Python.
(_extensions_loader, importlib.machinery.EXTENSION_SUFFIXES),
(_source_loader, importlib.machinery.SOURCE_SUFFIXES),
(_bytecode_loader, importlib.machinery.BYTECODE_SUFFIXES),
)
Gregory Szorc
demandimport: make module ignores a set (API)...
r37862 ignores = set()
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
Gregory Szorc
demandimport: make module ignores a set (API)...
r37862 def init(ignoreset):
global ignores
ignores = ignoreset
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
def isenabled():
return _makefinder in sys.path_hooks and not _deactivated
def disable():
try:
while True:
sys.path_hooks.remove(_makefinder)
except ValueError:
pass
def enable():
Jun Wu
demandimport: move HGDEMANDIMPORT test to __init__.py...
r33861 sys.path_hooks.insert(0, _makefinder)
Siddharth Agarwal
demandimport: add python 3 implementation...
r32423
@contextlib.contextmanager
def deactivated():
# This implementation is a bit different from Python 2's. Python 3
# maintains a per-package finder cache in sys.path_importer_cache (see
# PEP 302). This means that we can't just call disable + enable.
# If we do that, in situations like:
#
# demandimport.enable()
# ...
# from foo.bar import mod1
# with demandimport.deactivated():
# from foo.bar import mod2
#
# mod2 will be imported lazily. (The converse also holds -- whatever finder
# first gets cached will be used.)
#
# Instead, have a global flag the LazyLoader can use.
global _deactivated
demandenabled = isenabled()
if demandenabled:
_deactivated = True
try:
yield
finally:
if demandenabled:
_deactivated = False