Coverage for aipyapp/exec/python/mod_obj.py: 31%

55 statements  

« prev     ^ index     » next       coverage.py v7.10.3, created at 2025-08-11 12:02 +0200

1import sys 

2import types 

3import importlib.abc 

4import importlib.util 

5 

6from loguru import logger 

7 

8class ObjectModuleLoader(importlib.abc.Loader): 

9 def __init__(self, fullname, obj): 

10 self.fullname = fullname 

11 self.obj = obj 

12 

13 def create_module(self, spec): 

14 mod = types.ModuleType(self.fullname) 

15 # 注入所有非魔法属性,包括方法 

16 for attr in dir(self.obj): 

17 if not attr.startswith("__"): 

18 setattr(mod, attr, getattr(self.obj, attr)) 

19 return mod 

20 

21 def exec_module(self, module): 

22 pass 

23 

24class ObjectModuleFinder(importlib.abc.MetaPathFinder): 

25 def __init__(self, package, object_map): 

26 self.package = package 

27 self.object_map = object_map 

28 self.logger = logger.bind(src='ObjectModuleFinder') 

29 

30 def find_spec(self, fullname, path, target=None): 

31 self.logger.info(f"find_spec: {fullname}, {path}, {target}") 

32 if fullname == self.package: 

33 spec = importlib.util.spec_from_loader(fullname, loader=None) 

34 spec.submodule_search_locations = [] 

35 return spec 

36 

37 if not fullname.startswith(self.package + "."): 

38 return None 

39 

40 subname = fullname[len(self.package) + 1:] 

41 if subname in self.object_map: 

42 loader = ObjectModuleLoader(fullname, self.object_map[subname]) 

43 return importlib.util.spec_from_loader(fullname, loader) 

44 return None 

45 

46class ObjectImporter: 

47 def __init__(self, object_map, package='aipyapp'): 

48 self.package = package 

49 self.finder = ObjectModuleFinder(package, object_map) 

50 

51 def __enter__(self): 

52 self._old_meta_path = sys.meta_path[:] 

53 if self.finder not in sys.meta_path: 

54 sys.meta_path.insert(0, self.finder) 

55 return self 

56 

57 def __exit__(self, exc_type, exc_val, exc_tb): 

58 sys.meta_path = self._old_meta_path 

59 

60if __name__ == "__main__": 

61 class Runtime: 

62 def do(self): 

63 print("runtime doing something") 

64 

65 runtime = Runtime() 

66 

67 obj_importer = ObjectImporter({"runtime": runtime}) 

68 

69 code = ''' 

70from aipyapp import runtime 

71runtime.do() 

72''' 

73 

74 with obj_importer: 

75 exec(code)