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