Coverage for src\zapy\utils\module.py: 61%

1 from pathlib import Path

2 import importlib.util

3 from threading import Lock

4 import io, sys, types

5

6 from zapy.templating.eval import exec_async

7

8

9 def load_module(module_path: str | Path):

10 module_path = Path(module_path)

11

12 if module_path.is_dir():

13 return load_module_dir(module_path)

14 elif module_path.suffix == '.ipynb':

15 raise ValueError('use load_ipynb to load ipynb')

16 else:

17 return load_module_python(module_path)

18

19

20 def load_module_dir(module_path: str | Path):

21 module_path = Path(module_path)

22 module_str = str(module_path)

23 with Lock():

24 sys.path.append(module_str)

25 try:

26 return load_module_python(module_path / '__init__.py')

27 finally:

28 sys.path.remove(module_str)

29

30

31 def load_module_python(module_path: str | Path):

32 module_path = Path(module_path)

33 module_spec = importlib.util.spec_from_file_location(module_path.stem, module_path)

34 module = importlib.util.module_from_spec(module_spec)

35 module_spec.loader.exec_module(module)

36

37 return module

38

39

40 async def load_ipynb(module_path: str | Path, variables=None):

41 ''' from https://jupyter-notebook.readthedocs.io/en/latest/examples/Notebook/Importing%20Notebooks.html '''

42 from IPython import get_ipython

43 from IPython.core.interactiveshell import InteractiveShell

44 from nbformat import read

45

46 module_path = Path(module_path)

47 shell = InteractiveShell.instance()

48 fullname = module_path.stem

49

50 variables = variables or dict()

51

52 # load the notebook object

53 with io.open(module_path, 'r', encoding='utf-8') as f:

54 nb = read(f, 4)

55

56 # create the module and add it to sys.modules if name in sys.modules:

57 # return sys.modules[name]

58 mod = types.ModuleType(fullname)

59 mod.__file__ = module_path

60 mod.__dict__['get_ipython'] = get_ipython

61 # apply parameters

62 for k, v in variables.items():

63 mod.__dict__[k] = v

64

65 # extra work to ensure that magics that would affect the user_ns

66 # actually affect the notebook module's ns

67 save_user_ns = shell.user_ns

68 shell.user_ns = mod.__dict__

69

70 try:

71 for cell in nb.cells:

72 if cell.cell_type == 'code': 72 ↛ 71line 72 didn't jump to line 71, because the condition on line 72 was never false

73 # transform the input to executable Python

74 code = shell.input_transformer_manager.transform_cell(cell.source)

75 # run the code in themodule

76 await exec_async(code, mod.__dict__)

77 finally:

78 shell.user_ns = save_user_ns

79 return mod