| @ -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) | |||