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,186 @@
1
+ from textwrap import dedent
2
+ import pytest
3
+ from hpcflow.app import app as hf
4
+ from hpcflow.sdk.core.errors import MissingVariableSubstitutionError
5
+ from hpcflow.sdk.core.test_utils import (
6
+ make_test_data_YAML_workflow_template,
7
+ )
8
+
9
+
10
+ def test_merge_template_level_resources_into_element_set(null_config):
11
+ wkt = hf.WorkflowTemplate(
12
+ name="w1",
13
+ tasks=[hf.Task(schema=[hf.task_schemas.test_t1_ps])],
14
+ resources={"any": {"num_cores": 1}},
15
+ )
16
+ assert wkt.tasks[0].element_sets[0].resources == hf.ResourceList.from_json_like(
17
+ {"any": {"num_cores": 1}}
18
+ )
19
+
20
+
21
+ def test_equivalence_from_YAML_and_JSON_files(null_config):
22
+ wkt_yaml = make_test_data_YAML_workflow_template("workflow_1.yaml")
23
+ wkt_json = make_test_data_YAML_workflow_template("workflow_1.json")
24
+ assert wkt_json == wkt_yaml
25
+
26
+
27
+ def test_reuse(null_config, tmp_path):
28
+ """Test we can re-use a template that has already been made persistent."""
29
+ wkt = hf.WorkflowTemplate(name="test", tasks=[])
30
+ wk1 = hf.Workflow.from_template(wkt, name="test_1", path=tmp_path)
31
+ wk2 = hf.Workflow.from_template(wkt, name="test_2", path=tmp_path)
32
+
33
+
34
+ def test_workflow_template_vars(tmp_path, new_null_config):
35
+ num_repeats = 2
36
+ wkt = make_test_data_YAML_workflow_template(
37
+ workflow_name="benchmark_N_elements.yaml",
38
+ variables={"N": num_repeats},
39
+ )
40
+ assert wkt.tasks[0].element_sets[0].repeats[0]["number"] == num_repeats
41
+
42
+
43
+ def test_workflow_template_vars_raise_no_vars(tmp_path, new_null_config):
44
+ # no default value for the variable is provided in `benchmark_N_elements`, so should
45
+ # raise if the variables dict is not passed:
46
+ with pytest.raises(MissingVariableSubstitutionError):
47
+ make_test_data_YAML_workflow_template("benchmark_N_elements.yaml")
48
+
49
+
50
+ def test_workflow_template_vars_defaults_used(tmp_path, new_null_config):
51
+ # `benchmark_script_runner` contains a default value for the variable `N`, so that
52
+ # should be used, since we don't pass any variables:
53
+ wkt = make_test_data_YAML_workflow_template("benchmark_script_runner.yaml")
54
+ assert wkt.tasks[0].element_sets[0].repeats[0]["number"] == 1
55
+
56
+
57
+ def test_workflow_template_vars_False_no_substitution(tmp_path, new_null_config):
58
+ # read a yaml template, check variables are not substituted, when `variables=False`:
59
+ wkt_yaml = dedent(
60
+ """\
61
+ name: workflow_1
62
+ tasks:
63
+ - schema: test_t1_conditional_OS
64
+ inputs:
65
+ p1: <<var:my_var>>
66
+ """
67
+ )
68
+ wkt = hf.WorkflowTemplate.from_YAML_string(wkt_yaml, variables=False)
69
+ assert wkt.tasks[0].element_sets[0].inputs[0].value == "<<var:my_var>>"
70
+
71
+
72
+ def test_env_preset_merge_simple(null_config):
73
+ s1 = hf.TaskSchema(
74
+ objective="s1",
75
+ actions=[hf.Action(environments=[hf.ActionEnvironment("my_env")])],
76
+ environment_presets={"my_env_preset": {"my_env": {"version": 1}}},
77
+ )
78
+ wkt = hf.WorkflowTemplate(
79
+ name="test",
80
+ env_presets="my_env_preset",
81
+ tasks=[hf.Task(schema=s1)],
82
+ )
83
+ assert wkt.tasks[0].element_sets[0].env_preset == "my_env_preset"
84
+ assert wkt.tasks[0].element_sets[0].resources[0].environments == {
85
+ "my_env": {"version": 1}
86
+ }
87
+
88
+
89
+ def test_env_preset_merge_simple_list(null_config):
90
+ s1 = hf.TaskSchema(
91
+ objective="s1",
92
+ actions=[hf.Action(environments=[hf.ActionEnvironment("my_env")])],
93
+ environment_presets={"my_env_preset": {"my_env": {"version": 1}}},
94
+ )
95
+ wkt = hf.WorkflowTemplate(
96
+ name="test",
97
+ env_presets=["my_env_preset", "my_other_env_preset"],
98
+ tasks=[hf.Task(schema=s1)],
99
+ )
100
+ assert wkt.tasks[0].element_sets[0].env_preset == "my_env_preset"
101
+ assert wkt.tasks[0].element_sets[0].resources[0].environments == {
102
+ "my_env": {"version": 1}
103
+ }
104
+
105
+
106
+ def test_env_preset_no_merge_existing_env_preset(null_config):
107
+ s1 = hf.TaskSchema(
108
+ objective="s1",
109
+ actions=[hf.Action(environments=[hf.ActionEnvironment("my_env")])],
110
+ environment_presets={
111
+ "env_preset_1": {"my_env": {"version": 1}},
112
+ "env_preset_2": {"my_env": {"version": 2}},
113
+ },
114
+ )
115
+ wkt = hf.WorkflowTemplate(
116
+ name="test",
117
+ env_presets="env_preset_1",
118
+ tasks=[hf.Task(schema=s1, env_preset="env_preset_2")],
119
+ )
120
+ assert wkt.tasks[0].element_sets[0].env_preset == "env_preset_2"
121
+ assert wkt.tasks[0].element_sets[0].resources[0].environments == {
122
+ "my_env": {"version": 2}
123
+ }
124
+
125
+
126
+ def test_environments_merge_simple(null_config):
127
+ s1 = hf.TaskSchema(
128
+ objective="s1",
129
+ actions=[hf.Action(environments=[hf.ActionEnvironment("my_env")])],
130
+ )
131
+ wkt = hf.WorkflowTemplate(
132
+ name="test",
133
+ environments={"my_env": {"version": 1}, "my_other_env": {"version": 2}},
134
+ tasks=[hf.Task(schema=s1)],
135
+ )
136
+ assert wkt.tasks[0].element_sets[0].environments == {"my_env": {"version": 1}}
137
+ assert wkt.tasks[0].element_sets[0].resources[0].environments == {
138
+ "my_env": {"version": 1}
139
+ }
140
+
141
+
142
+ def test_environments_no_merge_existing_envs(null_config):
143
+ s1 = hf.TaskSchema(
144
+ objective="s1",
145
+ actions=[hf.Action(environments=[hf.ActionEnvironment("my_env")])],
146
+ )
147
+ wkt = hf.WorkflowTemplate(
148
+ name="test",
149
+ environments={"my_env": {"version": 1}, "my_other_env": {"version": 2}},
150
+ tasks=[hf.Task(schema=s1, environments={"my_env": {"version": 2}})],
151
+ )
152
+ assert wkt.tasks[0].element_sets[0].environments == {"my_env": {"version": 2}}
153
+ assert wkt.tasks[0].element_sets[0].resources[0].environments == {
154
+ "my_env": {"version": 2}
155
+ }
156
+
157
+
158
+ def test_raise_on_env_preset_and_environments(null_config):
159
+ with pytest.raises(ValueError):
160
+ wkt = hf.WorkflowTemplate(
161
+ name="test",
162
+ env_presets="my_env_preset",
163
+ environments={"my_env": {"version": 1}},
164
+ )
165
+
166
+
167
+ def test_default_env_preset_used_if_available(null_config):
168
+ """Test that if no env_presets or environments are specified at template-level or task
169
+ level, the default (named as an empty string) env preset is used if available."""
170
+
171
+ s1 = hf.TaskSchema(
172
+ objective="s1",
173
+ actions=[hf.Action(environments=[hf.ActionEnvironment("my_env")])],
174
+ environment_presets={
175
+ "": {"my_env": {"version": 1}},
176
+ "env_preset_1": {"my_env": {"version": 2}},
177
+ },
178
+ )
179
+ wkt = hf.WorkflowTemplate(
180
+ name="test",
181
+ tasks=[hf.Task(schema=s1)],
182
+ )
183
+ assert wkt.tasks[0].element_sets[0].env_preset == ""
184
+ assert wkt.tasks[0].element_sets[0].resources[0].environments == {
185
+ "my_env": {"version": 1}
186
+ }
@@ -0,0 +1,40 @@
1
+ import numpy as np
2
+
3
+ from hpcflow.sdk.utils.arrays import get_1D_idx, get_2D_idx, split_arr
4
+
5
+
6
+ def test_get_2D_idx():
7
+ assert get_2D_idx(0, num_cols=10) == (0, 0)
8
+ assert get_2D_idx(4, num_cols=10) == (0, 4)
9
+ assert get_2D_idx(9, num_cols=10) == (0, 9)
10
+ assert get_2D_idx(10, num_cols=10) == (1, 0)
11
+ assert get_2D_idx(13, num_cols=10) == (1, 3)
12
+ assert get_2D_idx(20, num_cols=10) == (2, 0)
13
+ arr_r, arr_c = get_2D_idx(np.array([0, 4, 9, 10, 13, 20]), num_cols=10)
14
+ assert np.array_equal(arr_r, np.array([0, 0, 0, 1, 1, 2]))
15
+ assert np.array_equal(arr_c, np.array([0, 4, 9, 0, 3, 0]))
16
+
17
+
18
+ def test_get_1D_idx():
19
+ assert get_1D_idx(*(0, 0), num_cols=10) == 0
20
+ assert get_1D_idx(*(0, 4), num_cols=10) == 4
21
+ assert get_1D_idx(*(0, 9), num_cols=10) == 9
22
+ assert get_1D_idx(*(1, 0), num_cols=10) == 10
23
+ assert get_1D_idx(*(1, 3), num_cols=10) == 13
24
+ assert get_1D_idx(*(2, 0), num_cols=10) == 20
25
+
26
+ assert np.array_equal(
27
+ get_1D_idx(
28
+ np.array([0, 0, 0, 1, 1, 2]), np.array([0, 4, 9, 0, 3, 0]), num_cols=10
29
+ ),
30
+ np.array([0, 4, 9, 10, 13, 20]),
31
+ )
32
+
33
+
34
+ def test_split_arr():
35
+ splt = split_arr(np.array([4, 0, 1, 2, 3, 4, 1, 4, 5, 6]), metadata_size=1)
36
+ assert len(splt) == 2
37
+ assert np.array_equal(splt[0][0], np.array([0]))
38
+ assert np.array_equal(splt[0][1], np.array([1, 2, 3]))
39
+ assert np.array_equal(splt[1][0], np.array([1]))
40
+ assert np.array_equal(splt[1][1], np.array([4, 5, 6]))
@@ -0,0 +1,34 @@
1
+ from hpcflow.sdk.utils.deferred_file import DeferredFileWriter
2
+
3
+
4
+ def test_file_not_created(tmp_path):
5
+ file_name = tmp_path / "test.txt"
6
+ assert not file_name.is_file()
7
+ with DeferredFileWriter(file_name, mode="w") as fp:
8
+ assert not fp._is_open
9
+ assert not file_name.is_file()
10
+
11
+
12
+ def test_append_file_not_opened(tmp_path):
13
+ file_name = tmp_path / "test.txt"
14
+ with DeferredFileWriter(file_name, mode="a") as fp:
15
+ assert not fp._is_open
16
+ assert not file_name.is_file()
17
+
18
+
19
+ def test_file_created_write(tmp_path):
20
+ file_name = tmp_path / "test.txt"
21
+ assert not file_name.is_file()
22
+ with DeferredFileWriter(file_name, mode="w") as fp:
23
+ fp.write("contents\n")
24
+ assert fp._is_open
25
+ assert file_name.is_file()
26
+
27
+
28
+ def test_file_created_writelines(tmp_path):
29
+ file_name = tmp_path / "test.txt"
30
+ assert not file_name.is_file()
31
+ with DeferredFileWriter(file_name, mode="w") as fp:
32
+ fp.writelines(["contents\n"])
33
+ assert fp._is_open
34
+ assert file_name.is_file()
@@ -0,0 +1,65 @@
1
+ from hpcflow.sdk.utils.hashing import get_hash
2
+
3
+
4
+ def test_get_hash_simple_types_is_int():
5
+ assert isinstance(get_hash(1), int)
6
+ assert isinstance(get_hash(3.2), int)
7
+ assert isinstance(get_hash("a"), int)
8
+ assert isinstance(get_hash("abc"), int)
9
+
10
+
11
+ def test_get_hash_compound_types_is_int():
12
+ assert isinstance(get_hash([1, 2, 3]), int)
13
+ assert isinstance(get_hash((1, 2, 3)), int)
14
+ assert isinstance(get_hash({1, 2, 3}), int)
15
+ assert isinstance(get_hash({"a": 1, "b": 2, "c": 3}), int)
16
+
17
+
18
+ def test_get_hash_nested_dict_is_int():
19
+ assert isinstance(get_hash({"a": {"b": {"c": [1, 2, 3, ("4", 5, 6)]}}}), int)
20
+
21
+
22
+ def test_get_hash_distinct_simple_types():
23
+ assert get_hash(1) != get_hash(2)
24
+ assert get_hash(2.2) != get_hash(2.3)
25
+ assert get_hash("a") != get_hash("b")
26
+ assert get_hash("abc") != get_hash("ABC")
27
+
28
+
29
+ def test_get_hash_distinct_compound_types():
30
+ assert get_hash([1, 2, 3]) != get_hash([1, 2, 4])
31
+ assert get_hash((1, 2, 3)) != get_hash((1, 2, 4))
32
+ assert get_hash({1, 2, 3}) != get_hash({1, 2, 4})
33
+ assert get_hash({"a": 1, "b": 2, "c": 3}) != get_hash({"a": 1, "b": 2, "c": 4})
34
+ assert get_hash({"a": {"b": {"c": [1, 2, 3, ("4", 5, 7)]}}}) == get_hash(
35
+ {"a": {"b": {"c": [1, 2, 3, ("4", 5, 7)]}}}
36
+ )
37
+ assert get_hash({"a": 1}) != get_hash(1) != get_hash("a")
38
+
39
+
40
+ def test_get_hash_equal_simple_types():
41
+ assert get_hash(1) == get_hash(1)
42
+ assert get_hash(2.2) == get_hash(2.2)
43
+ assert get_hash("a") == get_hash("a")
44
+ assert get_hash("abc") == get_hash("abc")
45
+
46
+
47
+ def test_get_hash_equal_compound_types():
48
+ assert get_hash([1, 2, 3]) == get_hash([1, 2, 3])
49
+ assert get_hash((1, 2, 3)) == get_hash((1, 2, 3))
50
+ assert get_hash({1, 2, 3}) == get_hash({1, 2, 3})
51
+ assert get_hash({"a": 1, "b": 2, "c": 3}) == get_hash({"a": 1, "b": 2, "c": 3})
52
+ assert get_hash({"a": {"b": {"c": [1, 2, 3, ("4", 5, 6)]}}}) == get_hash(
53
+ {"a": {"b": {"c": [1, 2, 3, ("4", 5, 6)]}}}
54
+ )
55
+
56
+
57
+ def test_get_hash_order_insensitivity():
58
+ assert get_hash({"a": 1, "b": 2}) == get_hash({"b": 2, "a": 1})
59
+ assert get_hash({1, 2, 3}) == get_hash({2, 3, 1})
60
+
61
+
62
+ def test_get_hash_order_sensitivity():
63
+ assert get_hash([1, 2, 3]) != get_hash([2, 3, 1])
64
+ assert get_hash((1, 2, 3)) != get_hash((2, 3, 1))
65
+ assert get_hash("abc") != get_hash("cba")
@@ -0,0 +1,5 @@
1
+ from hpcflow.sdk.utils.patches import resolve_path
2
+
3
+
4
+ def test_absolute_path():
5
+ assert resolve_path("my_file_path").is_absolute()
@@ -0,0 +1,50 @@
1
+ import sys
2
+
3
+ import pytest
4
+ from hpcflow.sdk.core.utils import redirect_std_to_file
5
+
6
+
7
+ def test_stdout_redirect(tmp_path):
8
+ file_name = tmp_path / "test.txt"
9
+ expected = "stdout"
10
+ with redirect_std_to_file(file_name, mode="w"):
11
+ print(expected)
12
+ with file_name.open("r") as fp:
13
+ contents = fp.read().strip()
14
+ assert contents == expected
15
+
16
+
17
+ def test_stderr_redirect(tmp_path):
18
+ file_name = tmp_path / "test.txt"
19
+ expected = "stderr"
20
+ with redirect_std_to_file(file_name, mode="w"):
21
+ print(expected, file=sys.stderr)
22
+ with file_name.open("r") as fp:
23
+ contents = fp.read().strip()
24
+ assert contents == expected
25
+
26
+
27
+ def test_exception_exits_with_code(tmp_path):
28
+ file_name = tmp_path / "test.txt"
29
+ with pytest.raises(SystemExit) as exc:
30
+ with redirect_std_to_file(file_name, mode="w"):
31
+ raise ValueError("oh no!")
32
+ assert exc.value.code == 1
33
+
34
+
35
+ def test_exception_prints_to_file(tmp_path):
36
+ file_name = tmp_path / "test.txt"
37
+ with pytest.raises(SystemExit):
38
+ with redirect_std_to_file(file_name, mode="w"):
39
+ raise ValueError("oh no!")
40
+ with file_name.open("r") as fp:
41
+ contents = fp.read().strip()
42
+ assert 'ValueError("oh no!")' in contents
43
+
44
+
45
+ def test_file_not_created(tmp_path):
46
+ file_name = tmp_path / "test.txt"
47
+ assert not file_name.is_file()
48
+ with redirect_std_to_file(file_name, mode="w"):
49
+ pass
50
+ assert not file_name.is_file()
@@ -0,0 +1,97 @@
1
+ from textwrap import dedent
2
+
3
+ from hpcflow.sdk.utils.strings import extract_py_from_future_imports
4
+
5
+
6
+ def test_extract_py_from_future_imports_none():
7
+ py_str = dedent(
8
+ """\
9
+
10
+ def my_function():
11
+ print("blah!")
12
+ """
13
+ )
14
+ new_str, imports = extract_py_from_future_imports(py_str)
15
+ assert imports == set()
16
+ assert new_str == py_str
17
+
18
+
19
+ def test_extract_py_from_future_imports_single():
20
+ py_str = dedent(
21
+ """\
22
+ from __future__ import annotations
23
+
24
+ def my_function():
25
+ print("blah!")
26
+ """
27
+ )
28
+ new_str, imports = extract_py_from_future_imports(py_str)
29
+ assert imports == {"annotations"}
30
+ assert new_str == dedent(
31
+ """\
32
+
33
+ def my_function():
34
+ print("blah!")
35
+ """
36
+ )
37
+
38
+
39
+ def test_extract_py_from_future_imports_multi():
40
+ py_str = dedent(
41
+ """\
42
+ from __future__ import annotations, feature_2
43
+
44
+ def my_function():
45
+ print("blah!")
46
+ """
47
+ )
48
+ new_str, imports = extract_py_from_future_imports(py_str)
49
+ assert imports == {"annotations", "feature_2"}
50
+ assert new_str == dedent(
51
+ """\
52
+
53
+ def my_function():
54
+ print("blah!")
55
+ """
56
+ )
57
+
58
+
59
+ def test_extract_py_from_future_imports_trailing_comma():
60
+ py_str = dedent(
61
+ """\
62
+ from __future__ import annotations,
63
+
64
+ def my_function():
65
+ print("blah!")
66
+ """
67
+ )
68
+ new_str, imports = extract_py_from_future_imports(py_str)
69
+ assert imports == {"annotations"}
70
+ assert new_str == dedent(
71
+ """\
72
+
73
+ def my_function():
74
+ print("blah!")
75
+ """
76
+ )
77
+
78
+
79
+ def test_extract_py_from_future_imports_multi_lines():
80
+ py_str = dedent(
81
+ """\
82
+ from __future__ import annotations, feature_2
83
+ from __future__ import feature_2, feature_3,
84
+
85
+ def my_function():
86
+ print("blah!")
87
+ """
88
+ )
89
+ new_str, imports = extract_py_from_future_imports(py_str)
90
+ assert imports == {"annotations", "feature_2", "feature_3"}
91
+ assert new_str == dedent(
92
+ """\
93
+
94
+ def my_function():
95
+ print("blah!")
96
+ """
97
+ )
File without changes
@@ -0,0 +1,31 @@
1
+ """Tests concerning the directory structure of a created or submitted workflow"""
2
+
3
+ import os
4
+ from pathlib import Path
5
+ import pytest
6
+
7
+ from hpcflow.sdk.core.test_utils import (
8
+ make_test_data_YAML_workflow,
9
+ make_workflow_to_run_command,
10
+ )
11
+
12
+
13
+ @pytest.mark.integration
14
+ def test_std_stream_file_not_created(tmp_path, new_null_config):
15
+ """Normally, the app standard stream file should not be written."""
16
+ wk = make_test_data_YAML_workflow("workflow_1.yaml", path=tmp_path)
17
+ wk.submit(wait=True, add_to_known=False)
18
+ run = wk.get_all_EARs()[0]
19
+ std_stream_path = run.get_app_std_path()
20
+ assert not std_stream_path.is_file()
21
+
22
+
23
+ @pytest.mark.integration
24
+ def test_std_stream_file_created_on_exception_raised(tmp_path, new_null_config):
25
+ command = 'wkflow_app --std-stream "$HPCFLOW_RUN_STD_PATH" internal noop --raise'
26
+ wk = make_workflow_to_run_command(command=command, path=tmp_path)
27
+ wk.submit(wait=True, add_to_known=False)
28
+ run = wk.get_all_EARs()[0]
29
+ std_stream_path = run.get_app_std_path()
30
+ assert std_stream_path.is_file()
31
+ assert "ValueError: internal noop raised!" in std_stream_path.read_text()