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
hpcflow/__init__.py CHANGED
@@ -1,12 +1,3 @@
1
- """`hpcflow.__init__.py`"""
2
-
3
1
  from hpcflow._version import __version__
4
- from hpcflow.api import (
5
- make_workflow,
6
- submit_workflow,
7
- clean,
8
- get_stats,
9
- save_stats,
10
- kill,
11
- cloud_connect,
12
- )
2
+
3
+ _app_name = "hpcFlow"
@@ -0,0 +1,5 @@
1
+ from pathlib import Path
2
+
3
+
4
+ def get_hook_dirs():
5
+ return [str(Path(__file__).parent.resolve())]
@@ -0,0 +1,40 @@
1
+ from PyInstaller.utils.hooks import collect_data_files
2
+
3
+ from hpcflow.sdk import sdk_classes
4
+
5
+
6
+ # most of the modules in `sdk_classes` are imported on-demand via the app object:
7
+ hiddenimports = [
8
+ *sdk_classes.values(),
9
+ "hpcflow.sdk.data",
10
+ "hpcflow.data.demo_data_manifest",
11
+ "hpcflow.data.scripts",
12
+ "hpcflow.data.jinja_templates",
13
+ "hpcflow.data.template_components",
14
+ "hpcflow.data.workflows",
15
+ "hpcflow.tests.data",
16
+ "hpcflow.sdk.core.test_utils",
17
+ "hpcflow.sdk.utils.patches",
18
+ "click.testing",
19
+ "requests", # for GitHub fsspec file system
20
+ "fsspec.implementations.github", # for GitHub fsspec file system
21
+ ]
22
+
23
+ datas = (
24
+ collect_data_files("hpcflow.sdk.data")
25
+ + collect_data_files("hpcflow.data.demo_data_manifest")
26
+ + collect_data_files(
27
+ "hpcflow.data.scripts", include_py_files=True, excludes=("**/__pycache__",)
28
+ )
29
+ + collect_data_files(
30
+ "hpcflow.data.jinja_templates",
31
+ include_py_files=True,
32
+ excludes=("**/__pycache__",),
33
+ )
34
+ + collect_data_files("hpcflow.data.template_components")
35
+ + collect_data_files("hpcflow.data.workflows")
36
+ + collect_data_files(
37
+ "hpcflow.tests", include_py_files=True, excludes=("**/__pycache__",)
38
+ )
39
+ + collect_data_files("hpcflow.tests.data")
40
+ )
hpcflow/_version.py CHANGED
@@ -1 +1 @@
1
- __version__ = '0.1.15'
1
+ __version__ = "0.2.0a271"
hpcflow/app.py ADDED
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+ from hpcflow import __version__, _app_name
3
+ from hpcflow.sdk import app as sdk_app
4
+ from hpcflow.sdk.config import ConfigOptions
5
+
6
+
7
+ # provide access to app attributes:
8
+ __getattr__ = sdk_app.get_app_attribute
9
+
10
+ # ensure docs/help can see dynamically loaded attributes:
11
+ __all__ = sdk_app.get_app_module_all()
12
+ __dir__ = sdk_app.get_app_module_dir()
13
+
14
+ # set app-level config options:
15
+ config_options = ConfigOptions(
16
+ directory_env_var="HPCFLOW_CONFIG_DIR",
17
+ default_directory="~/.hpcflow",
18
+ )
19
+
20
+ # load built in template components (in this case, for demonstration purposes):
21
+ template_components = sdk_app.BaseApp.load_builtin_template_component_data(
22
+ "hpcflow.data.template_components"
23
+ )
24
+
25
+ # initialise the App object:
26
+ app: sdk_app.BaseApp = sdk_app.BaseApp(
27
+ name=_app_name,
28
+ version=__version__,
29
+ module=__name__,
30
+ docs_import_conv="hf",
31
+ description="Computational workflow management",
32
+ gh_org="hpcflow",
33
+ gh_repo="hpcflow",
34
+ config_options=config_options,
35
+ template_components=template_components,
36
+ scripts_dir="data.scripts", # relative to root package
37
+ jinja_templates_dir="data.jinja_templates", # relative to root package
38
+ programs_dir="data.programs", # relative to root package
39
+ workflows_dir="data.workflows", # relative to root package
40
+ demo_data_dir="hpcflow.data.demo_data",
41
+ demo_data_manifest_dir="hpcflow.data.demo_data_manifest",
42
+ docs_url="https://hpcflow.github.io/docs/stable",
43
+ ) #: |app|
hpcflow/cli.py CHANGED
@@ -1,463 +1,4 @@
1
- """`hpcflow.cli.py`
1
+ from hpcflow.app import cli
2
2
 
3
- Module that exposes a command line interface for `hpcflow`.
4
-
5
- """
6
- import socket
7
- import os
8
- from pathlib import Path
9
- from datetime import datetime
10
- from random import randint
11
-
12
- import click
13
-
14
- from hpcflow import __version__
15
- from hpcflow import api
16
-
17
-
18
- def get_process_stamp():
19
- return '{} {} {}'.format(
20
- datetime.now(),
21
- socket.gethostname(),
22
- os.getpid(),
23
- )
24
-
25
-
26
- def validate_cloud_provider(ctx, param, value):
27
-
28
- good_providers = ['dropbox']
29
- if value not in good_providers:
30
- msg = ('`provider` must be one of: {}'.format(good_providers))
31
- raise click.BadParameter(msg)
32
-
33
- return value
34
-
35
-
36
- def validate_task_ranges(ctx, param, value):
37
- """Validate the task range.
38
-
39
- Parameters
40
- ----------
41
- ctx
42
- param
43
- value : str
44
- Stringified comma-separated list, where each element indicates the
45
- tasks to submit for that channel of the Workflow. List elements can be
46
- one of:
47
- all
48
- submit all tasks in the given channel.
49
- n[-m[:s]]
50
- submit a range of tasks from task `n` to task `m`
51
- (inclusively), with an optional step size of `s`.
52
- <empty>
53
- submit no tasks from the given channel.
54
-
55
- Returns
56
- -------
57
- task_ranges : list of tuple
58
- (start, stop, step)
59
-
60
- """
61
-
62
- if value is None:
63
- return
64
-
65
- if ',' in value:
66
- value = value.split(',')
67
- else:
68
- value = [value]
69
-
70
- task_ranges = []
71
- for i in value:
72
-
73
- if i.strip() == 'all':
74
- task_ranges.append([1, -1, 1])
75
- continue
76
-
77
- elif i.strip() == '':
78
- task_ranges.append([])
79
- continue
80
-
81
- task_step = 1
82
-
83
- msg = ('Could not understand task range. It should be specified in '
84
- 'the format: `n[-m[:s]]` where `n` is the starting task ID, `m` is '
85
- ' the ending task ID, and `s` is the task step size.')
86
-
87
- if '-' in i:
88
- # Task range
89
- task_start, task_stop = i.split('-')
90
-
91
- if ':' in task_stop:
92
- # With step size:
93
- task_stop, task_step = task_stop.split(':')
94
-
95
- try:
96
- task_step = int(task_step)
97
- except ValueError:
98
- raise click.BadParameter(msg)
99
-
100
- try:
101
- task_start = int(task_start)
102
- task_stop = int(task_stop)
103
- except ValueError:
104
- raise click.BadParameter(msg)
105
-
106
- else:
107
- # Single task
108
- try:
109
- task = int(i)
110
- task_start = task
111
- task_stop = task
112
- except ValueError:
113
- raise click.BadParameter(msg)
114
-
115
- if task_start > task_stop:
116
- msg = ('Task starting ID must be smaller than or equal to '
117
- 'task ending ID.')
118
- raise click.BadParameter(msg)
119
-
120
- task_range = [task_start, task_stop, task_step]
121
- task_ranges.append(task_range)
122
-
123
- task_ranges = task_ranges[0] # For now - no channels.
124
- return task_ranges
125
-
126
-
127
- @click.group()
128
- @click.version_option(version=__version__)
129
- def cli():
130
- pass
131
-
132
-
133
- @cli.command()
134
- @click.option('--yes', '-y', is_flag=True)
135
- @click.option('--config-dir', type=click.Path(exists=True))
136
- def clean(directory=None, yes=True, config_dir=None):
137
- """Clean the directory of all content generated by `hpcflow`."""
138
- msg = ('Do you want to remove all `hpc-flow`-generated files '
139
- 'from {}?')
140
- if directory:
141
- msg = msg.format(directory)
142
- else:
143
- msg = msg.format('the current directory')
144
- if yes or click.confirm(msg):
145
- api.clean(dir_path=directory, config_dir=config_dir)
146
-
147
-
148
- @cli.command()
149
- @click.option('--directory', '-d')
150
- @click.option('--json-file')
151
- @click.option('--json')
152
- @click.option('--config-dir', type=click.Path(exists=True))
153
- @click.argument('profiles', nargs=-1, type=click.Path(exists=True))
154
- def make(directory=None, profiles=None, json_file=None, json=None, config_dir=None):
155
- """Generate a new Workflow."""
156
- print('hpcflow.cli.make', flush=True)
157
-
158
- workflow_id = api.make_workflow(
159
- dir_path=directory,
160
- profile_list=profiles,
161
- json_file=json_file,
162
- json_str=json,
163
- config_dir=config_dir,
164
- clean=False,
165
- )
166
- print('Generated new Workflow with ID {}'.format(workflow_id))
167
-
168
-
169
- @cli.command()
170
- @click.option('--directory', '-d')
171
- @click.option('--config-dir', type=click.Path(exists=True))
172
- @click.argument('cmd_group_sub_id', type=click.INT)
173
- @click.argument('task_idx', type=click.INT)
174
- @click.argument('iter_idx', type=click.INT)
175
- def write_runtime_files(cmd_group_sub_id, task_idx, iter_idx, directory=None,
176
- config_dir=None):
177
- print('hpcflow.cli.write_runtime_files', flush=True)
178
- api.write_runtime_files(
179
- cmd_group_sub_id,
180
- task_idx,
181
- iter_idx,
182
- dir_path=directory,
183
- config_dir=config_dir,
184
- )
185
-
186
-
187
- @cli.command()
188
- @click.option('--directory', '-d')
189
- @click.option('--config-dir', type=click.Path(exists=True))
190
- @click.argument('cmd_group_sub_id', type=click.INT)
191
- @click.argument('task_idx', type=click.INT)
192
- @click.argument('iter_idx', type=click.INT)
193
- def set_task_start(cmd_group_sub_id, task_idx, iter_idx, directory=None, config_dir=None):
194
- print('hpcflow.cli.set_task_start', flush=True)
195
- api.set_task_start(cmd_group_sub_id, task_idx, iter_idx, directory, config_dir)
196
-
197
-
198
- @cli.command()
199
- @click.option('--directory', '-d')
200
- @click.option('--config-dir', type=click.Path(exists=True))
201
- @click.argument('cmd_group_sub_id', type=click.INT)
202
- @click.argument('task_idx', type=click.INT)
203
- @click.argument('iter_idx', type=click.INT)
204
- def set_task_end(cmd_group_sub_id, task_idx, iter_idx, directory=None, config_dir=None):
205
- print('hpcflow.cli.set_task_end', flush=True)
206
- api.set_task_end(cmd_group_sub_id, task_idx, iter_idx, directory, config_dir)
207
-
208
-
209
- @cli.command()
210
- @click.option('--directory', '-d')
211
- @click.option('--config-dir', type=click.Path(exists=True))
212
- @click.argument('cmd_group_sub_id', type=click.INT)
213
- @click.argument('task_idx', type=click.INT)
214
- @click.argument('iter_idx', type=click.INT)
215
- def archive(cmd_group_sub_id, task_idx, iter_idx, directory=None, config_dir=None):
216
- print('hpcflow.cli.archive', flush=True)
217
- api.archive(
218
- cmd_group_sub_id,
219
- task_idx,
220
- iter_idx,
221
- dir_path=directory,
222
- config_dir=config_dir,
223
- )
224
-
225
-
226
- @cli.command()
227
- @click.option('--directory', '-d')
228
- @click.option('--config-dir', type=click.Path(exists=True))
229
- @click.argument('cmd_group_sub_id', type=click.INT)
230
- @click.argument('task_idx', type=click.INT)
231
- @click.argument('iter_idx', type=click.INT)
232
- def get_scheduler_stats(cmd_group_sub_id, task_idx, iter_idx, directory=None,
233
- config_dir=None):
234
- print('hpcflow.cli.get_scheduler_stats', flush=True)
235
- api.get_scheduler_stats(
236
- cmd_group_sub_id,
237
- task_idx,
238
- iter_idx,
239
- dir_path=directory,
240
- config_dir=config_dir,
241
- )
242
-
243
-
244
- @cli.command()
245
- @click.option('--directory', '-d')
246
- @click.option('--workflow-id', '-w', type=click.INT)
247
- @click.option('--config-dir', type=click.Path(exists=True))
248
- def root_archive(workflow_id, directory=None, config_dir=None):
249
- print('hpcflow.cli.root_archive', flush=True)
250
- api.root_archive(
251
- workflow_id,
252
- dir_path=directory,
253
- config_dir=config_dir,
254
- )
255
-
256
-
257
- @cli.command()
258
- def stat():
259
- """Show the status of running tasks and the number completed tasks."""
260
- print('hpcflow.cli.stat')
261
-
262
-
263
- @cli.command()
264
- @click.option('--directory', '-d')
265
- @click.option('--workflow-id', '-w', type=click.INT)
266
- @click.option('--config-dir', type=click.Path(exists=True))
267
- def show_stats(directory=None, workflow_id=None, config_dir=None):
268
- """Show task statistics, formatted as a table."""
269
- stats_fmt = api.get_formatted_stats(directory, workflow_id, config_dir=config_dir)
270
- print(stats_fmt)
271
-
272
-
273
- @cli.command()
274
- @click.option('--directory', '-d')
275
- @click.option('--workflow-id', '-w', type=click.INT)
276
- @click.option('--config-dir', type=click.Path(exists=True))
277
- @click.argument('save_path', type=click.Path(exists=False, dir_okay=False))
278
- def save_stats(save_path, directory=None, workflow_id=None, config_dir=None):
279
- """Save task statistics as a JSON file."""
280
- api.save_stats(save_path, directory, workflow_id, config_dir=config_dir)
281
-
282
-
283
- @cli.command()
284
- @click.option('--directory', '-d')
285
- @click.option('--workflow-id', '-w', type=click.INT)
286
- @click.option('--config-dir', type=click.Path(exists=True))
287
- def kill(directory=None, workflow_id=None, config_dir=None):
288
- api.kill(directory, workflow_id, config_dir=config_dir)
289
-
290
-
291
- @cli.command()
292
- @click.option('--directory', '-d')
293
- @click.option('--workflow-id', '-w', type=click.INT)
294
- @click.option('--config-dir', type=click.Path(exists=True))
295
- @click.option('--json-file')
296
- @click.option('--json')
297
- @click.option('--task-ranges', '-t',
298
- help=('Task ranges are specified as a comma-separated list whose'
299
- ' elements are one of: "n[-m[:s]]", "all" or "" (empty)'),
300
- callback=validate_task_ranges)
301
- @click.argument('profiles', nargs=-1, type=click.Path(exists=True))
302
- def submit(directory=None, workflow_id=None, task_ranges=None, profiles=None,
303
- json_file=None, json=None, config_dir=None):
304
- """Submit(and optionally generate) a Workflow."""
305
-
306
- print('hpcflow.cli.submit', flush=True)
307
-
308
- existing_ids = api.get_workflow_ids(directory, config_dir)
309
- submit_args = {
310
- 'dir_path': directory,
311
- 'task_range': task_ranges,
312
- 'config_dir': config_dir,
313
- }
314
-
315
- if workflow_id:
316
- # Submit an existing Workflow.
317
-
318
- if not existing_ids:
319
- msg = 'There are no existing Workflows in the directory {}'
320
- raise ValueError(msg.format(directory))
321
-
322
- submit_args['workflow_id'] = workflow_id
323
-
324
- if workflow_id not in existing_ids:
325
- msg = ('The Workflow ID "{}" does not match an existing Workflow '
326
- 'in the directory {}. Existing Workflow IDs are {}')
327
- raise ValueError(msg.format(workflow_id, directory, existing_ids))
328
-
329
- submission_id = api.submit_workflow(**submit_args)
330
-
331
- else:
332
- # First generate a Workflow, and then submit it.
333
-
334
- make_workflow = True
335
- if existing_ids:
336
- # Check user did not want to submit existing Workflow:
337
- msg = 'Previous workflows exist with IDs: {}. Add new workflow?'
338
- make_workflow = click.confirm(msg.format(existing_ids))
339
-
340
- # TODO: if `make_workflow=False`, show existing IDs and offer to
341
- # submit one?
342
-
343
- if make_workflow:
344
- workflow_id = api.make_workflow(
345
- dir_path=directory,
346
- profile_list=profiles,
347
- json_file=json_file,
348
- json_str=json,
349
- config_dir=config_dir,
350
- )
351
- print('Generated new Workflow with ID {}'.format(workflow_id))
352
-
353
- submit_args['workflow_id'] = workflow_id
354
- submission_id = api.submit_workflow(**submit_args)
355
-
356
- else:
357
- print('Exiting.')
358
- return
359
-
360
- print('Submitted Workflow (ID {}) with submission '
361
- 'ID {}'.format(workflow_id, submission_id))
362
-
363
-
364
- @cli.command()
365
- @click.option('--name', '-n', required=True)
366
- @click.option('--value', '-v', required=True)
367
- @click.option('--config-dir', type=click.Path(exists=True))
368
- def update_config(name, value, config_dir=None):
369
- api.update_config(name, value, config_dir=config_dir)
370
-
371
-
372
- @cli.command()
373
- @click.option('--provider', '-p', required=True)
374
- @click.option('--config-dir', type=click.Path(exists=True))
375
- def cloud_connect(provider, config_dir=None):
376
- api.cloud_connect(provider, config_dir=config_dir)
377
-
378
-
379
- @cli.group()
380
- def dummy():
381
- """Dummy commands for testing/documentation."""
382
-
383
-
384
- @dummy.command('makeSomething')
385
- @click.option('--name', default='infile')
386
- @click.option('--num', type=click.INT, default=2)
387
- @click.argument('extension', nargs=-1, default=None)
388
- def dummy_make_something(name, num, extension):
389
-
390
- if not extension:
391
- extension = ['.txt' for i in range(num)]
392
- elif len(extension) != num:
393
- raise click.BadParameter(
394
- 'Number of specified extensions argument must match `num` parameter.')
395
-
396
- for i in range(num):
397
- out_path = Path('{}_{}{}'.format(name, i + 1, extension[i]))
398
- with out_path.open('w') as handle:
399
- handle.write('{}\n'.format(randint(0, 1e6)))
400
- handle.write('{} Generated by `makeSomething --name {} --num {} {}`.'.format(
401
- get_process_stamp(),
402
- name,
403
- num,
404
- ' '.join(['"{}"'.format(j) for j in extension])
405
- ))
406
-
407
-
408
- @dummy.command('doSomething')
409
- @click.option('--infile1', '-i1', type=click.Path(exists=True), required=True)
410
- @click.option('--infile2', '-i2', type=click.Path(exists=True), required=True)
411
- @click.option('--value', '-v')
412
- @click.option('--out', '-o')
413
- def dummy_do_something(infile1, infile2, value=None, out=None):
414
-
415
- with Path(infile1).open('r') as handle:
416
- file_id_1 = int(handle.readline().strip())
417
- with Path(infile2).open('r') as handle:
418
- file_id_2 = int(handle.readline().strip())
419
-
420
- if out is None:
421
- out = 'outfile.txt'
422
- out_path = Path(out)
423
- with out_path.open('a') as handle:
424
- handle.write('{}\n'.format(randint(0, 1e6)))
425
- handle.write('{} Generated by `doSomething --infile1 {} --infile2 {}`.\n'.format(
426
- get_process_stamp(), infile1, infile2))
427
- if value:
428
- handle.write('{} Value: {}\n'.format(get_process_stamp(), value))
429
- handle.write('{} Original file ID: {}: {}\n'.format(
430
- get_process_stamp(), infile1, file_id_1))
431
- handle.write('{} Original file ID: {}: {}\n'.format(
432
- get_process_stamp(), infile2, file_id_2))
433
-
434
-
435
- @dummy.command('splitSomething')
436
- @click.argument('infile', type=click.Path(exists=True))
437
- @click.option('--num', '-n', type=click.INT, default=2)
438
- def dummy_split_something(infile, num):
439
-
440
- with Path(infile).open('r') as handle:
441
- file_id = int(handle.readline().strip())
442
- for i in range(num):
443
- out_path = Path('outfile_{}.txt'.format(i + 1))
444
- with out_path.open('w') as handle:
445
- handle.write('{}\n'.format(randint(0, 1e6)))
446
- handle.write('{} Generated by `splitSomething {}`.\n'.format(
447
- get_process_stamp(), infile))
448
- handle.write('{} Original file ID: {}: {}\n'.format(
449
- get_process_stamp(), infile, file_id))
450
-
451
-
452
- @dummy.command('processSomething')
453
- @click.argument('infile', type=click.Path(exists=True))
454
- def dummy_process_something(infile):
455
-
456
- with Path(infile).open('a') as handle:
457
- handle.write('\n{} Modified by `processSomething {}`.\n'.format(
458
- get_process_stamp(), infile
459
- ))
460
-
461
-
462
- if __name__ == '__main__':
3
+ if __name__ == "__main__":
463
4
  cli()
