hpcflow 0.1.15__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 -461
  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.15.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 -490
  236. hpcflow/archive/archive.py +0 -307
  237. hpcflow/archive/cloud/cloud.py +0 -45
  238. hpcflow/archive/cloud/errors.py +0 -9
  239. hpcflow/archive/cloud/providers/dropbox.py +0 -427
  240. hpcflow/archive/errors.py +0 -5
  241. hpcflow/base_db.py +0 -4
  242. hpcflow/config.py +0 -233
  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 -2595
  262. hpcflow/nesting.py +0 -9
  263. hpcflow/profiles.py +0 -455
  264. hpcflow/project.py +0 -81
  265. hpcflow/scheduler.py +0 -322
  266. hpcflow/utils.py +0 -103
  267. hpcflow/validation.py +0 -166
  268. hpcflow/variables.py +0 -543
  269. hpcflow-0.1.15.dist-info/METADATA +0 -168
  270. hpcflow-0.1.15.dist-info/RECORD +0 -45
  271. hpcflow-0.1.15.dist-info/entry_points.txt +0 -8
  272. hpcflow-0.1.15.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,221 @@
1
+ """
2
+ Core enumeration types.
3
+ """
4
+
5
+ from __future__ import annotations
6
+ from collections.abc import Sequence
7
+ from dataclasses import dataclass
8
+ from enum import Enum
9
+
10
+
11
+ class ActionScopeType(Enum):
12
+ """
13
+ Types of action scope.
14
+ """
15
+
16
+ #: Scope that applies to anything.
17
+ ANY = 0
18
+ #: Scope that only applies to main scripts.
19
+ MAIN = 1
20
+ #: Scope that applies to processing steps.
21
+ PROCESSING = 2
22
+ #: Scope that applies to input file generators.
23
+ INPUT_FILE_GENERATOR = 3
24
+ #: Scope that applies to output file parsers.
25
+ OUTPUT_FILE_PARSER = 4
26
+
27
+
28
+ @dataclass(frozen=True)
29
+ class _ReportableStateData:
30
+ """
31
+ Model of the state of something that is renderable using a symbol and colour.
32
+
33
+ Notes
34
+ -----
35
+ This class is used as the value in the the enumeration subclasses
36
+ :py:class:`EARStatus` and :py:class:`JobscriptElementState`.
37
+
38
+ """
39
+
40
+ #: ID that distinguishes the state.
41
+ id: int
42
+ #: Symbol to use when rendering a state.
43
+ symbol: str
44
+ #: Colour to use when rendering a state.
45
+ colour: str
46
+ #: Documentation of the meaning of the state.
47
+ __doc__: str = ""
48
+
49
+
50
+ class _ReportableStateEnum(Enum):
51
+ """Enumeration superclass for reportable state subclasses with some shared methods."""
52
+
53
+ @property
54
+ def id(self) -> int:
55
+ """
56
+ The integer ID associated with this state.
57
+ """
58
+ return self.value.id
59
+
60
+ @property
61
+ def colour(self) -> str:
62
+ """
63
+ The colour associated with this state.
64
+ """
65
+ return self.value.colour
66
+
67
+ @property
68
+ def symbol(self) -> str:
69
+ """
70
+ The symbol associated with this state.
71
+ """
72
+ return self.value.symbol
73
+
74
+ @property
75
+ def rich_repr(self) -> str:
76
+ """
77
+ Rich representation of this enumeration element.
78
+ """
79
+ return f"[{self.colour}]{self.symbol}[/{self.colour}]"
80
+
81
+
82
+ class EARStatus(_ReportableStateEnum):
83
+ """Enumeration of all possible EAR statuses, and their associated status colour."""
84
+
85
+ #: Not yet associated with a submission.
86
+ pending = _ReportableStateData(
87
+ 0,
88
+ ".",
89
+ "grey46",
90
+ "Not yet associated with a submission.",
91
+ )
92
+ #: Associated with a prepared submission that is not yet submitted.
93
+ prepared = _ReportableStateData(
94
+ 1,
95
+ ".",
96
+ "grey46",
97
+ "Associated with a prepared submission that is not yet submitted.",
98
+ )
99
+ #: Submitted for execution.
100
+ submitted = _ReportableStateData(
101
+ 2,
102
+ ".",
103
+ "grey46",
104
+ "Submitted for execution.",
105
+ )
106
+ #: Executing now.
107
+ running = _ReportableStateData(
108
+ 3,
109
+ "●",
110
+ "dodger_blue1",
111
+ "Executing now.",
112
+ )
113
+ #: Not attempted due to a failure of an upstream action on which this depends,
114
+ #: or a loop termination condition being satisfied.
115
+ skipped = _ReportableStateData(
116
+ 4,
117
+ "s",
118
+ "dark_orange",
119
+ (
120
+ "Not attempted due to a failure of an upstream action on which this depends, "
121
+ "or a loop termination condition being satisfied."
122
+ ),
123
+ )
124
+ #: Aborted by the user; downstream actions will be attempted.
125
+ aborted = _ReportableStateData(
126
+ 5,
127
+ "A",
128
+ "deep_pink4",
129
+ "Aborted by the user; downstream actions will be attempted.",
130
+ )
131
+ #: Probably exited successfully.
132
+ success = _ReportableStateData(
133
+ 6,
134
+ "■",
135
+ "green3",
136
+ "Probably exited successfully.",
137
+ )
138
+ #: Probably failed.
139
+ error = _ReportableStateData(
140
+ 7,
141
+ "E",
142
+ "red3",
143
+ "Probably failed.",
144
+ )
145
+
146
+ @classmethod
147
+ def get_non_running_submitted_states(cls) -> frozenset[EARStatus]:
148
+ """Return the set of all non-running states, excluding those before submission."""
149
+ return frozenset(
150
+ {
151
+ cls.skipped,
152
+ cls.aborted,
153
+ cls.success,
154
+ cls.error,
155
+ }
156
+ )
157
+
158
+
159
+ class InputSourceType(Enum):
160
+ """
161
+ The types of input sources.
162
+ """
163
+
164
+ #: Input source is an import.
165
+ IMPORT = 0
166
+ #: Input source is local.
167
+ LOCAL = 1
168
+ #: Input source is a default.
169
+ DEFAULT = 2
170
+ #: Input source is a task.
171
+ TASK = 3
172
+
173
+
174
+ class ParallelMode(Enum):
175
+ """
176
+ Potential parallel modes.
177
+ """
178
+
179
+ #: Use distributed-memory parallelism (e.g. MPI).
180
+ DISTRIBUTED = 0
181
+ #: Use shared-memory parallelism (e.g. OpenMP).
182
+ SHARED = 1
183
+ #: Use both distributed- and shared-memory parallelism.
184
+ #:
185
+ #: Note
186
+ #: ----
187
+ #: This is not yet implemented in any meaningful way!
188
+ HYBRID = 2
189
+
190
+
191
+ class ParameterPropagationMode(Enum):
192
+ """
193
+ How a parameter is propagated.
194
+ """
195
+
196
+ #: Parameter is propagated implicitly.
197
+ IMPLICIT = 0
198
+ #: Parameter is propagated explicitly.
199
+ EXPLICIT = 1
200
+ #: Parameter is never propagated.
201
+ NEVER = 2
202
+
203
+
204
+ class TaskSourceType(Enum):
205
+ """
206
+ The types of task-based input sources.
207
+ """
208
+
209
+ #: Input source is a task input.
210
+ INPUT = 0
211
+ #: Input source is a task output.
212
+ OUTPUT = 1
213
+ #: Input source is unspecified.
214
+ ANY = 2
215
+
216
+ @classmethod
217
+ def names(cls) -> Sequence[str]:
218
+ """
219
+ Get the names of the task source types.
220
+ """
221
+ return cls._member_names_
@@ -0,0 +1,256 @@
1
+ """
2
+ Model of an execution environment.
3
+ """
4
+
5
+ from __future__ import annotations
6
+
7
+ from dataclasses import dataclass
8
+ from typing import TYPE_CHECKING
9
+
10
+ from hpcflow.sdk.typing import hydrate
11
+ from hpcflow.sdk.core.errors import DuplicateExecutableError
12
+ from hpcflow.sdk.core.json_like import ChildObjectSpec, JSONLike
13
+ from hpcflow.sdk.core.object_list import ExecutablesList
14
+ from hpcflow.sdk.core.utils import check_valid_py_identifier, get_duplicate_items
15
+
16
+ if TYPE_CHECKING:
17
+ from collections.abc import Mapping, Sequence
18
+ from typing import Any, ClassVar
19
+
20
+
21
+ @dataclass
22
+ class NumCores(JSONLike):
23
+ """
24
+ A range of cores supported by an executable instance.
25
+
26
+ Parameters
27
+ ----------
28
+ start:
29
+ The minimum number of cores supported.
30
+ stop:
31
+ The maximum number of cores supported.
32
+ step: int
33
+ The step in the number of cores supported. Defaults to 1.
34
+ """
35
+
36
+ #: The minimum number of cores supported.
37
+ start: int
38
+ #: The maximum number of cores supported.
39
+ stop: int
40
+ #: The step in the number of cores supported. Normally 1.
41
+ step: int = 1
42
+
43
+ def __contains__(self, x: int) -> bool:
44
+ return x in range(self.start, self.stop + 1, self.step)
45
+
46
+
47
+ @dataclass
48
+ @hydrate
49
+ class ExecutableInstance(JSONLike):
50
+ """
51
+ A particular instance of an executable that can support some mode of operation.
52
+
53
+ Parameters
54
+ ----------
55
+ parallel_mode:
56
+ What parallel mode is supported by this executable instance.
57
+ num_cores: NumCores | int | dict[str, int]
58
+ The number of cores supported by this executable instance.
59
+ command:
60
+ The actual command to use for this executable instance.
61
+ """
62
+
63
+ #: What parallel mode is supported by this executable instance.
64
+ parallel_mode: str | None
65
+ #: The number of cores supported by this executable instance.
66
+ num_cores: NumCores
67
+ #: The actual command to use for this executable instance.
68
+ command: str
69
+
70
+ def __init__(
71
+ self, parallel_mode: str | None, num_cores: NumCores | int | dict, command: str
72
+ ):
73
+ self.parallel_mode = parallel_mode
74
+ self.command = command
75
+ if isinstance(num_cores, NumCores):
76
+ self.num_cores = num_cores
77
+ elif isinstance(num_cores, int):
78
+ self.num_cores = NumCores(num_cores, num_cores)
79
+ else:
80
+ self.num_cores = NumCores(**num_cores)
81
+
82
+ @classmethod
83
+ def from_spec(cls, spec: dict[str, Any]) -> ExecutableInstance:
84
+ """
85
+ Construct an instance from a specification dictionary.
86
+ """
87
+ return cls(**spec)
88
+
89
+
90
+ class Executable(JSONLike):
91
+ """
92
+ A program managed by the environment.
93
+
94
+ Parameters
95
+ ----------
96
+ label:
97
+ The abstract name of the program.
98
+ instances: list[ExecutableInstance]
99
+ The concrete instances of the application that may be present.
100
+ """
101
+
102
+ _child_objects: ClassVar[tuple[ChildObjectSpec, ...]] = (
103
+ ChildObjectSpec(
104
+ name="instances",
105
+ class_name="ExecutableInstance",
106
+ is_multiple=True,
107
+ ),
108
+ )
109
+
110
+ def __init__(self, label: str, instances: list[ExecutableInstance]):
111
+ #: The abstract name of the program.
112
+ self.label = check_valid_py_identifier(label)
113
+ #: The concrete instances of the application that may be present.
114
+ self.instances = instances
115
+
116
+ self._executables_list: ExecutablesList | None = None # assigned by parent
117
+
118
+ def __repr__(self):
119
+ return (
120
+ f"{self.__class__.__name__}("
121
+ f"label={self.label}, "
122
+ f"instances={self.instances!r}"
123
+ f")"
124
+ )
125
+
126
+ def __eq__(self, other: Any) -> bool:
127
+ return (
128
+ isinstance(other, self.__class__)
129
+ and self.label == other.label
130
+ and self.instances == other.instances
131
+ and (
132
+ (
133
+ self.environment
134
+ and other.environment
135
+ and self.environment.name == other.environment.name
136
+ )
137
+ or (not self.environment and not other.environment)
138
+ )
139
+ )
140
+
141
+ @property
142
+ def environment(self) -> Environment | None:
143
+ """
144
+ The environment that the executable is going to run in.
145
+ """
146
+ return None if (el := self._executables_list) is None else el.environment
147
+
148
+ def filter_instances(
149
+ self, parallel_mode: str | None = None, num_cores: int | None = None
150
+ ) -> list[ExecutableInstance]:
151
+ """
152
+ Select the instances of the executable that are compatible with the given
153
+ requirements.
154
+
155
+ Parameters
156
+ ----------
157
+ parallel_mode: str
158
+ If given, the parallel mode to require.
159
+ num_cores: int
160
+ If given, the number of cores desired.
161
+
162
+ Returns
163
+ -------
164
+ list[ExecutableInstance]:
165
+ The known executable instances that match the requirements.
166
+ """
167
+ return [
168
+ inst
169
+ for inst in self.instances
170
+ if (parallel_mode is None or inst.parallel_mode == parallel_mode)
171
+ and (num_cores is None or num_cores in inst.num_cores)
172
+ ]
173
+
174
+
175
+ class Environment(JSONLike):
176
+ """
177
+ An execution environment that contains a number of executables.
178
+
179
+ Parameters
180
+ ----------
181
+ name: str
182
+ The name of the environment.
183
+ setup: list[str]
184
+ Commands to run to enter the environment.
185
+ specifiers: dict[str, str]
186
+ Dictionary of attributes that may be used to supply additional key/value pairs to
187
+ look up an environment by.
188
+ executables: list[Executable]
189
+ List of abstract executables in the environment.
190
+ """
191
+
192
+ _validation_schema: ClassVar[str] = "environments_spec_schema.yaml"
193
+ _child_objects: ClassVar[tuple[ChildObjectSpec, ...]] = (
194
+ ChildObjectSpec(
195
+ name="executables",
196
+ class_name="ExecutablesList",
197
+ parent_ref="environment",
198
+ ),
199
+ )
200
+
201
+ def __init__(
202
+ self,
203
+ name: str,
204
+ setup: Sequence[str] | None = None,
205
+ specifiers: Mapping[str, str] | None = None,
206
+ executables: ExecutablesList | Sequence[Executable] | None = None,
207
+ doc: str = "",
208
+ _hash_value: str | None = None,
209
+ ):
210
+ #: The name of the environment.
211
+ self.name = name
212
+ #: Documentation for the environment.
213
+ self.doc = doc
214
+ #: Dictionary of attributes that may be used to supply additional key/value pairs
215
+ #: to look up an environment by.
216
+ self.specifiers: Mapping[str, str] = specifiers or {}
217
+ #: List of abstract executables in the environment.
218
+ self.executables = (
219
+ executables
220
+ if isinstance(executables, ExecutablesList)
221
+ else self._app.ExecutablesList(executables or ())
222
+ )
223
+ self._hash_value = _hash_value
224
+ #: Commands to run to enter the environment.
225
+ self.setup: tuple[str, ...] | None
226
+ if not setup:
227
+ self.setup = None
228
+ elif isinstance(setup, str):
229
+ self.setup = tuple(cmd.strip() for cmd in setup.strip().split("\n"))
230
+ else:
231
+ self.setup = tuple(setup)
232
+ self._set_parent_refs()
233
+ self._validate()
234
+
235
+ def __eq__(self, other: Any) -> bool:
236
+ return (
237
+ isinstance(other, self.__class__)
238
+ and self.setup == other.setup
239
+ and self.executables == other.executables
240
+ and self.specifiers == other.specifiers
241
+ )
242
+
243
+ def __repr__(self):
244
+ return f"{self.__class__.__name__}({self.name!r})"
245
+
246
+ def _validate(self):
247
+ if dup_labels := get_duplicate_items(exe.label for exe in self.executables):
248
+ raise DuplicateExecutableError(dup_labels)
249
+
250
+ @property
251
+ def documentation(self) -> str:
252
+ if self.doc:
253
+ import markupsafe
254
+
255
+ return markupsafe.Markup(self.doc)
256
+ return repr(self)