Coverage for adhoc-cicd-odoo-odoo / odoo / _monkeypatches / __init__.py: 94%

37 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-09 18:22 +0000

1"""Lazy module monkeypatcher 

2 

3Submodules should be named after the module (stdlib or third-party) they need 

4to patch, and should define a `patch_module` function. 

5 

6This function will be called either immediately if the module to patch is 

7already imported when the monkey patcher runs, or right after that module is 

8imported otherwise. 

9""" 

10 

11import importlib 

12import os 

13import pkgutil 

14import sys 

15import time 

16from types import ModuleType, SimpleNamespace 

17 

18 

19class PatchImportHook: 

20 """Register hooks that are run on import.""" 

21 

22 def __init__(self): 

23 self.hooks = set() 

24 

25 def add_hook(self, fullname: str) -> None: 

26 """Register a hook after a module is loaded. 

27 If already loaded, run hook immediately.""" 

28 self.hooks.add(fullname) 

29 if fullname in sys.modules: 

30 patch_module(fullname) 

31 

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

33 if fullname not in self.hooks: 

34 return None # let python use another import hook to import this fullname 

35 

36 # skip all finders before this one 

37 idx = sys.meta_path.index(self) 

38 for finder in sys.meta_path[idx + 1:]: 38 ↛ 49line 38 didn't jump to line 49 because the loop on line 38 didn't complete

39 spec = finder.find_spec(fullname, path, target) 

40 if spec is not None: 

41 # we found a spec, change the loader 

42 

43 def exec_module(module: ModuleType, exec_module=spec.loader.exec_module) -> None: 

44 exec_module(module) 

45 patch_module(module.__name__) 

46 

47 spec.loader = SimpleNamespace(create_module=spec.loader.create_module, exec_module=exec_module) 

48 return spec 

49 raise ImportError(f"Could not load the module {fullname!r} to patch") 

50 

51 

52HOOK_IMPORT = PatchImportHook() 

53sys.meta_path.insert(0, HOOK_IMPORT) 

54 

55 

56def patch_init() -> None: 

57 os.environ['TZ'] = 'UTC' # Set the timezone 

58 if hasattr(time, 'tzset'): 58 ↛ 61line 58 didn't jump to line 61 because the condition on line 58 was always true

59 time.tzset() 

60 

61 for submodule in pkgutil.iter_modules(__path__): 

62 HOOK_IMPORT.add_hook(submodule.name) 

63 

64 

65def patch_module(name: str) -> None: 

66 module = importlib.import_module(f'.{name}', __name__) 

67 module.patch_module()