|
10 | 10 | import inspect
|
11 | 11 | import os
|
12 | 12 | import sys
|
| 13 | +import threading |
13 | 14 | import types
|
14 | 15 | import warnings
|
15 | 16 |
|
16 | 17 | __all__ = ["attach", "load", "attach_stub"]
|
17 | 18 |
|
18 | 19 |
|
| 20 | +threadlock = threading.Lock() |
| 21 | + |
| 22 | + |
19 | 23 | def attach(package_name, submodules=None, submod_attrs=None):
|
20 | 24 | """Attach lazily loaded submodules, functions, or other attributes.
|
21 | 25 |
|
@@ -171,42 +175,45 @@ def myfunc():
|
171 | 175 | Actual loading of the module occurs upon first attribute request.
|
172 | 176 |
|
173 | 177 | """
|
174 |
| - try: |
175 |
| - return sys.modules[fullname] |
176 |
| - except KeyError: |
177 |
| - pass |
178 |
| - |
179 |
| - if "." in fullname: |
180 |
| - msg = ( |
181 |
| - "subpackages can technically be lazily loaded, but it causes the " |
182 |
| - "package to be eagerly loaded even if it is already lazily loaded." |
183 |
| - "So, you probably shouldn't use subpackages with this lazy feature." |
184 |
| - ) |
185 |
| - warnings.warn(msg, RuntimeWarning) |
186 |
| - |
187 |
| - spec = importlib.util.find_spec(fullname) |
188 |
| - if spec is None: |
189 |
| - if error_on_import: |
190 |
| - raise ModuleNotFoundError(f"No module named '{fullname}'") |
191 |
| - else: |
192 |
| - try: |
193 |
| - parent = inspect.stack()[1] |
194 |
| - frame_data = { |
195 |
| - "spec": fullname, |
196 |
| - "filename": parent.filename, |
197 |
| - "lineno": parent.lineno, |
198 |
| - "function": parent.function, |
199 |
| - "code_context": parent.code_context, |
200 |
| - } |
201 |
| - return DelayedImportErrorModule(frame_data, "DelayedImportErrorModule") |
202 |
| - finally: |
203 |
| - del parent |
204 |
| - |
205 |
| - module = importlib.util.module_from_spec(spec) |
206 |
| - sys.modules[fullname] = module |
207 |
| - |
208 |
| - loader = importlib.util.LazyLoader(spec.loader) |
209 |
| - loader.exec_module(module) |
| 178 | + with threadlock: |
| 179 | + try: |
| 180 | + return sys.modules[fullname] |
| 181 | + except KeyError: |
| 182 | + pass |
| 183 | + |
| 184 | + if "." in fullname: |
| 185 | + msg = ( |
| 186 | + "subpackages can technically be lazily loaded, but it causes the " |
| 187 | + "package to be eagerly loaded even if it is already lazily loaded." |
| 188 | + "So, you probably shouldn't use subpackages with this lazy feature." |
| 189 | + ) |
| 190 | + warnings.warn(msg, RuntimeWarning) |
| 191 | + |
| 192 | + spec = importlib.util.find_spec(fullname) |
| 193 | + if spec is None: |
| 194 | + if error_on_import: |
| 195 | + raise ModuleNotFoundError(f"No module named '{fullname}'") |
| 196 | + else: |
| 197 | + try: |
| 198 | + parent = inspect.stack()[1] |
| 199 | + frame_data = { |
| 200 | + "spec": fullname, |
| 201 | + "filename": parent.filename, |
| 202 | + "lineno": parent.lineno, |
| 203 | + "function": parent.function, |
| 204 | + "code_context": parent.code_context, |
| 205 | + } |
| 206 | + return DelayedImportErrorModule( |
| 207 | + frame_data, "DelayedImportErrorModule" |
| 208 | + ) |
| 209 | + finally: |
| 210 | + del parent |
| 211 | + |
| 212 | + module = importlib.util.module_from_spec(spec) |
| 213 | + sys.modules[fullname] = module |
| 214 | + |
| 215 | + loader = importlib.util.LazyLoader(spec.loader) |
| 216 | + loader.exec_module(module) |
210 | 217 |
|
211 | 218 | return module
|
212 | 219 |
|
|
0 commit comments