Skip to content

Instantly share code, notes, and snippets.

@StSav012
Last active April 10, 2025 17:12
Show Gist options
  • Save StSav012/a1ec296d11a38da2cbeb372f11ca75bd to your computer and use it in GitHub Desktop.
Save StSav012/a1ec296d11a38da2cbeb372f11ca75bd to your computer and use it in GitHub Desktop.
Use custom meta hook to import modules available as strings
"""
Use custom meta hook to import modules available as strings.
Cp. PEP 302 http://www.python.org/dev/peps/pep-0302/#specification-part-2-registering-hooks
Credit: Thorsten Kranz, https://stackoverflow.com/a/14192708/8554611
"""
import sys
from importlib.abc import Loader, MetaPathFinder
from importlib.machinery import ModuleSpec
from importlib.util import spec_from_file_location
from types import ModuleType
class StringImporter(MetaPathFinder):
class Loader(Loader):
def __init__(self, modules: dict[str, str | dict]) -> None:
self._modules: dict[str, str | dict] = modules
# noinspection PyMethodMayBeStatic
def is_package(self, module_name: str) -> bool:
return isinstance(self._modules[module_name], dict)
# noinspection PyMethodMayBeStatic
def get_code(self, module_name: str):
return compile(self._modules[module_name], filename="<string>", mode="exec")
def create_module(self, spec: ModuleSpec) -> ModuleType | None:
return ModuleType(spec.name)
def exec_module(self, module: ModuleType) -> None:
if module.__name__ not in self._modules:
raise ImportError(module.__name__)
sys.modules[module.__name__] = module
if not self.is_package(module.__name__):
exec(self._modules[module.__name__], module.__dict__)
else:
for sub_module in self._modules[module.__name__]:
self._modules[".".join((module.__name__, sub_module))] = self._modules[module.__name__][
sub_module
]
exec(self._modules[module.__name__].get("__init__", ""), module.__dict__)
def __init__(self, **modules: str | dict) -> None:
self._modules: dict[str, str | dict] = modules
self._loader = StringImporter.Loader(modules)
def find_spec(
self,
fullname: str,
path: "str | None",
target: "ModuleType | None" = None,
) -> "ModuleSpec | None":
if fullname in self._modules:
spec: ModuleSpec = spec_from_file_location(fullname, loader=self._loader)
spec.origin = "<string>"
return spec
return None
if __name__ == "__main__":
def main() -> None:
modules = {
"a": """def hello():
return f'Hello World from {__spec__.name or __file__}!'""",
"b": """def hello():
return f'Hello World from {__spec__.name or __file__}!'""",
"package": {
"__init__": """print('initializing the package')""",
"module": """def hello():
return f'Hello World from {__spec__.name or __file__}!'""",
},
}
sys.meta_path.append(StringImporter(**modules))
# Let's use our import hook
# noinspection PyUnresolvedReferences
import a
print(a.hello())
# noinspection PyUnresolvedReferences
from a import hello
print(hello())
# noinspection PyUnresolvedReferences
from b import hello
print(hello())
# noinspection PyUnresolvedReferences
from package.module import hello
print(hello())
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment