| @ -0,0 +1,96 @@ | |||||
| import importlib | |||||
| from importlib.abc import Loader, MetaPathFinder | |||||
| import sys | |||||
| registry = dict() | |||||
| module_cls = type(sys) | |||||
| spec_cls = type(sys.__spec__) | |||||
| class VirtualModule: | |||||
| __slots__ = ['name', 'module', 'spec'] | |||||
| def __init__(self, name): | |||||
| self.name = name | |||||
| self.module = module_cls(name) | |||||
| self.spec = spec_cls(name=name, loader=VirtualModuleLoader) | |||||
| setattr(self.module, '__spec__', self.spec) | |||||
| def set_attribute(self, name, value): | |||||
| setattr(self.module, name, value) | |||||
| def delete_attribute(self, name): | |||||
| delattr(self.module, name) | |||||
| def create_module(name): | |||||
| module = VirtualModule(name) | |||||
| registry[name] = module | |||||
| return module | |||||
| def copy_module(module): | |||||
| name = module.__name__ | |||||
| if hasattr(module, '__spec__'): | |||||
| name = module.__spec__.name | |||||
| virt_mod = VirtualModule(name) | |||||
| for key, value in module.__dict__.items(): | |||||
| if key in ('__spec__', '__name__', '__loader__', '__package__'): | |||||
| continue | |||||
| virt_mod.set_attribute(key, value) | |||||
| registry[name] = virt_mod | |||||
| importlib.reload(module) | |||||
| return virt_mod | |||||
| def as_module(cls_or_name): | |||||
| if isinstance(cls_or_name, str): | |||||
| cls = None | |||||
| name = cls_or_name | |||||
| elif isinstance(cls_or_name, type): | |||||
| cls = cls_or_name | |||||
| name = getattr(cls, '__module_name__', cls.__name__) | |||||
| else: | |||||
| raise ValueError('Expected as_module to be passed a string or a class type') | |||||
| def wrapper(cls): | |||||
| module = create_module(name) | |||||
| for key, value in cls.__dict__.items(): | |||||
| if key.startswith('__') and key.endswith('__'): | |||||
| continue | |||||
| module.set_attribute(key, value) | |||||
| return module | |||||
| if cls is None: | |||||
| return wrapper | |||||
| return wrapper(cls) | |||||
| class VirtualModuleLoader(Loader): | |||||
| def create_module(spec): | |||||
| if spec.name not in registry: | |||||
| return None | |||||
| return registry[spec.name].module | |||||
| def exec_module(module): | |||||
| module_name = module.__name__ | |||||
| if hasattr(module, '__spec__'): | |||||
| module_name = module.__spec__.name | |||||
| sys.modules[module_name] = module | |||||
| class VirtualModuleFinder(MetaPathFinder): | |||||
| def find_spec(fullname, path, target=None): | |||||
| if fullname in registry: | |||||
| return registry[fullname].spec | |||||
| return None | |||||
| sys.meta_path.insert(0, VirtualModuleFinder) | |||||