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,666 @@
1
+ from __future__ import annotations
2
+ from pathlib import Path
3
+ from textwrap import dedent
4
+ from typing import Any, TYPE_CHECKING
5
+ import pytest
6
+ from hpcflow.app import app as hf
7
+ from hpcflow.sdk.core.errors import UnsetParameterDataError
8
+ from hpcflow.sdk.core.test_utils import (
9
+ make_schemas,
10
+ P1_parameter_cls as P1,
11
+ P1_sub_parameter_cls as P1_sub,
12
+ )
13
+
14
+ if TYPE_CHECKING:
15
+ from hpcflow.sdk.core.workflow import Workflow
16
+
17
+
18
+ @pytest.fixture
19
+ def workflow_w1(null_config, tmp_path: Path) -> Workflow:
20
+ s1, s2 = make_schemas(
21
+ ({"p1": None}, ("p2",), "t1"),
22
+ ({"p2": None}, (), "t2"),
23
+ )
24
+
25
+ t1 = hf.Task(
26
+ schema=s1,
27
+ sequences=[hf.ValueSequence("inputs.p1", values=[101, 102], nesting_order=1)],
28
+ )
29
+ t2 = hf.Task(schema=s2, nesting_order={"inputs.p2": 1})
30
+
31
+ wkt = hf.WorkflowTemplate(name="w1", tasks=[t1, t2])
32
+ return hf.Workflow.from_template(wkt, path=tmp_path)
33
+
34
+
35
+ def test_element_task_dependencies(workflow_w1: Workflow):
36
+ assert workflow_w1.tasks.t2.elements[0].get_task_dependencies(as_objects=True) == [
37
+ workflow_w1.tasks.t1
38
+ ]
39
+
40
+
41
+ def test_element_dependent_tasks(workflow_w1: Workflow):
42
+ assert workflow_w1.tasks.t1.elements[0].get_dependent_tasks(as_objects=True) == [
43
+ workflow_w1.tasks.t2
44
+ ]
45
+
46
+
47
+ def test_element_element_dependencies(workflow_w1: Workflow):
48
+ assert workflow_w1.tasks.t2.elements[0].get_element_dependencies() == {0}
49
+ assert workflow_w1.tasks.t2.elements[1].get_element_dependencies() == {1}
50
+
51
+
52
+ def test_element_dependent_elements(workflow_w1: Workflow):
53
+ assert workflow_w1.tasks.t1.elements[0].get_dependent_elements() == {2}
54
+ assert workflow_w1.tasks.t1.elements[1].get_dependent_elements() == {3}
55
+
56
+
57
+ def test_equivalence_single_labelled_schema_input_element_get_label_and_non_label(
58
+ new_null_config, tmp_path: Path
59
+ ):
60
+ s1 = hf.TaskSchema(
61
+ objective="t1",
62
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"), labels={"one": {}})],
63
+ actions=[
64
+ hf.Action(
65
+ commands=[
66
+ hf.Command(command="Write-Output (<<parameter:p1[one]>> + 100)")
67
+ ]
68
+ )
69
+ ],
70
+ )
71
+ tasks = [hf.Task(schema=s1, inputs=[hf.InputValue("p1", label="one", value=101)])]
72
+ wk = hf.Workflow.from_template_data(
73
+ tasks=tasks,
74
+ path=tmp_path,
75
+ template_name="wk0",
76
+ )
77
+ assert wk.tasks.t1.elements[0].get("inputs.p1") == wk.tasks.t1.elements[0].get(
78
+ "inputs.p1[one]"
79
+ )
80
+
81
+
82
+ def test_element_dependencies_inputs_only_schema(new_null_config, tmp_path: Path):
83
+ s1 = hf.TaskSchema(
84
+ objective="t1",
85
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1"))],
86
+ outputs=[hf.SchemaInput(parameter=hf.Parameter("p2"))],
87
+ actions=[
88
+ hf.Action(
89
+ commands=[
90
+ hf.Command(
91
+ command="Write-Output (<<parameter:p1>> + 100)",
92
+ stdout="<<parameter:p2>>",
93
+ )
94
+ ]
95
+ )
96
+ ],
97
+ )
98
+ s2 = hf.TaskSchema(
99
+ objective="t2",
100
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p2"))],
101
+ )
102
+ tasks = [
103
+ hf.Task(
104
+ schema=s1,
105
+ inputs=[hf.InputValue("p1", value=101)],
106
+ ),
107
+ hf.Task(schema=s2),
108
+ ]
109
+ wk = hf.Workflow.from_template_data(
110
+ tasks=tasks,
111
+ path=tmp_path,
112
+ template_name="wk0",
113
+ )
114
+ assert wk.tasks.t1.elements[0].get_dependent_elements() == {1}
115
+ assert wk.tasks.t2.elements[0].get_element_dependencies() == {0}
116
+ assert wk.tasks.t2.elements[0].get_EAR_dependencies() == {0}
117
+
118
+
119
+ def test_element_get_empty_path_single_labelled_input(null_config, tmp_path: Path):
120
+ p1_val = 101
121
+ label = "my_label"
122
+ s1 = hf.TaskSchema(
123
+ objective="t1", inputs=[hf.SchemaInput(parameter="p1", labels={label: {}})]
124
+ )
125
+ t1 = hf.Task(schema=[s1], inputs=[hf.InputValue("p1", p1_val, label=label)])
126
+ wk = hf.Workflow.from_template_data(
127
+ tasks=[t1],
128
+ path=tmp_path,
129
+ template_name="temp",
130
+ )
131
+ assert wk.tasks[0].elements[0].get() == {
132
+ "resources": {"any": {}},
133
+ "inputs": {"p1": p1_val},
134
+ }
135
+
136
+
137
+ def test_element_get_labelled_non_labelled_equivalence(null_config, tmp_path: Path):
138
+ p1_val = 101
139
+ label = "my_label"
140
+ s1 = hf.TaskSchema(
141
+ objective="t1", inputs=[hf.SchemaInput(parameter="p1", labels={label: {}})]
142
+ )
143
+ t1 = hf.Task(schema=[s1], inputs=[hf.InputValue("p1", p1_val, label=label)])
144
+ wk = hf.Workflow.from_template_data(
145
+ tasks=[t1],
146
+ path=tmp_path,
147
+ template_name="temp",
148
+ )
149
+ assert wk.tasks[0].elements[0].get("inputs.p1") == wk.tasks[0].elements[0].get(
150
+ f"inputs.p1[{label}]"
151
+ )
152
+
153
+
154
+ @pytest.fixture
155
+ def element_get_wk(null_config, tmp_path: Path) -> Workflow:
156
+ s1 = hf.TaskSchema(
157
+ objective="t1",
158
+ inputs=[hf.SchemaInput(parameter="p1"), hf.SchemaInput(parameter="p1c")],
159
+ outputs=[hf.SchemaOutput(parameter="p2")],
160
+ actions=[
161
+ hf.Action(
162
+ commands=[
163
+ hf.Command(
164
+ command="Write-Output (<<parameter:p1>> + <<parameter:p1c>>)",
165
+ stdout="<<int(parameter:p2)>>",
166
+ )
167
+ ],
168
+ ),
169
+ ],
170
+ parameter_class_modules=["hpcflow.sdk.core.test_utils"],
171
+ )
172
+ p1_value = 100
173
+ p1c_value = P1(a=10, sub_param=P1_sub(e=5))
174
+ t1 = hf.Task(
175
+ schema=s1,
176
+ inputs=[
177
+ hf.InputValue("p1", value=p1_value),
178
+ hf.InputValue("p1c", value=p1c_value),
179
+ ],
180
+ sequences=[hf.ValueSequence("inputs.p1c.a", values=[20, 30], nesting_order=0)],
181
+ )
182
+ wk = hf.Workflow.from_template_data(
183
+ tasks=[t1],
184
+ template_name="w1",
185
+ path=tmp_path,
186
+ )
187
+ return wk
188
+
189
+
190
+ def test_element_get_simple(element_get_wk: Workflow):
191
+ assert element_get_wk.tasks.t1.elements[0].get("inputs.p1") == 100
192
+ assert element_get_wk.tasks.t1.elements[1].get("inputs.p1") == 100
193
+
194
+
195
+ def test_element_get_obj(element_get_wk: Workflow):
196
+ obj_0 = P1(a=20, sub_param=P1_sub(e=5))
197
+ obj_1 = P1(a=30, sub_param=P1_sub(e=5))
198
+ assert element_get_wk.tasks.t1.elements[0].get("inputs.p1c") == obj_0
199
+ assert element_get_wk.tasks.t1.elements[1].get("inputs.p1c") == obj_1
200
+
201
+
202
+ def test_element_get_sub_obj(element_get_wk: Workflow):
203
+ sub_obj = P1_sub(e=5)
204
+ assert element_get_wk.tasks.t1.elements[0].get("inputs.p1c.sub_param") == sub_obj
205
+ assert element_get_wk.tasks.t1.elements[1].get("inputs.p1c.sub_param") == sub_obj
206
+
207
+
208
+ def test_element_get_sub_obj_attr(element_get_wk: Workflow):
209
+ assert element_get_wk.tasks.t1.elements[0].get("inputs.p1c.sub_param.e") == 5
210
+ assert element_get_wk.tasks.t1.elements[1].get("inputs.p1c.sub_param.e") == 5
211
+
212
+
213
+ def test_element_get_sub_obj_property(element_get_wk: Workflow):
214
+ assert element_get_wk.tasks.t1.elements[0].get("inputs.p1c.sub_param.twice_e") == 10
215
+ assert element_get_wk.tasks.t1.elements[1].get("inputs.p1c.sub_param.twice_e") == 10
216
+
217
+
218
+ def test_element_get_obj_no_raise_missing_attr(element_get_wk: Workflow):
219
+ assert element_get_wk.tasks.t1.elements[0].get("inputs.p1c.b") is None
220
+
221
+
222
+ def test_element_get_obj_raise_missing_attr(element_get_wk: Workflow):
223
+ with pytest.raises(ValueError):
224
+ element_get_wk.tasks.t1.elements[0].get("inputs.p1c.b", raise_on_missing=True)
225
+
226
+
227
+ def test_element_get_obj_raise_missing_nested_attr(element_get_wk: Workflow):
228
+ with pytest.raises(ValueError):
229
+ element_get_wk.tasks.t1.elements[0].get("inputs.p1c.a.b", raise_on_missing=True)
230
+
231
+
232
+ def test_element_get_raise_missing_root(element_get_wk: Workflow):
233
+ with pytest.raises(ValueError):
234
+ element_get_wk.tasks.t1.elements[0].get("blah", raise_on_missing=True)
235
+
236
+
237
+ def test_element_get_no_raise_missing_root(element_get_wk: Workflow):
238
+ assert element_get_wk.tasks.t1.elements[0].get("blah") is None
239
+
240
+
241
+ def test_element_get_expected_default(element_get_wk: Workflow):
242
+ assert element_get_wk.tasks.t1.elements[0].get("blah", default={}) == {}
243
+
244
+
245
+ def test_element_get_part_unset(null_config, tmp_path: Path):
246
+ s1 = hf.TaskSchema(
247
+ objective="t1",
248
+ inputs=[hf.SchemaInput(parameter="p1")],
249
+ outputs=[hf.SchemaOutput(parameter="p2")],
250
+ actions=[
251
+ hf.Action(
252
+ commands=[
253
+ hf.Command(
254
+ command="Write-Output (<<parameter:p1>> + 100)",
255
+ stdout="<<parameter:p2>>",
256
+ )
257
+ ],
258
+ ),
259
+ ],
260
+ parameter_class_modules=["hpcflow.sdk.core.test_utils"],
261
+ )
262
+ s2 = hf.TaskSchema(objective="t2", inputs=[hf.SchemaInput(parameter="p2")])
263
+
264
+ t1 = hf.Task(
265
+ schema=s1,
266
+ inputs=[hf.InputValue("p1", value=1)],
267
+ )
268
+ t2 = hf.Task(schema=s2, inputs=[hf.InputValue("p2", path="a", value=2)])
269
+
270
+ wk = hf.Workflow.from_template_data(
271
+ tasks=[t1, t2],
272
+ template_name="w1",
273
+ path=tmp_path,
274
+ )
275
+
276
+ # "inputs.p2.a" is set (local) but "inputs.p2" is unset (from task 1), so value of
277
+ # "p2" should be `None`:
278
+ assert wk.tasks.t2.elements[0].get() == {
279
+ "resources": {"any": {}},
280
+ "inputs": {"p2": None},
281
+ }
282
+ assert wk.tasks.t2.elements[0].get("inputs") == {"p2": None}
283
+ assert wk.tasks.t2.elements[0].get("inputs.p2") == None
284
+
285
+ # but value of "p2.a" should be accessible:
286
+ assert wk.tasks.t2.elements[0].get("inputs.p2.a") == 2
287
+
288
+ with pytest.raises(UnsetParameterDataError):
289
+ wk.tasks.t2.elements[0].get(raise_on_unset=True)
290
+
291
+ with pytest.raises(UnsetParameterDataError):
292
+ wk.tasks.t2.elements[0].get("inputs", raise_on_unset=True)
293
+
294
+ with pytest.raises(UnsetParameterDataError):
295
+ wk.tasks.t2.elements[0].get("inputs.p2", raise_on_unset=True)
296
+
297
+
298
+ def test_element_get_unset_object(null_config, tmp_path: Path):
299
+ s1 = hf.TaskSchema(
300
+ objective="t1",
301
+ inputs=[hf.SchemaInput(parameter="p1")],
302
+ outputs=[hf.SchemaOutput(parameter="p1c")],
303
+ actions=[
304
+ hf.Action(
305
+ commands=[
306
+ hf.Command(
307
+ command="Write-Output (<<parameter:p1>> + 100)",
308
+ stdout="<<parameter:p1c>>",
309
+ )
310
+ ],
311
+ ),
312
+ ],
313
+ parameter_class_modules=["hpcflow.sdk.core.test_utils"],
314
+ )
315
+ t1 = hf.Task(
316
+ schema=s1,
317
+ inputs=[hf.InputValue("p1", value=1)],
318
+ )
319
+ wk = hf.Workflow.from_template_data(
320
+ tasks=[t1],
321
+ template_name="w1",
322
+ path=tmp_path,
323
+ )
324
+ assert wk.tasks.t1.elements[0].get("outputs.p1c") == None
325
+
326
+
327
+ def test_element_get_unset_sub_object(null_config, tmp_path: Path):
328
+ s1 = hf.TaskSchema(
329
+ objective="t1",
330
+ inputs=[hf.SchemaInput(parameter="p1")],
331
+ outputs=[hf.SchemaOutput(parameter="p1c")],
332
+ actions=[
333
+ hf.Action(
334
+ commands=[
335
+ hf.Command(
336
+ command="Write-Output (<<parameter:p1>> + 100)",
337
+ stdout="<<parameter:p1c.CLI_parse(e=10)>>",
338
+ )
339
+ ],
340
+ ),
341
+ ],
342
+ parameter_class_modules=["hpcflow.sdk.core.test_utils"],
343
+ )
344
+ t1 = hf.Task(
345
+ schema=s1,
346
+ inputs=[hf.InputValue("p1", value=1)],
347
+ )
348
+ wk = hf.Workflow.from_template_data(
349
+ tasks=[t1],
350
+ template_name="w1",
351
+ path=tmp_path,
352
+ )
353
+ assert wk.tasks.t1.elements[0].get("outputs.p1c.sub_param") == None
354
+
355
+
356
+ def test_element_get_unset_object_group(null_config, tmp_path: Path):
357
+ s1 = hf.TaskSchema(
358
+ objective="t1",
359
+ inputs=[hf.SchemaInput(parameter="p1c")],
360
+ outputs=[hf.SchemaOutput(parameter="p1c")],
361
+ actions=[
362
+ hf.Action(
363
+ commands=[
364
+ hf.Command(
365
+ command="Write-Output (<<parameter:p1c>> + 100)",
366
+ stdout="<<parameter:p1c.CLI_parse()>>",
367
+ )
368
+ ],
369
+ ),
370
+ ],
371
+ parameter_class_modules=["hpcflow.sdk.core.test_utils"],
372
+ )
373
+ s2 = hf.TaskSchema(
374
+ objective="t2",
375
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1c"), group="my_group")],
376
+ )
377
+
378
+ t1 = hf.Task(
379
+ schema=s1,
380
+ inputs=[hf.InputValue("p1c", value=P1(a=10, sub_param=P1_sub(e=5)))],
381
+ sequences=[hf.ValueSequence("inputs.p1c.a", values=[20, 30], nesting_order=0)],
382
+ groups=[hf.ElementGroup(name="my_group")],
383
+ )
384
+ t2 = hf.Task(
385
+ schema=s2,
386
+ nesting_order={"inputs.p1c": 0},
387
+ )
388
+ wk = hf.Workflow.from_template_data(
389
+ tasks=[t1, t2],
390
+ template_name="w1",
391
+ path=tmp_path,
392
+ )
393
+ assert wk.tasks.t2.elements[0].get("inputs.p1c") == [None, None]
394
+
395
+
396
+ def test_element_get_unset_sub_object_group(null_config, tmp_path: Path):
397
+ s1 = hf.TaskSchema(
398
+ objective="t1",
399
+ inputs=[hf.SchemaInput(parameter="p1c")],
400
+ outputs=[hf.SchemaOutput(parameter="p1c")],
401
+ actions=[
402
+ hf.Action(
403
+ commands=[
404
+ hf.Command(
405
+ command="Write-Output (<<parameter:p1c>> + 100)",
406
+ stdout="<<parameter:p1c.CLI_parse(e=10)>>",
407
+ )
408
+ ],
409
+ ),
410
+ ],
411
+ parameter_class_modules=["hpcflow.sdk.core.test_utils"],
412
+ )
413
+ s2 = hf.TaskSchema(
414
+ objective="t2",
415
+ inputs=[hf.SchemaInput(parameter=hf.Parameter("p1c"), group="my_group")],
416
+ )
417
+
418
+ t1 = hf.Task(
419
+ schema=s1,
420
+ inputs=[hf.InputValue("p1c", value=P1(a=10, sub_param=P1_sub(e=5)))],
421
+ sequences=[hf.ValueSequence("inputs.p1c.a", values=[20, 30], nesting_order=0)],
422
+ groups=[hf.ElementGroup(name="my_group")],
423
+ )
424
+ t2 = hf.Task(
425
+ schema=s2,
426
+ nesting_order={"inputs.p1c": 0},
427
+ )
428
+ wk = hf.Workflow.from_template_data(
429
+ tasks=[t1, t2],
430
+ template_name="w1",
431
+ path=tmp_path,
432
+ )
433
+ assert wk.tasks.t2.elements[0].get("inputs.p1c.sub_param") == [None, None]
434
+
435
+
436
+ def test_iter(new_null_config, tmp_path: Path):
437
+ wkt = hf.WorkflowTemplate(
438
+ name="test",
439
+ tasks=[
440
+ hf.Task(
441
+ schema=hf.task_schemas.test_t1_ps,
442
+ sequences=[hf.ValueSequence(path="inputs.p1", values=[1, 2, 3])],
443
+ ),
444
+ ],
445
+ )
446
+ wk = hf.Workflow.from_template(wkt, path=tmp_path)
447
+ for idx, elem_i in enumerate(wk.tasks[0].elements):
448
+ assert elem_i.index == idx
449
+
450
+
451
+ def test_slice(new_null_config, tmp_path: Path):
452
+ wkt = hf.WorkflowTemplate(
453
+ name="test",
454
+ tasks=[
455
+ hf.Task(
456
+ schema=hf.task_schemas.test_t1_ps,
457
+ sequences=[hf.ValueSequence(path="inputs.p1", values=[1, 2, 3])],
458
+ ),
459
+ ],
460
+ )
461
+ wk = hf.Workflow.from_template(wkt, path=tmp_path)
462
+ elems = wk.tasks[0].elements[0::2]
463
+ assert len(elems) == 2
464
+ assert elems[0].index == 0
465
+ assert elems[1].index == 2
466
+
467
+
468
+ def test_element_get_with_list_index_sequence(null_config, tmp_path: Path):
469
+ wkt_yaml = dedent(
470
+ """\
471
+ name: test_list_idx_sequence
472
+ tasks:
473
+ - schema: test_t1_ps
474
+ inputs:
475
+ p1: [0, 1]
476
+ sequences:
477
+ - path: inputs.p1.0
478
+ values: [9]
479
+ """
480
+ )
481
+ wkt = hf.WorkflowTemplate.from_YAML_string(wkt_yaml)
482
+ wk = hf.Workflow.from_template(wkt, path=tmp_path)
483
+ assert wk.tasks[0].elements[0].get("inputs.p1") == [9, 1]
484
+
485
+
486
+ def test_element_get_with_list_index_sequence_two_parts(null_config, tmp_path: Path):
487
+ wkt_yaml = dedent(
488
+ """\
489
+ name: test_list_idx_sequence
490
+ tasks:
491
+ - schema: test_t1_ps
492
+ inputs:
493
+ p1: [
494
+ [0, 1],
495
+ [2, 3],
496
+ ]
497
+ sequences:
498
+ - path: inputs.p1.0.1
499
+ values: [9, 99]
500
+ """
501
+ )
502
+ wkt = hf.WorkflowTemplate.from_YAML_string(wkt_yaml)
503
+ wk = hf.Workflow.from_template(wkt, path=tmp_path)
504
+ assert wk.tasks[0].elements[0].get("inputs.p1") == [
505
+ [0, 9],
506
+ [2, 3],
507
+ ]
508
+ assert wk.tasks[0].elements[1].get("inputs.p1") == [
509
+ [0, 99],
510
+ [2, 3],
511
+ ]
512
+
513
+
514
+ def test_element_get_group_sequence(null_config, tmp_path: Path):
515
+ wkt_yaml = dedent(
516
+ """\
517
+ name: test_list_idx_sequence
518
+ template_components:
519
+ task_schemas:
520
+ - objective: test_group_schema
521
+ inputs:
522
+ - parameter: p1
523
+ group: my_group
524
+ tasks:
525
+ - schema: test_t1_ps
526
+ inputs:
527
+ p1:
528
+ a: 1
529
+ sequences:
530
+ - path: inputs.p1.b
531
+ values: [8, 9]
532
+ groups:
533
+ - name: my_group
534
+ - schema: test_group_schema
535
+ """
536
+ )
537
+ wkt = hf.WorkflowTemplate.from_YAML_string(wkt_yaml)
538
+ wk = hf.Workflow.from_template(wkt, path=tmp_path)
539
+ assert wk.tasks[1].elements[0].get("inputs") == {
540
+ "p1": [{"a": 1, "b": 8}, {"a": 1, "b": 9}]
541
+ }
542
+ assert wk.tasks[1].elements[0].get("inputs.p1") == [
543
+ {"a": 1, "b": 8},
544
+ {"a": 1, "b": 9},
545
+ ]
546
+ assert wk.tasks[1].elements[0].get("inputs.p1.b") == [
547
+ 8,
548
+ 9,
549
+ ]
550
+
551
+
552
+ def test_element_get_group_sequence_obj(new_null_config, tmp_path: Path):
553
+ wkt_yaml = dedent(
554
+ """\
555
+ name: test_list_idx_sequence
556
+ template_components:
557
+ task_schemas:
558
+ - objective: test_t1_ps_obj
559
+ parameter_class_modules: ["hpcflow.sdk.core.test_utils"]
560
+ inputs:
561
+ - parameter: p1c
562
+ outputs:
563
+ - parameter: p2
564
+ actions:
565
+ - environments:
566
+ - scope:
567
+ type: any
568
+ environment: null_env
569
+ commands:
570
+ - command: Write-Output ((<<parameter:p1c>> + 100))
571
+ stdout: <<parameter:p2>>
572
+ - objective: test_group_schema
573
+ parameter_class_modules: ["hpcflow.sdk.core.test_utils"]
574
+ inputs:
575
+ - parameter: p1c
576
+ group: my_group
577
+
578
+ tasks:
579
+ - schema: test_t1_ps_obj
580
+ inputs:
581
+ p1c:
582
+ a: 1
583
+ sequences:
584
+ - path: inputs.p1c.d
585
+ values: [8, 9]
586
+ groups:
587
+ - name: my_group
588
+ - schema: test_group_schema
589
+ """
590
+ )
591
+ wkt = hf.WorkflowTemplate.from_YAML_string(wkt_yaml)
592
+ wk = hf.Workflow.from_template(wkt, path=tmp_path)
593
+ assert wk.tasks[1].elements[0].get("inputs") == {
594
+ "p1c": [{"a": 1, "d": 8}, {"a": 1, "d": 9}]
595
+ }
596
+ assert wk.tasks[1].elements[0].get("inputs.p1c") == [
597
+ P1(a=1, d=8),
598
+ P1(a=1, d=9),
599
+ ]
600
+ assert wk.tasks[1].elements[0].get("inputs.p1c.d") == [
601
+ 8,
602
+ 9,
603
+ ]
604
+
605
+
606
+ def test_element_resources_get_jobscript_hash_equal_empty() -> None:
607
+ assert (
608
+ hf.ElementResources().get_jobscript_hash()
609
+ == hf.ElementResources().get_jobscript_hash()
610
+ )
611
+
612
+
613
+ def test_element_resources_get_jobscript_hash_unequal_num_cores() -> None:
614
+ assert (
615
+ hf.ElementResources(num_cores=1).get_jobscript_hash()
616
+ != hf.ElementResources(num_cores=2).get_jobscript_hash()
617
+ )
618
+
619
+
620
+ def test_element_resources_get_jobscript_hash_equal_num_cores() -> None:
621
+ assert (
622
+ hf.ElementResources(num_cores=1).get_jobscript_hash()
623
+ == hf.ElementResources(num_cores=1).get_jobscript_hash()
624
+ )
625
+
626
+
627
+ def test_element_resources_get_jobscript_hash_unequal_scheduler_args_empty() -> None:
628
+ assert (
629
+ hf.ElementResources().get_jobscript_hash()
630
+ != hf.ElementResources(
631
+ scheduler_args={"options": {"--time": "01:00:00"}}
632
+ ).get_jobscript_hash()
633
+ )
634
+
635
+
636
+ def test_element_resources_get_jobscript_hash_equal_non_truthy_scheduler_args() -> None:
637
+ assert (
638
+ hf.ElementResources().get_jobscript_hash()
639
+ == hf.ElementResources(scheduler_args={}).get_jobscript_hash()
640
+ )
641
+
642
+
643
+ def test_element_resources_get_jobscript_hash_unequal_scheduler_args_diff_options() -> (
644
+ None
645
+ ):
646
+ assert (
647
+ hf.ElementResources(
648
+ scheduler_args={"options": {"--time": "02:00:00"}}
649
+ ).get_jobscript_hash()
650
+ != hf.ElementResources(
651
+ scheduler_args={"options": {"--partition": "MULTICORE"}}
652
+ ).get_jobscript_hash()
653
+ )
654
+
655
+
656
+ def test_element_resources_get_jobscript_hash_unequal_scheduler_args_same_options() -> (
657
+ None
658
+ ):
659
+ assert (
660
+ hf.ElementResources(
661
+ scheduler_args={"options": {"--time": "02:00:00"}}
662
+ ).get_jobscript_hash()
663
+ != hf.ElementResources(
664
+ scheduler_args={"options": {"--time": "01:00:00"}}
665
+ ).get_jobscript_hash()
666
+ )