hpcflow 0.1.9__py3-none-any.whl → 0.2.0a271__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. hpcflow/__init__.py +2 -11
  2. hpcflow/__pyinstaller/__init__.py +5 -0
  3. hpcflow/__pyinstaller/hook-hpcflow.py +40 -0
  4. hpcflow/_version.py +1 -1
  5. hpcflow/app.py +43 -0
  6. hpcflow/cli.py +2 -462
  7. hpcflow/data/demo_data_manifest/__init__.py +3 -0
  8. hpcflow/data/demo_data_manifest/demo_data_manifest.json +6 -0
  9. hpcflow/data/jinja_templates/test/test_template.txt +8 -0
  10. hpcflow/data/programs/hello_world/README.md +1 -0
  11. hpcflow/data/programs/hello_world/hello_world.c +87 -0
  12. hpcflow/data/programs/hello_world/linux/hello_world +0 -0
  13. hpcflow/data/programs/hello_world/macos/hello_world +0 -0
  14. hpcflow/data/programs/hello_world/win/hello_world.exe +0 -0
  15. hpcflow/data/scripts/__init__.py +1 -0
  16. hpcflow/data/scripts/bad_script.py +2 -0
  17. hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +8 -0
  18. hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +8 -0
  19. hpcflow/data/scripts/demo_task_1_parse_p3.py +7 -0
  20. hpcflow/data/scripts/do_nothing.py +2 -0
  21. hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
  22. hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
  23. hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
  24. hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
  25. hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
  26. hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
  27. hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
  28. hpcflow/data/scripts/generate_t1_file_01.py +7 -0
  29. hpcflow/data/scripts/import_future_script.py +7 -0
  30. hpcflow/data/scripts/input_file_generator_basic.py +3 -0
  31. hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
  32. hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
  33. hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
  34. hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +6 -0
  35. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
  36. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
  37. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
  38. hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
  39. hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +15 -0
  40. hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +7 -0
  41. hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +8 -0
  42. hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
  43. hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
  44. hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +6 -0
  45. hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +12 -0
  46. hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
  47. hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +12 -0
  48. hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +11 -0
  49. hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +14 -0
  50. hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +17 -0
  51. hpcflow/data/scripts/main_script_test_json_in_json_out.py +14 -0
  52. hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +16 -0
  53. hpcflow/data/scripts/main_script_test_json_in_obj.py +12 -0
  54. hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
  55. hpcflow/data/scripts/main_script_test_json_out_obj.py +10 -0
  56. hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +16 -0
  57. hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
  58. hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
  59. hpcflow/data/scripts/output_file_parser_basic.py +3 -0
  60. hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
  61. hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
  62. hpcflow/data/scripts/parse_t1_file_01.py +4 -0
  63. hpcflow/data/scripts/script_exit_test.py +5 -0
  64. hpcflow/data/template_components/__init__.py +1 -0
  65. hpcflow/data/template_components/command_files.yaml +26 -0
  66. hpcflow/data/template_components/environments.yaml +13 -0
  67. hpcflow/data/template_components/parameters.yaml +14 -0
  68. hpcflow/data/template_components/task_schemas.yaml +139 -0
  69. hpcflow/data/workflows/workflow_1.yaml +5 -0
  70. hpcflow/examples.ipynb +1037 -0
  71. hpcflow/sdk/__init__.py +149 -0
  72. hpcflow/sdk/app.py +4266 -0
  73. hpcflow/sdk/cli.py +1479 -0
  74. hpcflow/sdk/cli_common.py +385 -0
  75. hpcflow/sdk/config/__init__.py +5 -0
  76. hpcflow/sdk/config/callbacks.py +246 -0
  77. hpcflow/sdk/config/cli.py +388 -0
  78. hpcflow/sdk/config/config.py +1410 -0
  79. hpcflow/sdk/config/config_file.py +501 -0
  80. hpcflow/sdk/config/errors.py +272 -0
  81. hpcflow/sdk/config/types.py +150 -0
  82. hpcflow/sdk/core/__init__.py +38 -0
  83. hpcflow/sdk/core/actions.py +3857 -0
  84. hpcflow/sdk/core/app_aware.py +25 -0
  85. hpcflow/sdk/core/cache.py +224 -0
  86. hpcflow/sdk/core/command_files.py +814 -0
  87. hpcflow/sdk/core/commands.py +424 -0
  88. hpcflow/sdk/core/element.py +2071 -0
  89. hpcflow/sdk/core/enums.py +221 -0
  90. hpcflow/sdk/core/environment.py +256 -0
  91. hpcflow/sdk/core/errors.py +1043 -0
  92. hpcflow/sdk/core/execute.py +207 -0
  93. hpcflow/sdk/core/json_like.py +809 -0
  94. hpcflow/sdk/core/loop.py +1320 -0
  95. hpcflow/sdk/core/loop_cache.py +282 -0
  96. hpcflow/sdk/core/object_list.py +933 -0
  97. hpcflow/sdk/core/parameters.py +3371 -0
  98. hpcflow/sdk/core/rule.py +196 -0
  99. hpcflow/sdk/core/run_dir_files.py +57 -0
  100. hpcflow/sdk/core/skip_reason.py +7 -0
  101. hpcflow/sdk/core/task.py +3792 -0
  102. hpcflow/sdk/core/task_schema.py +993 -0
  103. hpcflow/sdk/core/test_utils.py +538 -0
  104. hpcflow/sdk/core/types.py +447 -0
  105. hpcflow/sdk/core/utils.py +1207 -0
  106. hpcflow/sdk/core/validation.py +87 -0
  107. hpcflow/sdk/core/values.py +477 -0
  108. hpcflow/sdk/core/workflow.py +4820 -0
  109. hpcflow/sdk/core/zarr_io.py +206 -0
  110. hpcflow/sdk/data/__init__.py +13 -0
  111. hpcflow/sdk/data/config_file_schema.yaml +34 -0
  112. hpcflow/sdk/data/config_schema.yaml +260 -0
  113. hpcflow/sdk/data/environments_spec_schema.yaml +21 -0
  114. hpcflow/sdk/data/files_spec_schema.yaml +5 -0
  115. hpcflow/sdk/data/parameters_spec_schema.yaml +7 -0
  116. hpcflow/sdk/data/task_schema_spec_schema.yaml +3 -0
  117. hpcflow/sdk/data/workflow_spec_schema.yaml +22 -0
  118. hpcflow/sdk/demo/__init__.py +3 -0
  119. hpcflow/sdk/demo/cli.py +242 -0
  120. hpcflow/sdk/helper/__init__.py +3 -0
  121. hpcflow/sdk/helper/cli.py +137 -0
  122. hpcflow/sdk/helper/helper.py +300 -0
  123. hpcflow/sdk/helper/watcher.py +192 -0
  124. hpcflow/sdk/log.py +288 -0
  125. hpcflow/sdk/persistence/__init__.py +18 -0
  126. hpcflow/sdk/persistence/base.py +2817 -0
  127. hpcflow/sdk/persistence/defaults.py +6 -0
  128. hpcflow/sdk/persistence/discovery.py +39 -0
  129. hpcflow/sdk/persistence/json.py +954 -0
  130. hpcflow/sdk/persistence/pending.py +948 -0
  131. hpcflow/sdk/persistence/store_resource.py +203 -0
  132. hpcflow/sdk/persistence/types.py +309 -0
  133. hpcflow/sdk/persistence/utils.py +73 -0
  134. hpcflow/sdk/persistence/zarr.py +2388 -0
  135. hpcflow/sdk/runtime.py +320 -0
  136. hpcflow/sdk/submission/__init__.py +3 -0
  137. hpcflow/sdk/submission/enums.py +70 -0
  138. hpcflow/sdk/submission/jobscript.py +2379 -0
  139. hpcflow/sdk/submission/schedulers/__init__.py +281 -0
  140. hpcflow/sdk/submission/schedulers/direct.py +233 -0
  141. hpcflow/sdk/submission/schedulers/sge.py +376 -0
  142. hpcflow/sdk/submission/schedulers/slurm.py +598 -0
  143. hpcflow/sdk/submission/schedulers/utils.py +25 -0
  144. hpcflow/sdk/submission/shells/__init__.py +52 -0
  145. hpcflow/sdk/submission/shells/base.py +229 -0
  146. hpcflow/sdk/submission/shells/bash.py +504 -0
  147. hpcflow/sdk/submission/shells/os_version.py +115 -0
  148. hpcflow/sdk/submission/shells/powershell.py +352 -0
  149. hpcflow/sdk/submission/submission.py +1402 -0
  150. hpcflow/sdk/submission/types.py +140 -0
  151. hpcflow/sdk/typing.py +194 -0
  152. hpcflow/sdk/utils/arrays.py +69 -0
  153. hpcflow/sdk/utils/deferred_file.py +55 -0
  154. hpcflow/sdk/utils/hashing.py +16 -0
  155. hpcflow/sdk/utils/patches.py +31 -0
  156. hpcflow/sdk/utils/strings.py +69 -0
  157. hpcflow/tests/api/test_api.py +32 -0
  158. hpcflow/tests/conftest.py +123 -0
  159. hpcflow/tests/data/__init__.py +0 -0
  160. hpcflow/tests/data/benchmark_N_elements.yaml +6 -0
  161. hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
  162. hpcflow/tests/data/multi_path_sequences.yaml +29 -0
  163. hpcflow/tests/data/workflow_1.json +10 -0
  164. hpcflow/tests/data/workflow_1.yaml +5 -0
  165. hpcflow/tests/data/workflow_1_slurm.yaml +8 -0
  166. hpcflow/tests/data/workflow_1_wsl.yaml +8 -0
  167. hpcflow/tests/data/workflow_test_run_abort.yaml +42 -0
  168. hpcflow/tests/jinja_templates/test_jinja_templates.py +161 -0
  169. hpcflow/tests/programs/test_programs.py +180 -0
  170. hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +12 -0
  171. hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
  172. hpcflow/tests/schedulers/slurm/test_slurm_submission.py +14 -0
  173. hpcflow/tests/scripts/test_input_file_generators.py +282 -0
  174. hpcflow/tests/scripts/test_main_scripts.py +1361 -0
  175. hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
  176. hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
  177. hpcflow/tests/shells/wsl/test_wsl_submission.py +14 -0
  178. hpcflow/tests/unit/test_action.py +1066 -0
  179. hpcflow/tests/unit/test_action_rule.py +24 -0
  180. hpcflow/tests/unit/test_app.py +132 -0
  181. hpcflow/tests/unit/test_cache.py +46 -0
  182. hpcflow/tests/unit/test_cli.py +172 -0
  183. hpcflow/tests/unit/test_command.py +377 -0
  184. hpcflow/tests/unit/test_config.py +195 -0
  185. hpcflow/tests/unit/test_config_file.py +162 -0
  186. hpcflow/tests/unit/test_element.py +666 -0
  187. hpcflow/tests/unit/test_element_iteration.py +88 -0
  188. hpcflow/tests/unit/test_element_set.py +158 -0
  189. hpcflow/tests/unit/test_group.py +115 -0
  190. hpcflow/tests/unit/test_input_source.py +1479 -0
  191. hpcflow/tests/unit/test_input_value.py +398 -0
  192. hpcflow/tests/unit/test_jobscript_unit.py +757 -0
  193. hpcflow/tests/unit/test_json_like.py +1247 -0
  194. hpcflow/tests/unit/test_loop.py +2674 -0
  195. hpcflow/tests/unit/test_meta_task.py +325 -0
  196. hpcflow/tests/unit/test_multi_path_sequences.py +259 -0
  197. hpcflow/tests/unit/test_object_list.py +116 -0
  198. hpcflow/tests/unit/test_parameter.py +243 -0
  199. hpcflow/tests/unit/test_persistence.py +664 -0
  200. hpcflow/tests/unit/test_resources.py +243 -0
  201. hpcflow/tests/unit/test_run.py +286 -0
  202. hpcflow/tests/unit/test_run_directories.py +29 -0
  203. hpcflow/tests/unit/test_runtime.py +9 -0
  204. hpcflow/tests/unit/test_schema_input.py +372 -0
  205. hpcflow/tests/unit/test_shell.py +129 -0
  206. hpcflow/tests/unit/test_slurm.py +39 -0
  207. hpcflow/tests/unit/test_submission.py +502 -0
  208. hpcflow/tests/unit/test_task.py +2560 -0
  209. hpcflow/tests/unit/test_task_schema.py +182 -0
  210. hpcflow/tests/unit/test_utils.py +616 -0
  211. hpcflow/tests/unit/test_value_sequence.py +549 -0
  212. hpcflow/tests/unit/test_values.py +91 -0
  213. hpcflow/tests/unit/test_workflow.py +827 -0
  214. hpcflow/tests/unit/test_workflow_template.py +186 -0
  215. hpcflow/tests/unit/utils/test_arrays.py +40 -0
  216. hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
  217. hpcflow/tests/unit/utils/test_hashing.py +65 -0
  218. hpcflow/tests/unit/utils/test_patches.py +5 -0
  219. hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
  220. hpcflow/tests/unit/utils/test_strings.py +97 -0
  221. hpcflow/tests/workflows/__init__.py +0 -0
  222. hpcflow/tests/workflows/test_directory_structure.py +31 -0
  223. hpcflow/tests/workflows/test_jobscript.py +355 -0
  224. hpcflow/tests/workflows/test_run_status.py +198 -0
  225. hpcflow/tests/workflows/test_skip_downstream.py +696 -0
  226. hpcflow/tests/workflows/test_submission.py +140 -0
  227. hpcflow/tests/workflows/test_workflows.py +564 -0
  228. hpcflow/tests/workflows/test_zip.py +18 -0
  229. hpcflow/viz_demo.ipynb +6794 -0
  230. hpcflow-0.2.0a271.dist-info/LICENSE +375 -0
  231. hpcflow-0.2.0a271.dist-info/METADATA +65 -0
  232. hpcflow-0.2.0a271.dist-info/RECORD +237 -0
  233. {hpcflow-0.1.9.dist-info → hpcflow-0.2.0a271.dist-info}/WHEEL +4 -5
  234. hpcflow-0.2.0a271.dist-info/entry_points.txt +6 -0
  235. hpcflow/api.py +0 -458
  236. hpcflow/archive/archive.py +0 -308
  237. hpcflow/archive/cloud/cloud.py +0 -47
  238. hpcflow/archive/cloud/errors.py +0 -9
  239. hpcflow/archive/cloud/providers/dropbox.py +0 -432
  240. hpcflow/archive/errors.py +0 -5
  241. hpcflow/base_db.py +0 -4
  242. hpcflow/config.py +0 -232
  243. hpcflow/copytree.py +0 -66
  244. hpcflow/data/examples/_config.yml +0 -14
  245. hpcflow/data/examples/damask/demo/1.run.yml +0 -4
  246. hpcflow/data/examples/damask/demo/2.process.yml +0 -29
  247. hpcflow/data/examples/damask/demo/geom.geom +0 -2052
  248. hpcflow/data/examples/damask/demo/load.load +0 -1
  249. hpcflow/data/examples/damask/demo/material.config +0 -185
  250. hpcflow/data/examples/damask/inputs/geom.geom +0 -2052
  251. hpcflow/data/examples/damask/inputs/load.load +0 -1
  252. hpcflow/data/examples/damask/inputs/material.config +0 -185
  253. hpcflow/data/examples/damask/profiles/_variable_lookup.yml +0 -21
  254. hpcflow/data/examples/damask/profiles/damask.yml +0 -4
  255. hpcflow/data/examples/damask/profiles/damask_process.yml +0 -8
  256. hpcflow/data/examples/damask/profiles/damask_run.yml +0 -5
  257. hpcflow/data/examples/damask/profiles/default.yml +0 -6
  258. hpcflow/data/examples/thinking.yml +0 -177
  259. hpcflow/errors.py +0 -2
  260. hpcflow/init_db.py +0 -37
  261. hpcflow/models.py +0 -2549
  262. hpcflow/nesting.py +0 -9
  263. hpcflow/profiles.py +0 -455
  264. hpcflow/project.py +0 -81
  265. hpcflow/scheduler.py +0 -323
  266. hpcflow/utils.py +0 -103
  267. hpcflow/validation.py +0 -167
  268. hpcflow/variables.py +0 -544
  269. hpcflow-0.1.9.dist-info/METADATA +0 -168
  270. hpcflow-0.1.9.dist-info/RECORD +0 -45
  271. hpcflow-0.1.9.dist-info/entry_points.txt +0 -8
  272. hpcflow-0.1.9.dist-info/top_level.txt +0 -1
  273. /hpcflow/{archive → data/jinja_templates}/__init__.py +0 -0
  274. /hpcflow/{archive/cloud → data/programs}/__init__.py +0 -0
  275. /hpcflow/{archive/cloud/providers → data/workflows}/__init__.py +0 -0
@@ -0,0 +1,206 @@
1
+ """
2
+ Utilities for working with Zarr.
3
+ """
4
+
5
+ from __future__ import annotations
6
+ from typing import Any
7
+ from typing_extensions import Self
8
+
9
+ import zarr # type: ignore
10
+ import numpy as np
11
+
12
+ from hpcflow.sdk.core.utils import get_in_container, get_relative_path, set_in_container
13
+
14
+
15
+ #: The basic types that Zarr can handle directly with no special action.
16
+ PRIMITIVES: tuple[type, ...] = (
17
+ int,
18
+ float,
19
+ str,
20
+ type(None),
21
+ )
22
+
23
+ #: Maximum nesting depth for encoding.
24
+ MAX_DEPTH = 50
25
+
26
+
27
+ def zarr_encode(data, zarr_group: zarr.Group, is_pending_add: bool, is_set: bool):
28
+ """
29
+ Encode data into a zarr group.
30
+ """
31
+
32
+ encoded: list[dict] = []
33
+
34
+ def encode(obj: Any, path: list) -> Any:
35
+ if len(path) > MAX_DEPTH:
36
+ raise RuntimeError("I'm in too deep!")
37
+
38
+ if isinstance(obj, ZarrEncodable):
39
+ return encode(obj.to_dict(), path)
40
+ elif isinstance(obj, (list, tuple, set)):
41
+ out = (encode(item, [*path, idx]) for idx, item in enumerate(obj))
42
+ if isinstance(obj, tuple):
43
+ return tuple(out)
44
+ elif isinstance(obj, set):
45
+ return set(out)
46
+ else:
47
+ return list(out)
48
+ elif isinstance(obj, dict):
49
+ return {
50
+ dct_key: encode(dct_val, [*path, dct_key])
51
+ for dct_key, dct_val in obj.items()
52
+ }
53
+ elif isinstance(obj, PRIMITIVES):
54
+ return obj
55
+ elif isinstance(obj, np.ndarray):
56
+ new_name = str(max((int(i) + 1 for i in zarr_group.keys()), default=0))
57
+ zarr_group.create_dataset(name=new_name, data=obj)
58
+ encoded.append(
59
+ {
60
+ "path": path,
61
+ "dataset": new_name,
62
+ }
63
+ )
64
+ return None
65
+ else:
66
+ raise ValueError(f"unserializable type: {type(obj)}")
67
+
68
+ zarr_group.attrs["data"] = encode(data, [])
69
+ zarr_group.attrs["encoded"] = encoded
70
+ zarr_group.attrs["is_set"] = is_set
71
+ if is_pending_add:
72
+ zarr_group.attrs["is_pending_add"] = is_pending_add
73
+
74
+
75
+ # TODO: need to separate so this func doesn't need matflow
76
+
77
+
78
+ def _zarr_encode_NEW(
79
+ obj: Any,
80
+ root_group: zarr.Group,
81
+ arr_path: str,
82
+ ) -> tuple[Any, list[list]]:
83
+ """
84
+ Save arbitrarily-nested Python-primitive, `ZarrEncodable` and numpy array objects into
85
+ Zarr.
86
+
87
+ Parameters
88
+ ----------
89
+ obj:
90
+ Object to encode.
91
+ root_group:
92
+ Parent Zarr group into which new Zarr arrays will be added (at `arr_path`).
93
+ arr_path:
94
+ Path relative to `root_group` into which new Zarr arrays will be added.
95
+
96
+ Returns
97
+ -------
98
+ data
99
+ The encoded data.
100
+ arr_lookup
101
+ How to look up where to rebuild Numpy arrays.
102
+ """
103
+
104
+ arr_lookup: list[list] = []
105
+
106
+ def encode(obj: Any, path: list) -> Any:
107
+ if len(path) > MAX_DEPTH:
108
+ raise RuntimeError("I'm in too deep!")
109
+
110
+ if isinstance(obj, ZarrEncodable):
111
+ return encode(obj.to_dict(), path)
112
+ elif isinstance(obj, (list, tuple, set)):
113
+ items = (encode(item, [*path, idx]) for idx, item in enumerate(obj))
114
+ if isinstance(obj, tuple):
115
+ return tuple(items)
116
+ elif isinstance(obj, set):
117
+ return set(items)
118
+ else:
119
+ return list(items)
120
+ elif isinstance(obj, dict):
121
+ return {key: encode(val, [*path, key]) for key, val in obj.items()}
122
+ elif isinstance(obj, PRIMITIVES):
123
+ return obj
124
+ elif isinstance(obj, np.ndarray):
125
+ # Might need to generate new group:
126
+ param_arr_group = root_group.require_group(arr_path)
127
+ new_idx = max((int(i) + 1 for i in param_arr_group.keys()), default=0)
128
+ param_arr_group.create_dataset(name=f"arr_{new_idx}", data=obj)
129
+ arr_lookup.append([path, new_idx])
130
+ return None
131
+ else:
132
+ raise ValueError(f"unserializable type: {type(obj)}")
133
+
134
+ return encode(obj, []), arr_lookup
135
+
136
+
137
+ def zarr_decode(
138
+ param_data: None | dict,
139
+ arr_group: zarr.Group,
140
+ path: list | None = None,
141
+ dataset_copy: bool = False,
142
+ ):
143
+ """
144
+ Decode data from a zarr group.
145
+ """
146
+ if param_data is None:
147
+ return None
148
+
149
+ path = path or []
150
+
151
+ data = get_in_container(param_data["data"], path)
152
+ # data = copy.deepcopy(data) # TODO: why did we copy?
153
+
154
+ for arr_path, arr_idx in param_data["arr_lookup"]:
155
+ try:
156
+ rel_path = get_relative_path(arr_path, path)
157
+ except ValueError:
158
+ continue
159
+
160
+ dataset = arr_group.get(f"arr_{arr_idx}")
161
+
162
+ if dataset_copy:
163
+ dataset = dataset[:]
164
+
165
+ if rel_path:
166
+ set_in_container(data, rel_path, dataset)
167
+ else:
168
+ data = dataset
169
+
170
+ return data
171
+
172
+
173
+ class ZarrEncodable:
174
+ """
175
+ Base class of data that can be converted to and from zarr form.
176
+ """
177
+
178
+ _typ = None
179
+
180
+ def to_dict(self) -> dict[str, Any]:
181
+ """
182
+ Convert this object to a dict.
183
+ """
184
+ if hasattr(self, "__dict__"):
185
+ return dict(self.__dict__)
186
+ elif hasattr(self, "__slots__"):
187
+ return {k: getattr(self, k) for k in self.__slots__}
188
+ else:
189
+ # Should be unreachable
190
+ return {}
191
+
192
+ def to_zarr(self, zarr_group: zarr.Group):
193
+ """
194
+ Save this object into the given zarr group.
195
+ """
196
+ zarr_encode(self.to_dict(), zarr_group, is_pending_add=False, is_set=False)
197
+
198
+ @classmethod
199
+ def from_zarr(cls, zarr_group: zarr.Group, dataset_copy: bool = False) -> Self:
200
+ """
201
+ Read an instance of this class from the given zarr group.
202
+ """
203
+ # FIXME: Do the read of the data!
204
+ param_data = None
205
+ data = zarr_decode(param_data, zarr_group, dataset_copy=dataset_copy)
206
+ return cls(**data)
@@ -0,0 +1,13 @@
1
+ """
2
+ YAML schemas.
3
+
4
+ Contents:
5
+
6
+ * ``config_file_schema.yaml`` – Schema for configuration selection files.
7
+ * ``config_schema.yaml`` – Schema for configuration files.
8
+ * ``environments_spec_schema.yaml`` – Schema for execution environment definition files.
9
+ * ``files_spec_schema.yaml`` – Schema for input/output specification files.
10
+ * ``parameters_spec_schema.yaml`` – Schema for parameter specification files.
11
+ * ``task_schema_spec_schema.yaml`` – Schema for task template specification files.
12
+ * ``workflow_spec_schema.yaml`` – Schema for workflow files.
13
+ """
@@ -0,0 +1,34 @@
1
+ rules:
2
+ - path: []
3
+ condition:
4
+ and:
5
+ - value.required_keys:
6
+ - configs
7
+ - value.allowed_keys:
8
+ - configs
9
+
10
+ - path: [configs]
11
+ doc: >
12
+ A mapping of string config "invocation keys" to configuration settings.
13
+ condition:
14
+ and:
15
+ - value.type.equal_to: dict
16
+ - value.keys_is_instance: [str]
17
+
18
+ - path: [configs, { type: map_value }]
19
+ condition:
20
+ and:
21
+ - value.type.equal_to: dict
22
+ - value.required_keys:
23
+ - invocation
24
+ - config
25
+
26
+ - path: [configs, { type: map_value }, invocation]
27
+ condition:
28
+ value.allowed_keys:
29
+ - environment_setup
30
+ - match
31
+
32
+ - path: [configs, { type: map_value }, invocation, match]
33
+ condition:
34
+ value.type.equal_to: dict
@@ -0,0 +1,260 @@
1
+ rules:
2
+ - path: []
3
+ condition:
4
+ value.allowed_keys:
5
+ - machine
6
+ - user_name
7
+ - user_orcid
8
+ - user_affiliations
9
+ - linux_release_file
10
+ - log_file_path
11
+ - log_file_level
12
+ - log_console_level
13
+ - task_schema_sources
14
+ - parameter_sources
15
+ - command_file_sources
16
+ - environment_sources
17
+ - default_scheduler
18
+ - default_shell
19
+ - schedulers
20
+ - shells
21
+ - demo_data_dir
22
+ - demo_data_manifest_file
23
+ - default_workflow_path
24
+ - workflow_name_use_dir
25
+ - workflow_name_add_timestamp
26
+ - path: []
27
+ condition:
28
+ value.required_keys:
29
+ - machine
30
+ - task_schema_sources
31
+ - parameter_sources
32
+ - command_file_sources
33
+ - environment_sources
34
+ - default_scheduler
35
+ - default_shell
36
+ - schedulers
37
+ - path: []
38
+ condition:
39
+ value.forbidden_keys:
40
+ - config_directory # Config metadata
41
+ - config_file_name # Config metadata
42
+ - config_file_path # Config metadata
43
+ - config_file_contents # Config metadata
44
+ - config_key # Config metadata
45
+ - config_schemas # Config metadata
46
+ - invoking_user_id # Config metadata
47
+ - host_user_id # Config metadata
48
+ - host_user_id_file_path # Config metadata
49
+ - config_callback # Config method
50
+ - get_all # Config method
51
+ - get # Config method
52
+ - set # Config method
53
+ - _set # Config method
54
+ - unset # Config method
55
+ - save # Config method
56
+ - reload # Config method
57
+
58
+ - path: [machine]
59
+ doc: >
60
+ A label that references the current machine. By default, this uses the return from
61
+ the Python function `socket.gethostname()`.
62
+ condition:
63
+ value.type.equal_to: str
64
+
65
+ - path: [user_name]
66
+ condition:
67
+ value.type.equal_to: str
68
+
69
+ - path: [user_orcid]
70
+ condition:
71
+ value.type.equal_to: str
72
+
73
+ - path: [user_affiliations]
74
+ condition:
75
+ value.type.equal_to: list
76
+
77
+ - path: [user_affiliations, { type: list_value }]
78
+ condition:
79
+ value.is_instance: [str]
80
+
81
+ - path: [linux_release_file]
82
+ condition:
83
+ value.type.equal_to: str
84
+
85
+ - path: [log_file_path]
86
+ doc:
87
+ - >
88
+ File path to the app log file. The variables `<<app_name>>` and `<<app_version>>`
89
+ are available to be used in this option, which resolve to the app name and version,
90
+ respectively.
91
+ - >
92
+ The file path may be nested in non-existent directories, in which case
93
+ those directories will be generated. If specified as a relative path, the path will
94
+ be resolved relative to the config directory (the directory that contains the config
95
+ file).
96
+ condition:
97
+ value.is_instance: [str, path]
98
+
99
+ - path: [log_file_level]
100
+ condition:
101
+ and:
102
+ - value.type.equal_to: str
103
+ - value.in: [notset, debug, info, warning, error, critical]
104
+
105
+ - path: [log_console_level]
106
+ condition:
107
+ and:
108
+ - value.type.equal_to: str
109
+ - value.in: [notset, debug, info, warning, error, critical]
110
+
111
+ - path: [task_schema_sources]
112
+ condition:
113
+ value.type.equal_to: list
114
+
115
+ - path: [environment_sources]
116
+ condition:
117
+ value.type.equal_to: list
118
+
119
+ - path: [parameter_sources]
120
+ condition:
121
+ value.type.equal_to: list
122
+
123
+ - path: [command_file_sources]
124
+ condition:
125
+ value.type.equal_to: list
126
+
127
+ - path: [task_schema_sources, { type: list_value }]
128
+ condition:
129
+ value.is_instance: [str, path]
130
+
131
+ - path: [environment_sources, { type: list_value }]
132
+ condition:
133
+ value.is_instance: [str, path]
134
+
135
+ - path: [parameter_sources, { type: list_value }]
136
+ condition:
137
+ value.is_instance: [str, path]
138
+
139
+ - path: [command_file_sources, { type: list_value }]
140
+ condition:
141
+ value.is_instance: [str, path]
142
+
143
+ - path: [default_scheduler]
144
+ condition:
145
+ value.in: [direct, sge, slurm]
146
+
147
+ - path: [default_shell]
148
+ condition:
149
+ value.in: [powershell, bash, wsl, wsl+bash]
150
+
151
+ - path: [schedulers]
152
+ condition:
153
+ value.allowed_keys: [direct, direct_posix, sge, slurm]
154
+
155
+ - path: [schedulers, { type: map_value }]
156
+ condition:
157
+ value.allowed_keys: [defaults, parallel_environments, partitions] # TODO split these up based on scheduler type
158
+
159
+ - path: [schedulers, { type: map_value }, defaults]
160
+ condition:
161
+ value.allowed_keys: # TODO: split these up based on scheduler type
162
+ - shebang_executable
163
+ - directives # TODO: only actually allowed in `QueuedScheduler` sub-classes
164
+ - options # deprecated, replaced by directives
165
+ - submit_cmd
166
+ - show_cmd
167
+ - del_cmd
168
+ - js_cmd
169
+ - array_switch
170
+ - array_item_var
171
+ - cwd_switch
172
+
173
+ - path: [schedulers, sge]
174
+ condition:
175
+ value.type.equal_to: dict
176
+
177
+ - path: [schedulers, sge, parallel_environments]
178
+ condition:
179
+ value.type.equal_to: dict
180
+
181
+ - path: [schedulers, sge, parallel_environments, { type: map_value }]
182
+ condition:
183
+ and:
184
+ - value.allowed_keys:
185
+ - num_cores
186
+ - num_nodes
187
+ - parallel_modes
188
+ - value.required_keys:
189
+ - num_cores
190
+
191
+ - path: [schedulers, slurm]
192
+ condition:
193
+ value.type.equal_to: dict
194
+
195
+ - path: [schedulers, slurm, partitions]
196
+ condition:
197
+ value.type.equal_to: dict
198
+
199
+ - path: [schedulers, slurm, partitions, { type: map_value }]
200
+ condition:
201
+ and:
202
+ - value.allowed_keys:
203
+ - num_cores
204
+ - num_nodes
205
+ - num_cores_per_node
206
+ - parallel_modes
207
+ - value.required_keys:
208
+ - num_cores
209
+
210
+ - path: [shells]
211
+ condition:
212
+ value.allowed_keys: [powershell, bash, wsl, wsl+bash]
213
+
214
+ - path: [shells, { type: map_value }]
215
+ condition:
216
+ value.allowed_keys: [defaults]
217
+
218
+ - path: [shells, { type: map_value }, defaults]
219
+ condition:
220
+ value.allowed_keys:
221
+ - executable
222
+ - executable_args
223
+ - os_args
224
+ - WSL_executable
225
+ - WSL_distribution
226
+ - WSL_user
227
+
228
+ - path: [demo_data_dir]
229
+ doc: >
230
+ If provided, this will be used as the path to the directory containing demo data
231
+ files. This can be a local path or an fsspec URL.
232
+ condition:
233
+ value.is_instance: [str, path]
234
+
235
+ - path: [demo_data_manifest_file]
236
+ doc: >
237
+ If provided, this will be used as the path to the manifest for the built-in example
238
+ data files. It should point to a JSON file whose top-level keys are example data
239
+ file names. Each value should be an empty map/dict or a map like: `{"in_zip": "text_file.zip"}`,
240
+ where `text_file.zip` is the name of a zip archive that contains the example data
241
+ file. This can be a local path or an fsspec URL.
242
+ condition:
243
+ value.is_instance: [str, path]
244
+
245
+ - path: [default_workflow_path]
246
+ doc: Default directory path in which new workflows will be generated.
247
+ condition:
248
+ value.is_instance: [str, path]
249
+
250
+ - path: [workflow_name_add_timestamp]
251
+ doc: By default, whether to suffix the workflow name with a date-timestamp.
252
+ condition:
253
+ value.is_instance: [bool]
254
+
255
+ - path: [workflow_name_add_timestamp]
256
+ doc: >
257
+ By default, whether to use a directory named according to the workflow name, and
258
+ a separate child directory named according to the date-timestamp if present.
259
+ condition:
260
+ value.is_instance: [bool]
@@ -0,0 +1,21 @@
1
+ rules:
2
+ - path: []
3
+ condition:
4
+ {
5
+ value.allowed_keys: [name, setup, executables, specifiers, doc, _hash_value],
6
+ }
7
+ - path: [setup]
8
+ condition:
9
+ or:
10
+ - value.type.equal_to: str
11
+ - value.null: null
12
+ - path: [executables]
13
+ condition: { value.type.equal_to: list }
14
+ - path: [executables, { type: list_value }]
15
+ condition: { value.allowed_keys: [label, instances] }
16
+ - path: [executables, { type: list_value }, instances]
17
+ condition: { value.type.equal_to: list }
18
+ - path: [executables, { type: list_value }, instances, { type: list_value }]
19
+ condition: { value.type.equal_to: dict }
20
+ - path: [executables, { type: list_value }, instances, { type: list_value }]
21
+ condition: { value.allowed_keys: [command, num_cores, parallel_mode] }
@@ -0,0 +1,5 @@
1
+ rules:
2
+ - path: []
3
+ condition: { value.allowed_keys: [label, name, doc, _hash_value] }
4
+ - path: [name]
5
+ condition: { value.allowed_keys: [name, args, is_regex] }
@@ -0,0 +1,7 @@
1
+ rules:
2
+ - path: []
3
+ condition:
4
+ {
5
+ value.allowed_keys:
6
+ [type, sub_parameters, is_file, _hash_value, _validation],
7
+ }
@@ -0,0 +1,3 @@
1
+ rules:
2
+ - path: [inputs, { type: list_value }]
3
+ condition: { value.type.equal_to: dict }
@@ -0,0 +1,22 @@
1
+ rules:
2
+ - path: []
3
+ condition:
4
+ value.allowed_keys:
5
+ - doc
6
+ - name
7
+ - source_file
8
+ - resources
9
+ - config
10
+ - environments
11
+ - env_presets
12
+ - template_components
13
+ - tasks
14
+ - meta_tasks
15
+ - loops
16
+ - store_kwargs
17
+ - merge_resources
18
+ - merge_envs
19
+ - workflow
20
+
21
+ - path: [tasks]
22
+ condition: { value.type.equal_to: list }
@@ -0,0 +1,3 @@
1
+ """
2
+ Demonstration code.
3
+ """