@@ -0,0 +1,3 @@
1
+ """
2
+ Manifest for demonstration data.
3
+ """
@@ -0,0 +1,6 @@
1
+ {
2
+ "text_file.txt": {
3
+ "in_zip": "text_file.zip"
4
+ },
5
+ "zip_file.zip": {}
6
+ }
@@ -0,0 +1,8 @@
1
+ Hola, {{ name }}!
2
+
3
+ This is a template, with a loop. Here are your specified fruits:
4
+
5
+ {%- for fruit_i in fruits %}
6
+ - {{ fruit_i -}}
7
+ {% endfor %}
8
+
@@ -0,0 +1 @@
1
+ This directory contains binary programs that are used to test the `Action.program` attribute. These binary programs are generated by the `generate_test_programs.yml` GitHub actions workflow (from `hello_world.c`), and are organised into sub-directories named by the `resources.platform` (e.g. "win", "linux", "macos") attribute.
@@ -0,0 +1,87 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ #include <string.h>
4
+ #include "cJSON.h"
5
+
6
+ void hello_world()
7
+ {
8
+ printf("hello, world\n");
9
+ }
10
+
11
+ void hello_world_ins_outs(const char *inputs_path, const char *outputs_path)
12
+ {
13
+ printf("hello, world\n");
14
+
15
+ // Read input JSON
16
+ FILE *fp = fopen(inputs_path, "r");
17
+ if (!fp)
18
+ {
19
+ perror("Failed to open input file");
20
+ exit(1);
21
+ }
22
+
23
+ fseek(fp, 0, SEEK_END);
24
+ long len = ftell(fp);
25
+ fseek(fp, 0, SEEK_SET);
26
+
27
+ char *data = malloc(len + 1);
28
+ fread(data, 1, len, fp);
29
+ data[len] = '\0';
30
+ fclose(fp);
31
+
32
+ cJSON *json = cJSON_Parse(data);
33
+ if (!json)
34
+ {
35
+ fprintf(stderr, "Error parsing JSON input\n");
36
+ free(data);
37
+ exit(1);
38
+ }
39
+
40
+ double p1 = cJSON_GetObjectItem(json, "p1")->valuedouble;
41
+ double p2 = cJSON_GetObjectItem(json, "p2")->valuedouble;
42
+ double p3 = cJSON_GetObjectItem(json, "p3")->valuedouble;
43
+ double p4 = p1 + p2 + p3;
44
+
45
+ cJSON_Delete(json);
46
+ free(data);
47
+
48
+ // Create output JSON
49
+ cJSON *output_json = cJSON_CreateObject();
50
+ cJSON_AddNumberToObject(output_json, "p4", p4);
51
+
52
+ char *out_string = cJSON_Print(output_json);
53
+
54
+ fp = fopen(outputs_path, "w");
55
+ if (!fp)
56
+ {
57
+ perror("Failed to open output file");
58
+ cJSON_Delete(output_json);
59
+ free(out_string);
60
+ exit(1);
61
+ }
62
+
63
+ fprintf(fp, "%s\n", out_string);
64
+ fclose(fp);
65
+
66
+ cJSON_Delete(output_json);
67
+ free(out_string);
68
+ }
69
+
70
+ int main(int argc, char *argv[])
71
+ {
72
+ if (argc == 1)
73
+ {
74
+ hello_world();
75
+ }
76
+ else if (argc == 3)
77
+ {
78
+ hello_world_ins_outs(argv[1], argv[2]);
79
+ }
80
+ else
81
+ {
82
+ fprintf(stderr, "Usage: %s [input.json output.json]\n", argv[0]);
83
+ return 1;
84
+ }
85
+
86
+ return 0;
87
+ }
@@ -0,0 +1 @@
1
+ """This is required to allow the frozen app to find the scripts resources..."""