import sys import types from importlib.abc import MetaPathFinder from importlib.machinery import ModuleSpec from Redy.Tools.PathLib import Path from rbnf.edsl.rbnf_analyze import check_parsing_complete from yapypy.extended_python.parser import parse from yapypy.extended_python.py_compile import py_compile is_debug = False class YAPyPyFinder(MetaPathFinder): @classmethod def find_spec(cls, fullname: str, paths, target=None): paths = paths if isinstance( paths, list, ) else [paths] if isinstance( paths, str, ) else sys.path if is_debug: print(f'Searching module {fullname} from {paths[:5]}...') return find_yapypy_module_spec(fullname, paths) class YAPyPyLoader: def __init__(self, mod_name, mod_path): self.mod_name = mod_name self.mod_path = mod_path def exec_module(self, module): path = self.mod_path setattr(module, '__path__', path) setattr(module, '__package__', self.mod_name) setattr(module, '__loader__', self) bc = module.__bytecode__ if is_debug: print(f'found module {self.mod_name} at {self.mod_path}.') exec(bc, module.__dict__) def create_module(self, spec): bc: types.CodeType = spec.__bytecode__ doc = None if len(bc.co_consts) and isinstance(bc.co_consts[0], str): doc = bc.co_consts[0] mod = types.ModuleType(self.mod_name, doc) mod.__bytecode__ = bc return mod def find_yapypy_module_spec(names, paths): def try_find(prospective_path): path_secs = (prospective_path, *names.split('.')) *init, end = path_secs directory = Path(*init) if not directory.is_dir(): return for each in directory.list_dir(): each_path_str = each.relative() # print(each_path_str, end) if each_path_str == end + '.py': module_path = directory.into(each_path_str) yield get_yapypy_module_spec_from_path(names, str(module_path)) elif each_path_str == end and each.is_dir() and '__init__.py' in each: yield from try_find(str(each)) for each in paths: found = next(try_find(each), None) if found: return found def get_yapypy_module_spec_from_path(names, module_path): with Path(module_path).open('r') as fr: spec = ModuleSpec(names, YAPyPyLoader(names, module_path)) __source__ = fr.read() result = parse(__source__, module_path) check_parsing_complete(__source__, result.tokens, result.state) __bytecode__ = py_compile( result.result, filename=module_path, is_entrypoint=False) spec.__source__ = __source__ spec.__bytecode__ = __bytecode__ return spec sys.meta_path.insert(0, YAPyPyFinder())