hpcflow 0.1.9__py3-none-any.whl → 0.2.0a271__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (275) hide show
  1. hpcflow/__init__.py +2 -11
  2. hpcflow/__pyinstaller/__init__.py +5 -0
  3. hpcflow/__pyinstaller/hook-hpcflow.py +40 -0
  4. hpcflow/_version.py +1 -1
  5. hpcflow/app.py +43 -0
  6. hpcflow/cli.py +2 -462
  7. hpcflow/data/demo_data_manifest/__init__.py +3 -0
  8. hpcflow/data/demo_data_manifest/demo_data_manifest.json +6 -0
  9. hpcflow/data/jinja_templates/test/test_template.txt +8 -0
  10. hpcflow/data/programs/hello_world/README.md +1 -0
  11. hpcflow/data/programs/hello_world/hello_world.c +87 -0
  12. hpcflow/data/programs/hello_world/linux/hello_world +0 -0
  13. hpcflow/data/programs/hello_world/macos/hello_world +0 -0
  14. hpcflow/data/programs/hello_world/win/hello_world.exe +0 -0
  15. hpcflow/data/scripts/__init__.py +1 -0
  16. hpcflow/data/scripts/bad_script.py +2 -0
  17. hpcflow/data/scripts/demo_task_1_generate_t1_infile_1.py +8 -0
  18. hpcflow/data/scripts/demo_task_1_generate_t1_infile_2.py +8 -0
  19. hpcflow/data/scripts/demo_task_1_parse_p3.py +7 -0
  20. hpcflow/data/scripts/do_nothing.py +2 -0
  21. hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
  22. hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
  23. hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
  24. hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
  25. hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
  26. hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
  27. hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
  28. hpcflow/data/scripts/generate_t1_file_01.py +7 -0
  29. hpcflow/data/scripts/import_future_script.py +7 -0
  30. hpcflow/data/scripts/input_file_generator_basic.py +3 -0
  31. hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
  32. hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
  33. hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
  34. hpcflow/data/scripts/main_script_test_direct_in_direct_out.py +6 -0
  35. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
  36. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
  37. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
  38. hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
  39. hpcflow/data/scripts/main_script_test_direct_in_direct_out_all_iters_test.py +15 -0
  40. hpcflow/data/scripts/main_script_test_direct_in_direct_out_env_spec.py +7 -0
  41. hpcflow/data/scripts/main_script_test_direct_in_direct_out_labels.py +8 -0
  42. hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
  43. hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
  44. hpcflow/data/scripts/main_script_test_direct_sub_param_in_direct_out.py +6 -0
  45. hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +12 -0
  46. hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
  47. hpcflow/data/scripts/main_script_test_hdf5_in_obj_group.py +12 -0
  48. hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +11 -0
  49. hpcflow/data/scripts/main_script_test_json_and_direct_in_json_out.py +14 -0
  50. hpcflow/data/scripts/main_script_test_json_in_json_and_direct_out.py +17 -0
  51. hpcflow/data/scripts/main_script_test_json_in_json_out.py +14 -0
  52. hpcflow/data/scripts/main_script_test_json_in_json_out_labels.py +16 -0
  53. hpcflow/data/scripts/main_script_test_json_in_obj.py +12 -0
  54. hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
  55. hpcflow/data/scripts/main_script_test_json_out_obj.py +10 -0
  56. hpcflow/data/scripts/main_script_test_json_sub_param_in_json_out_labels.py +16 -0
  57. hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
  58. hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
  59. hpcflow/data/scripts/output_file_parser_basic.py +3 -0
  60. hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
  61. hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
  62. hpcflow/data/scripts/parse_t1_file_01.py +4 -0
  63. hpcflow/data/scripts/script_exit_test.py +5 -0
  64. hpcflow/data/template_components/__init__.py +1 -0
  65. hpcflow/data/template_components/command_files.yaml +26 -0
  66. hpcflow/data/template_components/environments.yaml +13 -0
  67. hpcflow/data/template_components/parameters.yaml +14 -0
  68. hpcflow/data/template_components/task_schemas.yaml +139 -0
  69. hpcflow/data/workflows/workflow_1.yaml +5 -0
  70. hpcflow/examples.ipynb +1037 -0
  71. hpcflow/sdk/__init__.py +149 -0
  72. hpcflow/sdk/app.py +4266 -0
  73. hpcflow/sdk/cli.py +1479 -0
  74. hpcflow/sdk/cli_common.py +385 -0
  75. hpcflow/sdk/config/__init__.py +5 -0
  76. hpcflow/sdk/config/callbacks.py +246 -0
  77. hpcflow/sdk/config/cli.py +388 -0
  78. hpcflow/sdk/config/config.py +1410 -0
  79. hpcflow/sdk/config/config_file.py +501 -0
  80. hpcflow/sdk/config/errors.py +272 -0
  81. hpcflow/sdk/config/types.py +150 -0
  82. hpcflow/sdk/core/__init__.py +38 -0
  83. hpcflow/sdk/core/actions.py +3857 -0
  84. hpcflow/sdk/core/app_aware.py +25 -0
  85. hpcflow/sdk/core/cache.py +224 -0
  86. hpcflow/sdk/core/command_files.py +814 -0
  87. hpcflow/sdk/core/commands.py +424 -0
  88. hpcflow/sdk/core/element.py +2071 -0
  89. hpcflow/sdk/core/enums.py +221 -0
  90. hpcflow/sdk/core/environment.py +256 -0
  91. hpcflow/sdk/core/errors.py +1043 -0
  92. hpcflow/sdk/core/execute.py +207 -0
  93. hpcflow/sdk/core/json_like.py +809 -0
  94. hpcflow/sdk/core/loop.py +1320 -0
  95. hpcflow/sdk/core/loop_cache.py +282 -0
  96. hpcflow/sdk/core/object_list.py +933 -0
  97. hpcflow/sdk/core/parameters.py +3371 -0
  98. hpcflow/sdk/core/rule.py +196 -0
  99. hpcflow/sdk/core/run_dir_files.py +57 -0
  100. hpcflow/sdk/core/skip_reason.py +7 -0
  101. hpcflow/sdk/core/task.py +3792 -0
  102. hpcflow/sdk/core/task_schema.py +993 -0
  103. hpcflow/sdk/core/test_utils.py +538 -0
  104. hpcflow/sdk/core/types.py +447 -0
  105. hpcflow/sdk/core/utils.py +1207 -0
  106. hpcflow/sdk/core/validation.py +87 -0
  107. hpcflow/sdk/core/values.py +477 -0
  108. hpcflow/sdk/core/workflow.py +4820 -0
  109. hpcflow/sdk/core/zarr_io.py +206 -0
  110. hpcflow/sdk/data/__init__.py +13 -0
  111. hpcflow/sdk/data/config_file_schema.yaml +34 -0
  112. hpcflow/sdk/data/config_schema.yaml +260 -0
  113. hpcflow/sdk/data/environments_spec_schema.yaml +21 -0
  114. hpcflow/sdk/data/files_spec_schema.yaml +5 -0
  115. hpcflow/sdk/data/parameters_spec_schema.yaml +7 -0
  116. hpcflow/sdk/data/task_schema_spec_schema.yaml +3 -0
  117. hpcflow/sdk/data/workflow_spec_schema.yaml +22 -0
  118. hpcflow/sdk/demo/__init__.py +3 -0
  119. hpcflow/sdk/demo/cli.py +242 -0
  120. hpcflow/sdk/helper/__init__.py +3 -0
  121. hpcflow/sdk/helper/cli.py +137 -0
  122. hpcflow/sdk/helper/helper.py +300 -0
  123. hpcflow/sdk/helper/watcher.py +192 -0
  124. hpcflow/sdk/log.py +288 -0
  125. hpcflow/sdk/persistence/__init__.py +18 -0
  126. hpcflow/sdk/persistence/base.py +2817 -0
  127. hpcflow/sdk/persistence/defaults.py +6 -0
  128. hpcflow/sdk/persistence/discovery.py +39 -0
  129. hpcflow/sdk/persistence/json.py +954 -0
  130. hpcflow/sdk/persistence/pending.py +948 -0
  131. hpcflow/sdk/persistence/store_resource.py +203 -0
  132. hpcflow/sdk/persistence/types.py +309 -0
  133. hpcflow/sdk/persistence/utils.py +73 -0
  134. hpcflow/sdk/persistence/zarr.py +2388 -0
  135. hpcflow/sdk/runtime.py +320 -0
  136. hpcflow/sdk/submission/__init__.py +3 -0
  137. hpcflow/sdk/submission/enums.py +70 -0
  138. hpcflow/sdk/submission/jobscript.py +2379 -0
  139. hpcflow/sdk/submission/schedulers/__init__.py +281 -0
  140. hpcflow/sdk/submission/schedulers/direct.py +233 -0
  141. hpcflow/sdk/submission/schedulers/sge.py +376 -0
  142. hpcflow/sdk/submission/schedulers/slurm.py +598 -0
  143. hpcflow/sdk/submission/schedulers/utils.py +25 -0
  144. hpcflow/sdk/submission/shells/__init__.py +52 -0
  145. hpcflow/sdk/submission/shells/base.py +229 -0
  146. hpcflow/sdk/submission/shells/bash.py +504 -0
  147. hpcflow/sdk/submission/shells/os_version.py +115 -0
  148. hpcflow/sdk/submission/shells/powershell.py +352 -0
  149. hpcflow/sdk/submission/submission.py +1402 -0
  150. hpcflow/sdk/submission/types.py +140 -0
  151. hpcflow/sdk/typing.py +194 -0
  152. hpcflow/sdk/utils/arrays.py +69 -0
  153. hpcflow/sdk/utils/deferred_file.py +55 -0
  154. hpcflow/sdk/utils/hashing.py +16 -0
  155. hpcflow/sdk/utils/patches.py +31 -0
  156. hpcflow/sdk/utils/strings.py +69 -0
  157. hpcflow/tests/api/test_api.py +32 -0
  158. hpcflow/tests/conftest.py +123 -0
  159. hpcflow/tests/data/__init__.py +0 -0
  160. hpcflow/tests/data/benchmark_N_elements.yaml +6 -0
  161. hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
  162. hpcflow/tests/data/multi_path_sequences.yaml +29 -0
  163. hpcflow/tests/data/workflow_1.json +10 -0
  164. hpcflow/tests/data/workflow_1.yaml +5 -0
  165. hpcflow/tests/data/workflow_1_slurm.yaml +8 -0
  166. hpcflow/tests/data/workflow_1_wsl.yaml +8 -0
  167. hpcflow/tests/data/workflow_test_run_abort.yaml +42 -0
  168. hpcflow/tests/jinja_templates/test_jinja_templates.py +161 -0
  169. hpcflow/tests/programs/test_programs.py +180 -0
  170. hpcflow/tests/schedulers/direct_linux/test_direct_linux_submission.py +12 -0
  171. hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
  172. hpcflow/tests/schedulers/slurm/test_slurm_submission.py +14 -0
  173. hpcflow/tests/scripts/test_input_file_generators.py +282 -0
  174. hpcflow/tests/scripts/test_main_scripts.py +1361 -0
  175. hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
  176. hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
  177. hpcflow/tests/shells/wsl/test_wsl_submission.py +14 -0
  178. hpcflow/tests/unit/test_action.py +1066 -0
  179. hpcflow/tests/unit/test_action_rule.py +24 -0
  180. hpcflow/tests/unit/test_app.py +132 -0
  181. hpcflow/tests/unit/test_cache.py +46 -0
  182. hpcflow/tests/unit/test_cli.py +172 -0
  183. hpcflow/tests/unit/test_command.py +377 -0
  184. hpcflow/tests/unit/test_config.py +195 -0
  185. hpcflow/tests/unit/test_config_file.py +162 -0
  186. hpcflow/tests/unit/test_element.py +666 -0
  187. hpcflow/tests/unit/test_element_iteration.py +88 -0
  188. hpcflow/tests/unit/test_element_set.py +158 -0
  189. hpcflow/tests/unit/test_group.py +115 -0
  190. hpcflow/tests/unit/test_input_source.py +1479 -0
  191. hpcflow/tests/unit/test_input_value.py +398 -0
  192. hpcflow/tests/unit/test_jobscript_unit.py +757 -0
  193. hpcflow/tests/unit/test_json_like.py +1247 -0
  194. hpcflow/tests/unit/test_loop.py +2674 -0
  195. hpcflow/tests/unit/test_meta_task.py +325 -0
  196. hpcflow/tests/unit/test_multi_path_sequences.py +259 -0
  197. hpcflow/tests/unit/test_object_list.py +116 -0
  198. hpcflow/tests/unit/test_parameter.py +243 -0
  199. hpcflow/tests/unit/test_persistence.py +664 -0
  200. hpcflow/tests/unit/test_resources.py +243 -0
  201. hpcflow/tests/unit/test_run.py +286 -0
  202. hpcflow/tests/unit/test_run_directories.py +29 -0
  203. hpcflow/tests/unit/test_runtime.py +9 -0
  204. hpcflow/tests/unit/test_schema_input.py +372 -0
  205. hpcflow/tests/unit/test_shell.py +129 -0
  206. hpcflow/tests/unit/test_slurm.py +39 -0
  207. hpcflow/tests/unit/test_submission.py +502 -0
  208. hpcflow/tests/unit/test_task.py +2560 -0
  209. hpcflow/tests/unit/test_task_schema.py +182 -0
  210. hpcflow/tests/unit/test_utils.py +616 -0
  211. hpcflow/tests/unit/test_value_sequence.py +549 -0
  212. hpcflow/tests/unit/test_values.py +91 -0
  213. hpcflow/tests/unit/test_workflow.py +827 -0
  214. hpcflow/tests/unit/test_workflow_template.py +186 -0
  215. hpcflow/tests/unit/utils/test_arrays.py +40 -0
  216. hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
  217. hpcflow/tests/unit/utils/test_hashing.py +65 -0
  218. hpcflow/tests/unit/utils/test_patches.py +5 -0
  219. hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
  220. hpcflow/tests/unit/utils/test_strings.py +97 -0
  221. hpcflow/tests/workflows/__init__.py +0 -0
  222. hpcflow/tests/workflows/test_directory_structure.py +31 -0
  223. hpcflow/tests/workflows/test_jobscript.py +355 -0
  224. hpcflow/tests/workflows/test_run_status.py +198 -0
  225. hpcflow/tests/workflows/test_skip_downstream.py +696 -0
  226. hpcflow/tests/workflows/test_submission.py +140 -0
  227. hpcflow/tests/workflows/test_workflows.py +564 -0
  228. hpcflow/tests/workflows/test_zip.py +18 -0
  229. hpcflow/viz_demo.ipynb +6794 -0
  230. hpcflow-0.2.0a271.dist-info/LICENSE +375 -0
  231. hpcflow-0.2.0a271.dist-info/METADATA +65 -0
  232. hpcflow-0.2.0a271.dist-info/RECORD +237 -0
  233. {hpcflow-0.1.9.dist-info → hpcflow-0.2.0a271.dist-info}/WHEEL +4 -5
  234. hpcflow-0.2.0a271.dist-info/entry_points.txt +6 -0
  235. hpcflow/api.py +0 -458
  236. hpcflow/archive/archive.py +0 -308
  237. hpcflow/archive/cloud/cloud.py +0 -47
  238. hpcflow/archive/cloud/errors.py +0 -9
  239. hpcflow/archive/cloud/providers/dropbox.py +0 -432
  240. hpcflow/archive/errors.py +0 -5
  241. hpcflow/base_db.py +0 -4
  242. hpcflow/config.py +0 -232
  243. hpcflow/copytree.py +0 -66
  244. hpcflow/data/examples/_config.yml +0 -14
  245. hpcflow/data/examples/damask/demo/1.run.yml +0 -4
  246. hpcflow/data/examples/damask/demo/2.process.yml +0 -29
  247. hpcflow/data/examples/damask/demo/geom.geom +0 -2052
  248. hpcflow/data/examples/damask/demo/load.load +0 -1
  249. hpcflow/data/examples/damask/demo/material.config +0 -185
  250. hpcflow/data/examples/damask/inputs/geom.geom +0 -2052
  251. hpcflow/data/examples/damask/inputs/load.load +0 -1
  252. hpcflow/data/examples/damask/inputs/material.config +0 -185
  253. hpcflow/data/examples/damask/profiles/_variable_lookup.yml +0 -21
  254. hpcflow/data/examples/damask/profiles/damask.yml +0 -4
  255. hpcflow/data/examples/damask/profiles/damask_process.yml +0 -8
  256. hpcflow/data/examples/damask/profiles/damask_run.yml +0 -5
  257. hpcflow/data/examples/damask/profiles/default.yml +0 -6
  258. hpcflow/data/examples/thinking.yml +0 -177
  259. hpcflow/errors.py +0 -2
  260. hpcflow/init_db.py +0 -37
  261. hpcflow/models.py +0 -2549
  262. hpcflow/nesting.py +0 -9
  263. hpcflow/profiles.py +0 -455
  264. hpcflow/project.py +0 -81
  265. hpcflow/scheduler.py +0 -323
  266. hpcflow/utils.py +0 -103
  267. hpcflow/validation.py +0 -167
  268. hpcflow/variables.py +0 -544
  269. hpcflow-0.1.9.dist-info/METADATA +0 -168
  270. hpcflow-0.1.9.dist-info/RECORD +0 -45
  271. hpcflow-0.1.9.dist-info/entry_points.txt +0 -8
  272. hpcflow-0.1.9.dist-info/top_level.txt +0 -1
  273. /hpcflow/{archive → data/jinja_templates}/__init__.py +0 -0
  274. /hpcflow/{archive/cloud → data/programs}/__init__.py +0 -0
  275. /hpcflow/{archive/cloud/providers → data/workflows}/__init__.py +0 -0
