Skip to content

Instantly share code, notes, and snippets.

@spajak
Last active March 8, 2022 17:08
Show Gist options
  • Save spajak/4e119240c37c59cc3e936e285ab76c55 to your computer and use it in GitHub Desktop.
Save spajak/4e119240c37c59cc3e936e285ab76c55 to your computer and use it in GitHub Desktop.
Python's example function `require` that imports file by path (like in PHP or JavaScript), with custom module's name and without creating bytecode.
import sys
from pathlib import Path
import importlib
import runpy
def require(file, name=None):
if name is None:
name = Path(file).stem
anonymous = lambda cls: cls(name, str(Path(__file__).parent / file))
@anonymous
class loader(importlib.machinery.SourceFileLoader):
"""This loader does't save bytecode"""
def set_data(self, *args, **kwargs):
raise NotImplementedError
spec = importlib.util.spec_from_loader(name, loader)
sys.modules[spec.name] = module = importlib.util.module_from_spec(spec)
loader.exec_module(module)
return module
a = require('foo.py')
assert a.Foo().bar == require('foo.py', 'b').bar()
print(a.__file__)
print(a.__name__)
print(a.Foo().__class__)
# Alternative way using runpy package: get file as a dict instead of a module
def execute(file, name=None):
if name is None:
name = Path(file).stem
return runpy.run_path(str(Path(__file__).parent / file), run_name=name)
b = execute('foo.py')
assert b['Foo'].x == execute('foo.py', 'c')['xyz']
print(b['__file__'])
print(b['__name__'])
x = b['Foo']()
print(x.__class__)
# Can be easily turned into an object and used like a module
class NS:
def __init__(self, file, name=None):
self.__dict__.update(execute(file, name))
c = NS('foo.py', 'bar')
# pylint: disable=no-member
print(c.__name__)
print(c.xyz)
class Foo:
x = 'xyz'
def __init__(self):
self.bar = 111
def bar():
return 111
xyz = 'xyz'
print(f'--- {__file__} executed with name: {__name__} ---')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment