Wrap a real loader to track the import stack during exec_module.
| 51 | |
| 52 | |
| 53 | class LoaderProxy(importlib.abc.Loader): |
| 54 | """Wrap a real loader to track the import stack during exec_module.""" |
| 55 | |
| 56 | def __init__(self, wrapped: Any, tracer: ImportTreeTracer, fullname: str): |
| 57 | self._wrapped = wrapped |
| 58 | self._tracer = tracer |
| 59 | self._fullname = fullname |
| 60 | |
| 61 | def create_module(self, spec): |
| 62 | if hasattr(self._wrapped, "create_module"): |
| 63 | return self._wrapped.create_module(spec) |
| 64 | return None |
| 65 | |
| 66 | def exec_module(self, module: ModuleType) -> None: |
| 67 | self._tracer.push(self._fullname) |
| 68 | try: |
| 69 | if hasattr(self._wrapped, "exec_module"): |
| 70 | self._wrapped.exec_module(module) |
| 71 | elif hasattr(self._wrapped, "load_module"): |
| 72 | self._wrapped.load_module(self._fullname) |
| 73 | else: |
| 74 | raise ImportError(f"Loader for {self._fullname!r} has neither exec_module nor load_module") |
| 75 | finally: |
| 76 | self._tracer.pop() |
| 77 | |
| 78 | def __getattr__(self, name: str) -> Any: |
| 79 | return getattr(self._wrapped, name) |
| 80 | |
| 81 | |
| 82 | class ImportTreeFinder(importlib.abc.MetaPathFinder): |