hpcflow/scheduler.py DELETED
@@ -1,323 +0,0 @@
1
- """`hpcflow.scheduler.py`"""
2
-
3
- from datetime import datetime
4
- from subprocess import run, PIPE
5
- from pprint import pprint
6
-
7
- from hpcflow.config import Config as CONFIG
8
- from hpcflow._version import __version__
9
-
10
-
11
- class Scheduler(object):
12
-
13
- options = None
14
- output_dir = None
15
- error_dir = None
16
-
17
- def __repr__(self):
18
- out = ('{}('
19
- 'options={!r}, '
20
- 'output_dir={!r}, '
21
- 'error_dir={!r}'
22
- ')').format(
23
- self.__class__.__name__,
24
- self.options,
25
- self.output_dir,
26
- self.error_dir,
27
- )
28
- return out
29
-
30
- def __init__(self, options=None, output_dir=None, error_dir=None):
31
-
32
- self.output_dir = output_dir or CONFIG.get('default_output_dir')
33
- self.error_dir = error_dir or CONFIG.get('default_error_dir')
34
- self.options = options
35
-
36
-
37
- class SunGridEngine(Scheduler):
38
-
39
- _NAME = 'sge'
40
- SHEBANG = '#!/bin/bash --login'
41
-
42
- STATS_DELIM = '==============================================================\n'
43
-
44
- # Options that determine how to set the output/error directories:
45
- STDOUT_OPT = 'o'
46
- STDERR_OPT = 'e'
47
- STDOUT_OPT_FMT = '{}/'
48
- STDERR_OPT_FMT = '{}/'
49
-
50
- # Required options to ensure the job scripts work with hpcflow:
51
- REQ_OPT = ['cwd']
52
- REQ_PARAMETRISED_OPT = {}
53
-
54
- ALLOWED_USER_OPTS = [
55
- 'pe', # Parallel environment
56
- 'l', # Resource request
57
- 'tc', # Max running tasks
58
- 'P', # Project name (e.g. to which account jobs are accounted against)
59
- ]
60
-
61
- NUM_CORES_VAR = '$NSLOTS'
62
-
63
- def __init__(self, options=None, output_dir=None, error_dir=None):
64
-
65
- for i in options:
66
- if i not in SunGridEngine.ALLOWED_USER_OPTS:
67
- msg = ('Option "{}" is not allowed for scheduler "{}". Allowed options '
68
- 'are: {}.')
69
- raise ValueError(
70
- msg.format(i, SunGridEngine._NAME, SunGridEngine.ALLOWED_USER_OPTS))
71
-
72
- super().__init__(options=options, output_dir=output_dir, error_dir=error_dir)
73
-
74
- def get_formatted_options(self, max_num_tasks, task_step_size, user_opt=True,
75
- name=None):
76
-
77
- opts = ['#$ -{}'.format(i) for i in SunGridEngine.REQ_OPT]
78
- opts.append('#$ -{} {}'.format(
79
- SunGridEngine.STDOUT_OPT,
80
- SunGridEngine.STDOUT_OPT_FMT.format(self.output_dir)),
81
- )
82
- opts.append('#$ -{} {}'.format(
83
- SunGridEngine.STDERR_OPT,
84
- SunGridEngine.STDERR_OPT_FMT.format(self.error_dir)),
85
- )
86
- opts += ['#$ -{} {}'.format(i, j)
87
- for i, j in SunGridEngine.REQ_PARAMETRISED_OPT.items()]
88
-
89
- if name:
90
- opts += [f'#$ -N {name}']
91
-
92
- if user_opt:
93
- opts += ['#$ -{} {}'.format(k, v).strip()
94
- for k, v in sorted(self.options.items())]
95
-
96
- opts += ['', '#$ -t 1-{}:{}'.format(max_num_tasks, task_step_size)]
97
-
98
- return opts
99
-
100
- def write_jobscript(self, dir_path, workflow_directory, command_group_order,
101
- max_num_tasks, task_step_size, environment, archive,
102
- alternate_scratch_dir, command_group_submission_id, name):
103
- """Write the jobscript.
104
-
105
- Parameters
106
- ----------
107
- archive : bool
108
-
109
- """
110
-
111
- js_ext = CONFIG.get('jobscript_ext')
112
- js_name = 'js_{}'.format(command_group_order)
113
- js_fn = js_name + js_ext
114
- js_path = dir_path.joinpath(js_fn)
115
-
116
- cmd_name = 'cmd_{}'.format(command_group_order)
117
- cmd_fn = cmd_name + js_ext
118
-
119
- submit_dir_relative = dir_path.relative_to(workflow_directory).as_posix()
120
-
121
- wk_dirs_path = ('${{ITER_DIR}}/working_dirs_{}{}').format(
122
- command_group_order, CONFIG.get('working_dirs_file_ext'))
123
-
124
- dt_stamp = datetime.now().strftime(r'%Y.%m.%d at %H:%M:%S')
125
- about_msg = ['# --- jobscript generated by `hpcflow` (version: {}) '
126
- 'on {} ---'.format(__version__, dt_stamp)]
127
-
128
- define_dirs_A = [
129
- 'ROOT_DIR=`pwd`',
130
- 'SUBMIT_DIR=$ROOT_DIR/{}'.format(submit_dir_relative),
131
- 'ITER_DIR=$SUBMIT_DIR/iter_$ITER_IDX',
132
- 'LOG_PATH=$ITER_DIR/log_{}.$SGE_TASK_ID'.format(command_group_order),
133
- 'TASK_IDX=$((($SGE_TASK_ID - 1)/{}))'.format(task_step_size),
134
- ]
135
-
136
- write_cmd_exec = [(
137
- f'hpcflow write-runtime-files --directory $ROOT_DIR '
138
- f'--config-dir {CONFIG.get("config_dir")} '
139
- f'{command_group_submission_id} $TASK_IDX $ITER_IDX > $LOG_PATH 2>&1'
140
- )]
141
-
142
- define_dirs_B = [
143
- 'INPUTS_DIR_REL=`sed -n "${{SGE_TASK_ID}}p" {}`'.format(wk_dirs_path),
144
- 'INPUTS_DIR=$ROOT_DIR/$INPUTS_DIR_REL',
145
- ]
146
-
147
- if alternate_scratch_dir:
148
- alt_scratch_exc_path = '$ITER_DIR/{}_{}_$TASK_IDX{}'.format(
149
- CONFIG.get('alt_scratch_exc_file'),
150
- command_group_order,
151
- CONFIG.get('alt_scratch_exc_file_ext'),
152
- )
153
- define_dirs_B.append('ALT_SCRATCH_EXC=' + alt_scratch_exc_path)
154
- in_dir_scratch = 'INPUTS_DIR_SCRATCH={}/$INPUTS_DIR_REL'.format(
155
- alternate_scratch_dir)
156
- copy_to_alt = [
157
- ('rsync -avviz --exclude-from="${ALT_SCRATCH_EXC}" '
158
- '$INPUTS_DIR/ $INPUTS_DIR_SCRATCH >> $LOG_PATH 2>&1'),
159
- '',
160
- ]
161
- move_from_alt = [
162
- '',
163
- ('rsync -avviz $INPUTS_DIR_SCRATCH/ $INPUTS_DIR --remove-source-files'
164
- ' >> $LOG_PATH 2>&1'),
165
- '',
166
- ]
167
- else:
168
- in_dir_scratch = 'INPUTS_DIR_SCRATCH=$INPUTS_DIR'
169
- copy_to_alt = []
170
- move_from_alt = []
171
-
172
- define_dirs_B.append(in_dir_scratch)
173
-
174
- log_stuff = [
175
- r'printf "Jobscript variables:\n" >> $LOG_PATH 2>&1',
176
- r'printf "ITER_IDX:\t ${ITER_IDX}\n" >> $LOG_PATH 2>&1',
177
- r'printf "ROOT_DIR:\t ${ROOT_DIR}\n" >> $LOG_PATH 2>&1',
178
- r'printf "SUBMIT_DIR:\t ${SUBMIT_DIR}\n" >> $LOG_PATH 2>&1',
179
- r'printf "ITER_DIR:\t ${ITER_DIR}\n" >> $LOG_PATH 2>&1',
180
- r'printf "LOG_PATH:\t ${LOG_PATH}\n" >> $LOG_PATH 2>&1',
181
- r'printf "SGE_TASK_ID:\t ${SGE_TASK_ID}\n" >> $LOG_PATH 2>&1',
182
- r'printf "TASK_IDX:\t ${TASK_IDX}\n" >> $LOG_PATH 2>&1',
183
- r'printf "INPUTS_DIR_REL:\t ${INPUTS_DIR_REL}\n" >> $LOG_PATH 2>&1',
184
- r'printf "INPUTS_DIR:\t ${INPUTS_DIR}\n" >> $LOG_PATH 2>&1',
185
- r'printf "INPUTS_DIR_SCRATCH:\t ${INPUTS_DIR_SCRATCH}\n" >> $LOG_PATH 2>&1',
186
- ]
187
-
188
- if alternate_scratch_dir:
189
- log_stuff.append(
190
- r'printf "ALT_SCRATCH_EXC:\t ${ALT_SCRATCH_EXC}\n" >> $LOG_PATH 2>&1',
191
- )
192
-
193
- log_stuff.append(r'printf "\n" >> $LOG_PATH 2>&1')
194
-
195
- if environment:
196
- loads = [''] + environment + ['']
197
- else:
198
- loads = []
199
-
200
- set_task_args = (f'--directory $ROOT_DIR '
201
- f'--config-dir {CONFIG.get("config_dir")} '
202
- f'{command_group_submission_id} '
203
- f'$TASK_IDX $ITER_IDX >> $LOG_PATH 2>&1')
204
- cmd_exec = [
205
- f'hpcflow set-task-start {set_task_args}',
206
- f'',
207
- f'cd $INPUTS_DIR_SCRATCH',
208
- f'. $SUBMIT_DIR/{cmd_fn}',
209
- f'',
210
- f'hpcflow set-task-end {set_task_args}',
211
- ]
212
-
213
- arch_lns = []
214
- if archive:
215
- arch_lns = [
216
- (f'hpcflow archive --directory $ROOT_DIR '
217
- f'--config-dir {CONFIG.get("config_dir")} '
218
- f'{command_group_submission_id} '
219
- f'$TASK_IDX $ITER_IDX >> $LOG_PATH 2>&1'),
220
- ''
221
- ]
222
-
223
- js_lines = ([SunGridEngine.SHEBANG, ''] +
224
- about_msg + [''] +
225
- self.get_formatted_options(max_num_tasks, task_step_size, name=name) +
226
- [''] +
227
- define_dirs_A + [''] +
228
- write_cmd_exec + [''] +
229
- define_dirs_B + [''] +
230
- log_stuff + [''] +
231
- loads + [''] +
232
- copy_to_alt +
233
- cmd_exec +
234
- move_from_alt +
235
- arch_lns)
236
-
237
- # Write jobscript:
238
- with js_path.open('w') as handle:
239
- handle.write('\n'.join(js_lines))
240
-
241
- return js_path
242
-
243
- def write_stats_jobscript(self, dir_path, workflow_directory, command_group_order,
244
- max_num_tasks, task_step_size, command_group_submission_id,
245
- name):
246
-
247
- js_ext = CONFIG.get('jobscript_ext')
248
- js_name = 'st_{}'.format(command_group_order)
249
- js_fn = js_name + js_ext
250
- js_path = dir_path.joinpath(js_fn)
251
-
252
- dt_stamp = datetime.now().strftime(r'%Y.%m.%d at %H:%M:%S')
253
- about_msg = ['# --- jobscript generated by `hpcflow` (version: {}) '
254
- 'on {} ---'.format(__version__, dt_stamp)]
255
-
256
- submit_dir_relative = dir_path.relative_to(workflow_directory).as_posix()
257
-
258
- define_dirs = [
259
- 'ROOT_DIR=`pwd`',
260
- 'SUBMIT_DIR=$ROOT_DIR/{}'.format(submit_dir_relative),
261
- 'ITER_DIR=$SUBMIT_DIR/iter_$ITER_IDX',
262
- 'LOG_PATH=$ITER_DIR/log_{}.$SGE_TASK_ID'.format(command_group_order),
263
- 'TASK_IDX=$((($SGE_TASK_ID - 1)/{}))'.format(task_step_size),
264
- ]
265
-
266
- log_stuff = [
267
- r'printf "Jobscript variables:\n" >> $LOG_PATH 2>&1',
268
- r'printf "ITER_IDX:\t ${ITER_IDX}\n" >> $LOG_PATH 2>&1',
269
- r'printf "ROOT_DIR:\t ${ROOT_DIR}\n" >> $LOG_PATH 2>&1',
270
- r'printf "SUBMIT_DIR:\t ${SUBMIT_DIR}\n" >> $LOG_PATH 2>&1',
271
- r'printf "ITER_DIR:\t ${ITER_DIR}\n" >> $LOG_PATH 2>&1',
272
- r'printf "LOG_PATH:\t ${LOG_PATH}\n" >> $LOG_PATH 2>&1',
273
- r'printf "SGE_TASK_ID:\t ${SGE_TASK_ID}\n" >> $LOG_PATH 2>&1',
274
- r'printf "TASK_IDX:\t ${TASK_IDX}\n" >> $LOG_PATH 2>&1',
275
- ]
276
-
277
- cmd_exec = [(
278
- f'hpcflow get-scheduler-stats --directory $ROOT_DIR '
279
- f'--config-dir {CONFIG.get("config_dir")} '
280
- f'{command_group_submission_id} $TASK_IDX $ITER_IDX >> $LOG_PATH 2>&1'
281
- )]
282
-
283
- opt = self.get_formatted_options(max_num_tasks, task_step_size, user_opt=False,
284
- name=name)
285
- opt.append('#$ -l short') # Temp (should be a profile option)
286
-
287
- js_lines = ([SunGridEngine.SHEBANG, ''] +
288
- about_msg + [''] +
289
- opt + [''] +
290
- define_dirs + [''] +
291
- log_stuff + [''] +
292
- cmd_exec)
293
-
294
- # Write jobscript:
295
- with js_path.open('w') as handle:
296
- handle.write('\n'.join(js_lines))
297
-
298
- return js_path
299
-
300
- def get_scheduler_stats(self, scheduler_job_id, task_id):
301
-
302
- cmd = ['/opt/site/sge/bin/lx-amd64/qacct', '-j', str(scheduler_job_id)]
303
- proc = run(cmd, stdout=PIPE, stderr=PIPE)
304
- out = proc.stdout.decode().strip()
305
- _ = proc.stderr.decode().strip()
306
-
307
- info = {}
308
- qacct = out.split(SunGridEngine.STATS_DELIM)
309
- for i in qacct[1:]:
310
- keep = False
311
- for ln in i.splitlines():
312
- key, val = ln.strip().split(None, 1)
313
- val = val.strip()
314
- info.update({key: val})
315
- if key == 'taskid':
316
- if val == 'undefined' or int(val) == task_id:
317
- keep = True
318
- if keep:
319
- break
320
- else:
321
- info = {}
322
-
323
- return info
hpcflow/utils.py DELETED
@@ -1,103 +0,0 @@
1
- """`hpcflow.utils.py`
2
-
3
- Utility functions that are not particularly specific to `hpcflow`.
4
-
5
- """
6
-
7
- import random
8
-
9
-
10
- def coerce_same_length(all_lists):
11
- """
12
- TODO: add docstring and examples
13
-
14
- """
15
-
16
- all_len = [len(i) for i in all_lists]
17
- uniq_lens = set(all_len)
18
- num_uniq_lens = len(uniq_lens)
19
-
20
- if num_uniq_lens == 1:
21
- out = all_lists
22
-
23
- elif num_uniq_lens == 2:
24
-
25
- if min(uniq_lens) != 1:
26
- raise ValueError('bad!')
27
-
28
- max_len = max(uniq_lens)
29
- out = []
30
- for i in all_lists:
31
- if len(i) != max_len:
32
- i = i * max_len
33
- out.append(i)
34
-
35
- else:
36
- raise ValueError('bad!')
37
-
38
- return out
39
-
40
-
41
- def zeropad(num, largest):
42
- """Return a zero-padded string of a number, given the largest number.
43
-
44
- TODO: want to support floating-point numbers as well? Or rename function
45
- accordingly.
46
-
47
- Parameters
48
- ----------
49
- num : int
50
- The number to be formatted with zeros padding on the left.
51
- largest : int
52
- The number that determines the number of zeros to pad with.
53
-
54
- Returns
55
- -------
56
- padded : str
57
- The original number, `num`, formatted as a string with zeros added
58
- on the left.
59
-
60
- """
61
-
62
- num_digits = len('{:.0f}'.format(largest))
63
- padded = '{0:0{width}}'.format(num, width=num_digits)
64
-
65
- return padded
66
-
67
-
68
- def datetime_to_dict(dt):
69
- return {
70
- 'year': dt.year,
71
- 'month': dt.month,
72
- 'day': dt.day,
73
- 'hour': dt.hour,
74
- 'minute': dt.minute,
75
- 'second': dt.second,
76
- 'microsecond': dt.microsecond,
77
- }
78
-
79
-
80
- def timedelta_to_dict(td):
81
- return {
82
- 'days': td.days,
83
- 'seconds': td.seconds,
84
- 'microseconds': td.microseconds,
85
- }
86
-
87
-
88
- def format_time_delta(time_delta):
89
-
90
- days, days_rem = divmod(time_delta.total_seconds(), 3600 * 24)
91
- hours, hours_rem = divmod(days_rem, 3600)
92
- mins, seconds = divmod(hours_rem, 60)
93
-
94
- time_diff_fmt = '{:02.0f}:{:02.0f}:{:02.0f}'.format(hours, mins, round(seconds))
95
- if days > 0:
96
- days_str = 'day' if days == 1 else 'days'
97
- time_diff_fmt = '{} {}, '.format(int(days), days_str) + time_diff_fmt
98
-
99
- return time_diff_fmt
100
-
101
-
102
- def get_random_hex(n=10):
103
- return ''.join([random.choice('0123456789abcdef') for i in range(n)])
hpcflow/validation.py DELETED
@@ -1,167 +0,0 @@
1
- """`hpcflow.validation.py`
2
-
3
- These validation functions are invoked during initialisation of the `Workflow`
4
- and `CommandGroup` instances. They are extracted out as functions here to allow
5
- re-use by the `visualise` module, whose code may be invoked without necessarily
6
- constructing `Workflow` and `CommandGroup` instances.
7
-
8
- """
9
-
10
- from hpcflow.config import Config as CONFIG
11
- from hpcflow.nesting import NestingType
12
-
13
-
14
- def validate_workflow(workflow_dict):
15
- """Validate the `nesting`, `order` and `num_tasks` for each in a list of
16
- workflow command groups."""
17
-
18
- return workflow_dict
19
-
20
-
21
- def validate_job_profile(job_profile):
22
- """Validate the keys of a job profile.
23
-
24
- Parameters
25
- ----------
26
- job_profile : dict
27
- Dictionary representing a job profile.
28
-
29
- Returns
30
- -------
31
- job_profile : dict
32
- Dictionary representing a job profile.
33
-
34
- """
35
-
36
- # Validate profile keys:
37
- keys = job_profile.keys()
38
- missing_keys = list(set(CONFIG.get('profile_keys_required')) - set(keys))
39
- bad_keys = list(set(keys) - set(CONFIG.get('profile_keys_allowed')))
40
-
41
- # Check required keys exist:
42
- if len(missing_keys) > 0:
43
- msg = ('Job profile is missing required key(s): {}')
44
- raise ValueError(msg.format(missing_keys))
45
-
46
- # Check for unknown keys:
47
- if len(bad_keys) > 0:
48
- msg = ('Job profile contains unknown key(s): {}')
49
- raise ValueError(msg.format(bad_keys))
50
-
51
- return job_profile
52
-
53
-
54
- def validate_job_profile_list(job_profiles):
55
- """Validate a list of job profiles and sort by `profile_order`.
56
-
57
- Parameters
58
- ----------
59
- job_profiles : list of dict
60
- List of dictionaries representing job profiles.
61
-
62
- Returns
63
- -------
64
- job_profiles : list of dict
65
- List of dictionaries representing job profiles, sorted by
66
- `profile_order`.
67
-
68
- """
69
-
70
- # Some validation:
71
- profile_orders = []
72
- profile_names = []
73
- for i in job_profiles:
74
-
75
- # Check all profiles have a name:
76
- if i.get('profile_name') is None:
77
- msg = ('`profile_name` must be set for each job profile.')
78
- raise ValueError(msg)
79
- else:
80
- profile_names.append(i['profile_name'])
81
-
82
- if len(job_profiles) > 1:
83
- # Check all profiles have an order:
84
- if i.get('profile_order') is None:
85
- msg = ('`profile_order` must be set for each profile if there '
86
- 'are multiple job profiles, but was not specified for '
87
- 'the job profile "{}"')
88
- raise ValueError(msg.format(i['profile_name']))
89
- else:
90
- profile_orders.append(i['profile_order'])
91
-
92
- if len(job_profiles) > 1:
93
- # Check distinct profile names:
94
- if len(set(profile_names)) < len(job_profiles):
95
- msg = ('Each job profile must have a distinct `profile_name` if '
96
- 'there are multiple job profiles, but job profile names '
97
- 'are: {}')
98
- raise ValueError(msg.format(profile_names))
99
-
100
- # Check distinct profile orders:
101
- if len(set(profile_orders)) < len(job_profiles):
102
- msg = ('Each job profile must have a distinct `profile_order` if '
103
- 'there are multiple job profiles, but job profile orders '
104
- 'are: {}')
105
- raise ValueError(msg.format(profile_orders))
106
-
107
- # Sort by profile order:
108
- job_profiles = sorted(job_profiles, key=lambda x: x['profile_order'])
109
-
110
- return job_profiles
111
-
112
-
113
- def validate_task_multiplicity(cmd_groups, common_err_msg='',
114
- max_num_channels=1):
115
- """Validate an ordered list of command groups that represent (part of) a
116
- Workflow.
117
-
118
- Parameters
119
- ----------
120
- cmd_groups : list of dict
121
- List of dicts representing command groups.
122
- common_err_msg : str, optional
123
- Optional error message to prepend to any exception raised in here. By
124
- default, empty.
125
- max_num_channels : int, optional
126
- Restrict the allowed number of channels to a given number.
127
-
128
- Returns
129
- -------
130
- cmd_groups : list of dict
131
- List of dicts representing command groups.
132
-
133
- """
134
-
135
- if not common_err_msg.endswith(' '):
136
- common_err_msg += ' '
137
-
138
- exec_orders_all = [i.get('exec_order') for i in cmd_groups]
139
- exec_orders = [i for i in exec_orders_all if i is not None]
140
-
141
- if exec_orders:
142
- # Check `exec_order` starts from zero and increases by 0 or 1:
143
- uniq_exec_orders = list(set(sorted(exec_orders)))
144
- if uniq_exec_orders != list(range(len(uniq_exec_orders))):
145
- msg = common_err_msg + ('If specified, `exec_order` must start at '
146
- 'zero and increase by zero or one across '
147
- 'command groups.')
148
- raise ValueError(msg)
149
-
150
- for i in uniq_exec_orders:
151
- # Get cmd_group indices that have this `exec_order`:
152
- exec_order_idx = [idx for idx, j in enumerate(exec_orders_all)
153
- if j == i]
154
-
155
- if len(exec_order_idx) > 1:
156
-
157
- if len(exec_order_idx) > max_num_channels:
158
- # Temporarily restrict number of channels to 1:
159
- msg = ('Multiple channels are not yet implemented.')
160
- raise NotImplementedError(msg)
161
-
162
- else:
163
- # Set execution orders for command groups:
164
- for i in range(len(cmd_groups)):
165
- cmd_groups[i]['exec_order'] = i
166
-
167
- return cmd_groups