Skip to content

Commit 1764385

Browse files
authored
✨ Feature: wrap origin loader for lazy modules (#260)
1 parent 7921bee commit 1764385

File tree

1 file changed

+29
-7
lines changed

1 file changed

+29
-7
lines changed

githubkit/lazy_module.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from collections.abc import Sequence
22
import importlib
3-
from importlib.abc import MetaPathFinder
3+
from importlib.abc import Loader
44
from importlib.machinery import ModuleSpec, PathFinder, SourceFileLoader
55
from itertools import chain
66
import re
@@ -71,18 +71,32 @@ def __reduce__(self):
7171

7272

7373
class LazyModuleLoader(SourceFileLoader):
74+
def __init__(
75+
self, fullname: str, path: str, origin_loader: Optional[Loader] = None
76+
) -> None:
77+
super().__init__(fullname, path)
78+
79+
self.origin_loader = origin_loader
80+
7481
def create_module(self, spec: ModuleSpec) -> Optional[ModuleType]:
7582
if self.name in sys.modules:
7683
return sys.modules[self.name]
84+
85+
# create a simple empty lazy module
7786
module = LazyModule(spec.name)
7887
# pre-initialize the module to avoid infinite recursion
7988
module.__lazy_vars_validated__ = None
8089
module.__lazy_vars_mapping__ = {}
8190
return module
8291

8392
def exec_module(self, module: ModuleType) -> None:
84-
super().exec_module(module)
93+
# execute the module code
94+
if self.origin_loader is not None:
95+
self.origin_loader.exec_module(module)
96+
else:
97+
super().exec_module(module)
8598

99+
# initialize the module's lazy vars structure
86100
if (
87101
isinstance(module, LazyModule)
88102
and getattr(module, "__lazy_vars_validated__", None) is None
@@ -104,19 +118,27 @@ def exec_module(self, module: ModuleType) -> None:
104118
)
105119

106120

107-
class LazyModuleFinder(MetaPathFinder):
121+
class LazyModuleFinder(PathFinder):
122+
@classmethod
108123
def find_spec(
109-
self,
124+
cls,
110125
fullname: str,
111-
path: Optional[Sequence[str]],
126+
path: Optional[Sequence[str]] = None,
112127
target: Optional[ModuleType] = None,
113128
) -> Optional[ModuleSpec]:
129+
# match if the module should be loaded lazily
114130
if any(re.match(pattern, fullname) for pattern in LAZY_MODULES):
115-
module_spec = PathFinder.find_spec(fullname, path, target)
131+
# find the module spec
132+
module_spec = super().find_spec(fullname, path, target)
133+
# do nothing if spec is not found
116134
if not module_spec or not module_spec.origin:
117135
return
118136

119-
module_spec.loader = LazyModuleLoader(module_spec.name, module_spec.origin)
137+
# wraps the module's loader to change the module into LazyModule
138+
# NOTE: module may have custom loader in some environment (e.g. pyinstaller)
139+
module_spec.loader = LazyModuleLoader(
140+
module_spec.name, module_spec.origin, module_spec.loader
141+
)
120142
return module_spec
121143

122144

0 commit comments

Comments
 (0)