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/api.py DELETED
@@ -1,490 +0,0 @@
1
- """`hpcflow.api.py`
2
-
3
- This module contains the application programming interface (API) to `hpcflow`,
4
- and includes functions that are called by the command line interface (CLI; in
5
- `hpcflow.cli.py`).
6
-
7
- """
8
-
9
- from pathlib import Path
10
- from time import sleep
11
- from datetime import datetime
12
- import json
13
-
14
-
15
- from beautifultable import BeautifulTable
16
- from sqlalchemy.exc import OperationalError
17
-
18
- from hpcflow.config import Config
19
- from hpcflow.init_db import init_db
20
- from hpcflow.models import Workflow, CommandGroupSubmission
21
- from hpcflow.profiles import parse_job_profiles, prepare_workflow_dict
22
- from hpcflow.project import Project
23
- from hpcflow.archive.cloud.cloud import CloudProvider
24
-
25
-
26
- def make_workflow(dir_path=None, profile_list=None, json_file=None, json_str=None,
27
- workflow_dict=None, clean=False, config_dir=None):
28
- """Generate a new Workflow and add it to the local database.
29
-
30
- Parameters
31
- ----------
32
- dir_path : str or Path, optional
33
- The directory in which the Workflow will be generated. By default, this
34
- is the working (i.e. invoking) directory.
35
- profile_list : list of (str or Path), optional
36
- List of YAML profile file paths to use to construct the Workflow. By
37
- default, and if `json_file` and `json_str` and not specified, all
38
- YAML files in the `dir_path` directory that match the profile
39
- specification format in the global configuration will be parsed as
40
- Workflow profiles. If not None, only those profiles listed will be
41
- parsed as Workflow profiles.
42
- json_file : str or Path, optional
43
- Path to a JSON file that represents a Workflow. By default, set to
44
- `None`.
45
- json_str : str, optional
46
- JSON string that represents a Workflow. By default, set to `None`.
47
- workflow_dict : dict, optional
48
- Dict representing the workflow to generate.
49
- clean : bool, optional
50
- If True, all existing hpcflow data will be removed from `dir_path`.
51
- Useful for debugging.
52
-
53
- Returns
54
- -------
55
- workflow_id : int
56
- The insert ID of the Workflow object in the local database.
57
-
58
- Notes
59
- -----
60
- Specify only one of `profile_list`, `json_file` or `json_str`.
61
-
62
- """
63
-
64
- opts = [profile_list, json_file, json_str, workflow_dict]
65
- not_nones = sum([i is not None for i in opts])
66
- if not_nones > 1:
67
- msg = ('Specify only one of `profile_list`, `json_file`, `json_str` or '
68
- '`workflow_dict`.')
69
- raise ValueError(msg)
70
-
71
- project = Project(dir_path, config_dir, clean=clean)
72
-
73
- if json_str:
74
- workflow_dict = json.loads(json_str)
75
-
76
- elif json_file:
77
- json_file = Path(json_file).resolve()
78
- with Path(json_file).open() as handle:
79
- workflow_dict = json.load(handle)
80
-
81
- elif profile_list:
82
- profile_list = [Path(i).resolve() for i in profile_list]
83
- # Get workflow from YAML profiles:
84
- workflow_dict = parse_job_profiles(project.dir_path, profile_list)
85
-
86
- else:
87
- workflow_dict = prepare_workflow_dict(workflow_dict)
88
-
89
- Session = init_db(project, check_exists=False)
90
- session = Session()
91
-
92
- workflow = Workflow(directory=project.dir_path, **workflow_dict)
93
-
94
- session.add(workflow)
95
- session.commit()
96
-
97
- workflow_id = workflow.id_
98
- session.close()
99
-
100
- return workflow_id
101
-
102
-
103
- def submit_workflow(workflow_id, dir_path=None, task_range='all', config_dir=None):
104
- """Submit (part of) a previously generated Workflow.
105
-
106
- Parameters
107
- ----------
108
- workflow_id : int
109
- The ID of the Workflow to submit, as in the local database.
110
- dir_path : str or Path, optional
111
- The directory in which the Workflow exists. By default, this is the working (i.e.
112
- invoking) directory.
113
- task_range : (list of int) or str, optional
114
- Specify which tasks from the initial command group to submit. If a list, it must
115
- have either two or three elements; if it has two elements, these signify the first
116
- and last tasks, inclusively, to submit. By default, the task step size is one, but
117
- this can be chosen as a third list entry. If a string "all", all tasks are
118
- submitted.
119
- """
120
-
121
- # TODO: do validation of task_ranges here? so models.workflow.add_submission
122
- # always receives a definite `task_ranges`? What about if the number is
123
- # indeterminate at submission time?
124
-
125
- if task_range == 'all' or task_range is None:
126
- task_range = [1, -1, 1]
127
- if len(task_range) == 2:
128
- task_range.append(1)
129
-
130
- # print('api.submit_workflow: task_range: {}'.format(task_range), flush=True)
131
-
132
- project = Project(dir_path, config_dir)
133
- Session = init_db(project, check_exists=True)
134
- session = Session()
135
-
136
- workflow = session.query(Workflow).get(workflow_id)
137
- submission = workflow.add_submission(project, task_range)
138
-
139
- session.commit()
140
-
141
- submission_id = submission.id_
142
- session.close()
143
-
144
- return submission_id
145
-
146
-
147
- def get_workflow_ids(dir_path=None, config_dir=None):
148
- """Get the IDs of existing Workflows.
149
-
150
- Parameters
151
- ----------
152
- dir_path : str or Path, optional
153
- The directory in which the Workflows exist. By default, this is the
154
- working (i.e. invoking) directory.
155
-
156
- Returns
157
- -------
158
- workflow_ids : list of int
159
- List of IDs of Workflows.
160
-
161
- """
162
-
163
- project = Project(dir_path, config_dir)
164
- Session = init_db(project, check_exists=True)
165
- session = Session()
166
-
167
- workflow_ids = [i.id_ for i in session.query(Workflow.id_)]
168
-
169
- session.close()
170
-
171
- return workflow_ids
172
-
173
-
174
- def clean(dir_path=None, config_dir=None):
175
- """Clean the directory of all content generated by `hpcflow`."""
176
-
177
- project = Project(dir_path, config_dir)
178
- project.clean()
179
-
180
-
181
- def write_runtime_files(cmd_group_sub_id, task_idx, iter_idx, dir_path=None,
182
- config_dir=None):
183
- """Write the commands files for a given command group submission.
184
-
185
- Parameters
186
- ----------
187
- cmd_group_sub_id : int
188
- ID of the command group submission for which a command file is to be
189
- generated.
190
- task_idx : int, optional
191
- Task ID. What is this for???
192
- dir_path : str or Path, optional
193
- The directory in which the Workflow will be generated. By default, this
194
- is the working (i.e. invoking) directory.
195
-
196
- """
197
-
198
- project = Project(dir_path, config_dir)
199
- Session = init_db(project, check_exists=True)
200
- session = Session()
201
-
202
- cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
203
- cg_sub.write_runtime_files(project, task_idx, iter_idx)
204
-
205
- session.commit()
206
- session.close()
207
-
208
-
209
- def set_task_start(cmd_group_sub_id, task_idx, iter_idx, dir_path=None, config_dir=None):
210
-
211
- project = Project(dir_path, config_dir)
212
- Session = init_db(project, check_exists=True)
213
- session = Session()
214
-
215
- cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
216
-
217
- sleep_time = 5
218
- block_msg = (f'{{}} api.set_task_start: Database locked. Sleeping for {sleep_time} '
219
- f'seconds')
220
-
221
- blocked = True
222
- while blocked:
223
- try:
224
- session.refresh(cg_sub)
225
- cg_sub.set_task_start(task_idx, iter_idx)
226
- session.commit()
227
- blocked = False
228
- except OperationalError:
229
- # Database is likely locked.
230
- session.rollback()
231
- print(block_msg.format(datetime.now()), flush=True)
232
- sleep(sleep_time)
233
-
234
- session.close()
235
-
236
-
237
- def set_task_end(cmd_group_sub_id, task_idx, iter_idx, dir_path=None, config_dir=None):
238
-
239
- project = Project(dir_path, config_dir)
240
- Session = init_db(project, check_exists=True)
241
- session = Session()
242
-
243
- cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
244
-
245
- sleep_time = 5
246
- block_msg = (f'{{}} api.set_task_end: Database locked. Sleeping for {sleep_time} '
247
- f'seconds')
248
-
249
- blocked = True
250
- while blocked:
251
- try:
252
- session.refresh(cg_sub)
253
- cg_sub.set_task_end(task_idx, iter_idx)
254
- session.commit()
255
- blocked = False
256
- except OperationalError:
257
- # Database is likely locked.
258
- session.rollback()
259
- print(block_msg.format(datetime.now()), flush=True)
260
- sleep(sleep_time)
261
-
262
- session.close()
263
-
264
-
265
- def archive(cmd_group_sub_id, task_idx, iter_idx, dir_path=None, config_dir=None):
266
- """Initiate an archive of a given task.
267
-
268
- Parameters
269
- ----------
270
- cmd_group_sub_id : int
271
- ID of the command group submission for which an archive is to be
272
- started.
273
- task_idx : int
274
- The task index to be archived (or rather, the task whose working directory
275
- will be archived).
276
- dir_path : str or Path, optional
277
- The directory in which the Workflow will be generated. By default, this
278
- is the working (i.e. invoking) directory.
279
-
280
- """
281
-
282
- project = Project(dir_path, config_dir)
283
- Session = init_db(project, check_exists=True)
284
- session = Session()
285
-
286
- cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
287
- cg_sub.do_archive(task_idx, iter_idx)
288
-
289
- session.commit()
290
- session.close()
291
-
292
-
293
- def root_archive(workflow_id, dir_path=None, config_dir=None):
294
- """Archive the root directory of the Workflow."""
295
-
296
- project = Project(dir_path, config_dir)
297
- Session = init_db(project, check_exists=True)
298
- session = Session()
299
-
300
- workflow = session.query(Workflow).get(workflow_id)
301
- workflow.do_root_archive()
302
-
303
- session.commit()
304
- session.close()
305
-
306
-
307
- def get_scheduler_stats(cmd_group_sub_id, task_idx, iter_idx, dir_path=None,
308
- config_dir=None):
309
- """Scrape completed task information from the scheduler.
310
-
311
- Parameters
312
- ----------
313
- cmd_group_sub_id : int
314
- ID of the command group submission for which an archive is to be
315
- started.
316
- task_idx : int
317
- The task index to be archived (or rather, the task whose working directory
318
- will be archived).
319
- dir_path : str or Path, optional
320
- The directory in which the Workflow will be generated. By default, this
321
- is the working (i.e. invoking) directory.
322
-
323
- """
324
-
325
- project = Project(dir_path, config_dir)
326
- Session = init_db(project, check_exists=True)
327
- session = Session()
328
-
329
- cg_sub = session.query(CommandGroupSubmission).get(cmd_group_sub_id)
330
- cg_sub.get_scheduler_stats(task_idx, iter_idx)
331
-
332
- session.commit()
333
- session.close()
334
-
335
-
336
- def get_stats(dir_path=None, workflow_id=None, jsonable=True, datetime_dicts=False,
337
- config_dir=None):
338
- """Get task statistics (as a JSON-like dict) for a project."""
339
-
340
- project = Project(dir_path, config_dir)
341
- Session = init_db(project, check_exists=True)
342
- session = Session()
343
-
344
- all_workflow_ids = [i.id_ for i in session.query(Workflow.id_)]
345
-
346
- if not all_workflow_ids:
347
- msg = 'No workflows exist in directory: "{}"'
348
- raise ValueError(msg.format(project.dir_path))
349
-
350
- elif workflow_id:
351
-
352
- if workflow_id not in all_workflow_ids:
353
- msg = 'No workflow with ID "{}" was found in directory: "{}"'
354
- raise ValueError(msg.format(workflow_id, project.dir_path))
355
-
356
- workflow_ids = [workflow_id]
357
-
358
- else:
359
- workflow_ids = all_workflow_ids
360
-
361
- workflows = [session.query(Workflow).get(i) for i in workflow_ids]
362
- stats = [i.get_stats(jsonable=jsonable, datetime_dicts=datetime_dicts)
363
- for i in workflows]
364
-
365
- session.close()
366
-
367
- return stats
368
-
369
-
370
- def get_formatted_stats(dir_path=None, workflow_id=None, max_width=100,
371
- show_task_end=False, config_dir=None):
372
- """Get task statistics formatted like a table."""
373
-
374
- stats = get_stats(dir_path, workflow_id, jsonable=True, config_dir=config_dir)
375
-
376
- out = ''
377
- for workflow in stats:
378
- out += 'Workflow ID: {}\n'.format(workflow['workflow_id'])
379
- for submission in workflow['submissions']:
380
- out += 'Submission ID: {}\n'.format(submission['submission_id'])
381
- for cmd_group_sub in submission['command_group_submissions']:
382
- out += 'Command group submission ID: {}\n'.format(
383
- cmd_group_sub['command_group_submission_id'])
384
- out += 'Commands:\n'
385
- for cmd in cmd_group_sub['commands']:
386
- out += '\t{}\n'.format(cmd)
387
- task_table = BeautifulTable(max_width=max_width)
388
- task_table.set_style(BeautifulTable.STYLE_BOX)
389
- task_table.row_separator_char = ''
390
- headers = [
391
- 'It.',
392
- '#',
393
- 'SID',
394
- 'Dir.',
395
- 'Start',
396
- 'Duration',
397
- 'Archive',
398
- 'memory',
399
- 'hostname',
400
- ]
401
- if show_task_end:
402
- headers = headers[:5] + ['End'] + headers[5:]
403
- task_table.column_headers = headers
404
- task_table.column_alignments['Duration'] = BeautifulTable.ALIGN_RIGHT
405
-
406
- for task in cmd_group_sub['tasks']:
407
- row = [
408
- task['iteration'],
409
- task['order_id'],
410
- task['scheduler_id'],
411
- task['working_directory'],
412
- task['start_time'] or 'pending',
413
- task['duration'] or '-',
414
- task['archive_status'] or '-',
415
- task['memory'] or '-',
416
- task['hostname'] or '-',
417
- ]
418
- if show_task_end:
419
- row = row[:5] + [task['end_time'] or '-'] + row[5:]
420
- task_table.append_row(row)
421
-
422
- out += str(task_table) + '\n\n'
423
-
424
- return out
425
-
426
-
427
- def save_stats(save_path, dir_path=None, workflow_id=None, config_dir=None):
428
- """Save task statistics as a JSON file."""
429
-
430
- stats = get_stats(dir_path, workflow_id, jsonable=True, config_dir=config_dir)
431
-
432
- save_path = Path(save_path)
433
- with save_path.open('w') as handle:
434
- json.dump(stats, handle, indent=4, sort_keys=True)
435
-
436
-
437
- def kill(dir_path=None, workflow_id=None, config_dir=None):
438
- """Delete jobscripts associated with a given workflow."""
439
-
440
- project = Project(dir_path, config_dir)
441
- Session = init_db(project, check_exists=True)
442
- session = Session()
443
-
444
- all_workflow_ids = [i.id_ for i in session.query(Workflow.id_)]
445
-
446
- if not all_workflow_ids:
447
- msg = 'No workflows exist in directory: "{}"'
448
- raise ValueError(msg.format(project.dir_path))
449
-
450
- elif workflow_id:
451
-
452
- if workflow_id not in all_workflow_ids:
453
- msg = 'No workflow with ID "{}" was found in directory: "{}"'
454
- raise ValueError(msg.format(workflow_id, project.dir_path))
455
-
456
- workflow_ids = [workflow_id]
457
-
458
- else:
459
- workflow_ids = all_workflow_ids
460
-
461
- for i in workflow_ids:
462
- workflow = session.query(Workflow).get(i)
463
- workflow.kill_active()
464
-
465
- session.commit()
466
- session.close()
467
-
468
-
469
- def update_config(name, value, config_dir=None):
470
- Config.update(name, value, config_dir=config_dir)
471
-
472
-
473
- def cloud_connect(provider, config_dir=None):
474
- Config.set_config(config_dir)
475
- token_key = {'dropbox': 'dropbox_token'}[provider.lower()]
476
- provider = {'dropbox': CloudProvider.dropbox}[provider.lower()]
477
- token = Config.get(token_key)
478
- good = False
479
- if token:
480
- try:
481
- provider.check_access()
482
- print('Connected to cloud provider.')
483
- good = True
484
- except:
485
- print('Existing cloud provider key does not work.')
486
- pass
487
- if not good:
488
- print('Getting new cloud token.')
489
- token = provider.get_token()
490
- update_config(token_key, token, config_dir=config_dir)