Last active
July 25, 2016 22:37
-
-
Save sunshowers/49513f0adc0c2ae2c00589dd99033819 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# Copyright 2004-present Facebook. Licensed as GPLv2+. | |
"""Lazy loading for Python 3. | |
Requires Python 3.5.2 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 the open source | |
demandimport, including a 'deactivated' context manager. | |
This also has some limitations compared to the Python 2 implementation: | |
* zipimports are not supported. | |
* 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. | |
* Extension modules cannot be lazily imported. This is a limitation in Python | |
3.5 and has been lifted in Python 3.6 (see https://python.org/sf/26186 for | |
more). | |
""" | |
import contextlib | |
import importlib.abc | |
import importlib.machinery | |
import importlib.util | |
import os | |
import sys | |
import _demandimport | |
ignore = _demandimport.ignore | |
_deactivated = False | |
class _LazyLoaderWithExclusions(importlib.util.LazyLoader): | |
"""This is a LazyLoader except it also ignores the _deactivated global and | |
the ignore list. | |
""" | |
def exec_module(self, module): | |
"""Make the module load lazily.""" | |
if _deactivated or module.__name__ in ignore: | |
self.loader.exec_module(module) | |
else: | |
super().exec_module(module) | |
# With Python 3.5 it isn't possible to lazily load extensions. With Python 3.6 | |
# it will be, so this code will have to be updated to reflect that. See the | |
# discussion in https://python.org/sf/26186 for more. | |
_extensions_loader = importlib.machinery.ExtensionFileLoader | |
_bytecode_loader = _LazyLoaderWithExclusions.factory( | |
importlib.machinery.SourcelessFileLoader) | |
_source_loader = _LazyLoaderWithExclusions.factory( | |
importlib.machinery.SourceFileLoader) | |
def _make_finder(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), | |
) | |
def isenabled(): | |
return _make_finder in sys.path_hooks and not _deactivated | |
def disable(): | |
try: | |
while True: | |
sys.path_hooks.remove(_make_finder) | |
except ValueError: | |
pass | |
def enable(): | |
if os.environ.get('HGDEMANDIMPORT') != 'disable': | |
sys.path_hooks.insert(0, _make_finder) | |
@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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment