##// END OF EJS Templates
demandimportpy3: only use lazy extension loader on Python 3.6+...
Gregory Szorc -
r43695:2d31ef3f stable
parent child Browse files
Show More
@@ -1,124 +1,128 b''
1 1 # demandimportpy3 - global demand-loading of modules for Mercurial
2 2 #
3 3 # Copyright 2017 Facebook Inc.
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """Lazy loading for Python 3.6 and above.
9 9
10 10 This uses the new importlib finder/loader functionality available in Python 3.5
11 11 and up. The code reuses most of the mechanics implemented inside importlib.util,
12 12 but with a few additions:
13 13
14 14 * Allow excluding certain modules from lazy imports.
15 15 * Expose an interface that's substantially the same as demandimport for
16 16 Python 2.
17 17
18 18 This also has some limitations compared to the Python 2 implementation:
19 19
20 20 * Much of the logic is per-package, not per-module, so any packages loaded
21 21 before demandimport is enabled will not be lazily imported in the future. In
22 22 practice, we only expect builtins to be loaded before demandimport is
23 23 enabled.
24 24 """
25 25
26 26 # This line is unnecessary, but it satisfies test-check-py3-compat.t.
27 27 from __future__ import absolute_import
28 28
29 29 import contextlib
30 30 import importlib.abc
31 31 import importlib.machinery
32 32 import importlib.util
33 33 import sys
34 34
35 35 from . import tracing
36 36
37 37 _deactivated = False
38 38
39 39
40 40 class _lazyloaderex(importlib.util.LazyLoader):
41 41 """This is a LazyLoader except it also follows the _deactivated global and
42 42 the ignore list.
43 43 """
44 44
45 45 def exec_module(self, module):
46 46 """Make the module load lazily."""
47 47 with tracing.log('demandimport %s', module):
48 48 if _deactivated or module.__name__ in ignores:
49 49 self.loader.exec_module(module)
50 50 else:
51 51 super().exec_module(module)
52 52
53 53
54 54 # This is 3.6+ because with Python 3.5 it isn't possible to lazily load
55 55 # extensions. See the discussion in https://bugs.python.org/issue26186 for more.
56 _extensions_loader = _lazyloaderex.factory(
57 importlib.machinery.ExtensionFileLoader
58 )
56 if sys.version_info[0:2] >= (3, 6):
57 _extensions_loader = _lazyloaderex.factory(
58 importlib.machinery.ExtensionFileLoader
59 )
60 else:
61 _extensions_loader = importlib.machinery.ExtensionFileLoader
62
59 63 _bytecode_loader = _lazyloaderex.factory(
60 64 importlib.machinery.SourcelessFileLoader
61 65 )
62 66 _source_loader = _lazyloaderex.factory(importlib.machinery.SourceFileLoader)
63 67
64 68
65 69 def _makefinder(path):
66 70 return importlib.machinery.FileFinder(
67 71 path,
68 72 # This is the order in which loaders are passed in in core Python.
69 73 (_extensions_loader, importlib.machinery.EXTENSION_SUFFIXES),
70 74 (_source_loader, importlib.machinery.SOURCE_SUFFIXES),
71 75 (_bytecode_loader, importlib.machinery.BYTECODE_SUFFIXES),
72 76 )
73 77
74 78
75 79 ignores = set()
76 80
77 81
78 82 def init(ignoreset):
79 83 global ignores
80 84 ignores = ignoreset
81 85
82 86
83 87 def isenabled():
84 88 return _makefinder in sys.path_hooks and not _deactivated
85 89
86 90
87 91 def disable():
88 92 try:
89 93 while True:
90 94 sys.path_hooks.remove(_makefinder)
91 95 except ValueError:
92 96 pass
93 97
94 98
95 99 def enable():
96 100 sys.path_hooks.insert(0, _makefinder)
97 101
98 102
99 103 @contextlib.contextmanager
100 104 def deactivated():
101 105 # This implementation is a bit different from Python 2's. Python 3
102 106 # maintains a per-package finder cache in sys.path_importer_cache (see
103 107 # PEP 302). This means that we can't just call disable + enable.
104 108 # If we do that, in situations like:
105 109 #
106 110 # demandimport.enable()
107 111 # ...
108 112 # from foo.bar import mod1
109 113 # with demandimport.deactivated():
110 114 # from foo.bar import mod2
111 115 #
112 116 # mod2 will be imported lazily. (The converse also holds -- whatever finder
113 117 # first gets cached will be used.)
114 118 #
115 119 # Instead, have a global flag the LazyLoader can use.
116 120 global _deactivated
117 121 demandenabled = isenabled()
118 122 if demandenabled:
119 123 _deactivated = True
120 124 try:
121 125 yield
122 126 finally:
123 127 if demandenabled:
124 128 _deactivated = False
General Comments 0
You need to be logged in to leave comments. Login now