hpcflow-new2 0.2.0a189__py3-none-any.whl → 0.2.0a199__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.
- hpcflow/__pyinstaller/hook-hpcflow.py +9 -6
- hpcflow/_version.py +1 -1
- hpcflow/app.py +1 -0
- hpcflow/data/scripts/bad_script.py +2 -0
- hpcflow/data/scripts/do_nothing.py +2 -0
- hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
- hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/input_file_generator_basic.py +3 -0
- hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
- hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +1 -1
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
- hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
- hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
- hpcflow/data/scripts/output_file_parser_basic.py +3 -0
- hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
- hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/script_exit_test.py +5 -0
- hpcflow/data/template_components/environments.yaml +1 -1
- hpcflow/sdk/__init__.py +26 -15
- hpcflow/sdk/app.py +2192 -768
- hpcflow/sdk/cli.py +506 -296
- hpcflow/sdk/cli_common.py +105 -7
- hpcflow/sdk/config/__init__.py +1 -1
- hpcflow/sdk/config/callbacks.py +115 -43
- hpcflow/sdk/config/cli.py +126 -103
- hpcflow/sdk/config/config.py +674 -318
- hpcflow/sdk/config/config_file.py +131 -95
- hpcflow/sdk/config/errors.py +125 -84
- hpcflow/sdk/config/types.py +148 -0
- hpcflow/sdk/core/__init__.py +25 -1
- hpcflow/sdk/core/actions.py +1771 -1059
- hpcflow/sdk/core/app_aware.py +24 -0
- hpcflow/sdk/core/cache.py +139 -79
- hpcflow/sdk/core/command_files.py +263 -287
- hpcflow/sdk/core/commands.py +145 -112
- hpcflow/sdk/core/element.py +828 -535
- hpcflow/sdk/core/enums.py +192 -0
- hpcflow/sdk/core/environment.py +74 -93
- hpcflow/sdk/core/errors.py +455 -52
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/json_like.py +540 -272
- hpcflow/sdk/core/loop.py +751 -347
- hpcflow/sdk/core/loop_cache.py +164 -47
- hpcflow/sdk/core/object_list.py +370 -207
- hpcflow/sdk/core/parameters.py +1100 -627
- hpcflow/sdk/core/rule.py +59 -41
- hpcflow/sdk/core/run_dir_files.py +21 -37
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +1649 -1339
- hpcflow/sdk/core/task_schema.py +308 -196
- hpcflow/sdk/core/test_utils.py +191 -114
- hpcflow/sdk/core/types.py +440 -0
- hpcflow/sdk/core/utils.py +485 -309
- hpcflow/sdk/core/validation.py +82 -9
- hpcflow/sdk/core/workflow.py +2544 -1178
- hpcflow/sdk/core/zarr_io.py +98 -137
- hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
- hpcflow/sdk/demo/cli.py +53 -33
- hpcflow/sdk/helper/cli.py +18 -15
- hpcflow/sdk/helper/helper.py +75 -63
- hpcflow/sdk/helper/watcher.py +61 -28
- hpcflow/sdk/log.py +122 -71
- hpcflow/sdk/persistence/__init__.py +8 -31
- hpcflow/sdk/persistence/base.py +1360 -606
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +38 -0
- hpcflow/sdk/persistence/json.py +568 -188
- hpcflow/sdk/persistence/pending.py +382 -179
- hpcflow/sdk/persistence/store_resource.py +39 -23
- hpcflow/sdk/persistence/types.py +318 -0
- hpcflow/sdk/persistence/utils.py +14 -11
- hpcflow/sdk/persistence/zarr.py +1337 -433
- hpcflow/sdk/runtime.py +44 -41
- hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
- hpcflow/sdk/submission/jobscript.py +1651 -692
- hpcflow/sdk/submission/schedulers/__init__.py +167 -39
- hpcflow/sdk/submission/schedulers/direct.py +121 -81
- hpcflow/sdk/submission/schedulers/sge.py +170 -129
- hpcflow/sdk/submission/schedulers/slurm.py +291 -268
- hpcflow/sdk/submission/schedulers/utils.py +12 -2
- hpcflow/sdk/submission/shells/__init__.py +14 -15
- hpcflow/sdk/submission/shells/base.py +150 -29
- hpcflow/sdk/submission/shells/bash.py +283 -173
- hpcflow/sdk/submission/shells/os_version.py +31 -30
- hpcflow/sdk/submission/shells/powershell.py +228 -170
- hpcflow/sdk/submission/submission.py +1014 -335
- hpcflow/sdk/submission/types.py +140 -0
- hpcflow/sdk/typing.py +182 -12
- hpcflow/sdk/utils/arrays.py +71 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +12 -0
- hpcflow/sdk/utils/strings.py +33 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +27 -6
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +866 -85
- hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
- hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
- hpcflow/tests/shells/wsl/test_wsl_submission.py +12 -4
- hpcflow/tests/unit/test_action.py +262 -75
- hpcflow/tests/unit/test_action_rule.py +9 -4
- hpcflow/tests/unit/test_app.py +33 -6
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +134 -1
- hpcflow/tests/unit/test_command.py +71 -54
- hpcflow/tests/unit/test_config.py +142 -16
- hpcflow/tests/unit/test_config_file.py +21 -18
- hpcflow/tests/unit/test_element.py +58 -62
- hpcflow/tests/unit/test_element_iteration.py +50 -1
- hpcflow/tests/unit/test_element_set.py +29 -19
- hpcflow/tests/unit/test_group.py +4 -2
- hpcflow/tests/unit/test_input_source.py +116 -93
- hpcflow/tests/unit/test_input_value.py +29 -24
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_json_like.py +44 -35
- hpcflow/tests/unit/test_loop.py +1396 -84
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
- hpcflow/tests/unit/test_object_list.py +17 -12
- hpcflow/tests/unit/test_parameter.py +29 -7
- hpcflow/tests/unit/test_persistence.py +237 -42
- hpcflow/tests/unit/test_resources.py +20 -18
- hpcflow/tests/unit/test_run.py +117 -6
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_runtime.py +2 -1
- hpcflow/tests/unit/test_schema_input.py +23 -15
- hpcflow/tests/unit/test_shell.py +23 -2
- hpcflow/tests/unit/test_slurm.py +8 -7
- hpcflow/tests/unit/test_submission.py +38 -89
- hpcflow/tests/unit/test_task.py +352 -247
- hpcflow/tests/unit/test_task_schema.py +33 -20
- hpcflow/tests/unit/test_utils.py +9 -11
- hpcflow/tests/unit/test_value_sequence.py +15 -12
- hpcflow/tests/unit/test_workflow.py +114 -83
- hpcflow/tests/unit/test_workflow_template.py +0 -1
- hpcflow/tests/unit/utils/test_arrays.py +40 -0
- hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
- hpcflow/tests/unit/utils/test_hashing.py +65 -0
- hpcflow/tests/unit/utils/test_patches.py +5 -0
- hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
- hpcflow/tests/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +334 -1
- hpcflow/tests/workflows/test_run_status.py +198 -0
- hpcflow/tests/workflows/test_skip_downstream.py +696 -0
- hpcflow/tests/workflows/test_submission.py +140 -0
- hpcflow/tests/workflows/test_workflows.py +160 -15
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6587 -3
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/METADATA +8 -4
- hpcflow_new2-0.2.0a199.dist-info/RECORD +221 -0
- hpcflow/sdk/core/parallel.py +0 -21
- hpcflow_new2-0.2.0a189.dist-info/RECORD +0 -158
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,757 @@
|
|
1
|
+
import numpy as np
|
2
|
+
from hpcflow.app import app as hf
|
3
|
+
from hpcflow.sdk.core.test_utils import make_schemas, make_workflow
|
4
|
+
from hpcflow.sdk.submission.jobscript import is_jobscript_array, resolve_jobscript_blocks
|
5
|
+
|
6
|
+
import pytest
|
7
|
+
|
8
|
+
|
9
|
+
def test_resolve_jobscript_blocks():
|
10
|
+
# separate jobscripts due to `is_array`:
|
11
|
+
jobscripts = {
|
12
|
+
0: {"is_array": True, "resource_hash": 0, "dependencies": {}},
|
13
|
+
1: {"is_array": True, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
14
|
+
}
|
15
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
16
|
+
{"resources": None, "is_array": True, "blocks": [{"dependencies": {}}]},
|
17
|
+
{
|
18
|
+
"resources": None,
|
19
|
+
"is_array": True,
|
20
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA"}}],
|
21
|
+
},
|
22
|
+
]
|
23
|
+
|
24
|
+
# separate jobscripts due to different `resource_hash`:
|
25
|
+
jobscripts = {
|
26
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
27
|
+
1: {"is_array": False, "resource_hash": 1, "dependencies": {0: "DEP_DATA"}},
|
28
|
+
}
|
29
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
30
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
31
|
+
{
|
32
|
+
"resources": None,
|
33
|
+
"is_array": False,
|
34
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA"}}],
|
35
|
+
},
|
36
|
+
]
|
37
|
+
|
38
|
+
# separate jobscripts due to `is_array`:
|
39
|
+
jobscripts = {
|
40
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
41
|
+
1: {"is_array": True, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
42
|
+
}
|
43
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
44
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
45
|
+
{
|
46
|
+
"resources": None,
|
47
|
+
"is_array": True,
|
48
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA"}}],
|
49
|
+
},
|
50
|
+
]
|
51
|
+
|
52
|
+
# separate jobscripts due to `is_array`:
|
53
|
+
jobscripts = {
|
54
|
+
0: {"is_array": True, "resource_hash": 0, "dependencies": {}},
|
55
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
56
|
+
}
|
57
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
58
|
+
{"resources": None, "is_array": True, "blocks": [{"dependencies": {}}]},
|
59
|
+
{
|
60
|
+
"resources": None,
|
61
|
+
"is_array": False,
|
62
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA"}}],
|
63
|
+
},
|
64
|
+
]
|
65
|
+
|
66
|
+
# combined jobscript due to same resource_hash, not is_array, and dependencies:
|
67
|
+
jobscripts = {
|
68
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
69
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
70
|
+
2: {"is_array": False, "resource_hash": 0, "dependencies": {1: "DEP_DATA"}},
|
71
|
+
}
|
72
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
73
|
+
{
|
74
|
+
"resources": None,
|
75
|
+
"is_array": False,
|
76
|
+
"blocks": [
|
77
|
+
{"dependencies": {}},
|
78
|
+
{"dependencies": {(0, 0): "DEP_DATA"}},
|
79
|
+
{"dependencies": {(0, 1): "DEP_DATA"}},
|
80
|
+
],
|
81
|
+
}
|
82
|
+
]
|
83
|
+
|
84
|
+
# combined jobscript due to same resource_hash, not is_array, and dependencies:
|
85
|
+
# (checking non-consecutive jobscript index `3` is inconsequential)
|
86
|
+
jobscripts = {
|
87
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
88
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
89
|
+
3: {"is_array": False, "resource_hash": 0, "dependencies": {1: "DEP_DATA"}},
|
90
|
+
}
|
91
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
92
|
+
{
|
93
|
+
"resources": None,
|
94
|
+
"is_array": False,
|
95
|
+
"blocks": [
|
96
|
+
{"dependencies": {}},
|
97
|
+
{"dependencies": {(0, 0): "DEP_DATA"}},
|
98
|
+
{"dependencies": {(0, 1): "DEP_DATA"}},
|
99
|
+
],
|
100
|
+
}
|
101
|
+
]
|
102
|
+
|
103
|
+
# jobscript 0 and 1 combined, not 2 due to independence:
|
104
|
+
jobscripts = {
|
105
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
106
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
107
|
+
2: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
108
|
+
}
|
109
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
110
|
+
{
|
111
|
+
"resources": None,
|
112
|
+
"is_array": False,
|
113
|
+
"blocks": [{"dependencies": {}}, {"dependencies": {(0, 0): "DEP_DATA"}}],
|
114
|
+
},
|
115
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
116
|
+
]
|
117
|
+
|
118
|
+
# separate jobscripts 0,1 due to independence, separate jobscript 2 due to dependence
|
119
|
+
# that spans multiple upstream jobscripts that are independent:
|
120
|
+
jobscripts = {
|
121
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
122
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
123
|
+
2: {
|
124
|
+
"is_array": False,
|
125
|
+
"resource_hash": 0,
|
126
|
+
"dependencies": {0: "DEP_DATA", 1: "DEP_DATA"},
|
127
|
+
},
|
128
|
+
}
|
129
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
130
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
131
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
132
|
+
{
|
133
|
+
"resources": None,
|
134
|
+
"is_array": False,
|
135
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA", (1, 0): "DEP_DATA"}}],
|
136
|
+
},
|
137
|
+
]
|
138
|
+
|
139
|
+
# combine jobscripts due to dependence
|
140
|
+
jobscripts = {
|
141
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
142
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {0: "DEP_DATA"}},
|
143
|
+
2: {
|
144
|
+
"is_array": False,
|
145
|
+
"resource_hash": 0,
|
146
|
+
"dependencies": {0: "DEP_DATA", 1: "DEP_DATA"},
|
147
|
+
},
|
148
|
+
}
|
149
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
150
|
+
{
|
151
|
+
"resources": None,
|
152
|
+
"is_array": False,
|
153
|
+
"blocks": [
|
154
|
+
{"dependencies": {}},
|
155
|
+
{"dependencies": {(0, 0): "DEP_DATA"}},
|
156
|
+
{"dependencies": {(0, 0): "DEP_DATA", (0, 1): "DEP_DATA"}},
|
157
|
+
],
|
158
|
+
}
|
159
|
+
]
|
160
|
+
|
161
|
+
# separate jobscripts 0,1 due to independence, combined jobscripts 3,4 due to shared
|
162
|
+
# dependencies:
|
163
|
+
jobscripts = {
|
164
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
165
|
+
1: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
166
|
+
2: {
|
167
|
+
"is_array": False,
|
168
|
+
"resource_hash": 0,
|
169
|
+
"dependencies": {0: "DEP_DATA", 1: "DEP_DATA"},
|
170
|
+
},
|
171
|
+
3: {
|
172
|
+
"is_array": False,
|
173
|
+
"resource_hash": 0,
|
174
|
+
"dependencies": {0: "DEP_DATA", 1: "DEP_DATA", 2: "DEP_DATA"},
|
175
|
+
},
|
176
|
+
}
|
177
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
178
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
179
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
180
|
+
{
|
181
|
+
"resources": None,
|
182
|
+
"is_array": False,
|
183
|
+
"blocks": [
|
184
|
+
{"dependencies": {(0, 0): "DEP_DATA", (1, 0): "DEP_DATA"}},
|
185
|
+
{
|
186
|
+
"dependencies": {
|
187
|
+
(0, 0): "DEP_DATA",
|
188
|
+
(1, 0): "DEP_DATA",
|
189
|
+
(2, 0): "DEP_DATA",
|
190
|
+
}
|
191
|
+
},
|
192
|
+
],
|
193
|
+
},
|
194
|
+
]
|
195
|
+
|
196
|
+
# seperate jobscripts 0,1,2 due to resource hashes, combined 2,3 due to shared
|
197
|
+
# upstream dependencies:
|
198
|
+
jobscripts = {
|
199
|
+
0: {"is_array": False, "resource_hash": 0, "dependencies": {}},
|
200
|
+
1: {"is_array": False, "resource_hash": 1, "dependencies": {0: "DEP_DATA"}},
|
201
|
+
2: {"is_array": False, "resource_hash": 0, "dependencies": {1: "DEP_DATA"}},
|
202
|
+
3: {
|
203
|
+
"is_array": False,
|
204
|
+
"resource_hash": 0,
|
205
|
+
"dependencies": {0: "DEP_DATA", 2: "DEP_DATA"},
|
206
|
+
},
|
207
|
+
}
|
208
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
209
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
210
|
+
{
|
211
|
+
"resources": None,
|
212
|
+
"is_array": False,
|
213
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA"}}],
|
214
|
+
},
|
215
|
+
{
|
216
|
+
"resources": None,
|
217
|
+
"is_array": False,
|
218
|
+
"blocks": [
|
219
|
+
{"dependencies": {(1, 0): "DEP_DATA"}},
|
220
|
+
{"dependencies": {(0, 0): "DEP_DATA", (2, 0): "DEP_DATA"}},
|
221
|
+
],
|
222
|
+
},
|
223
|
+
]
|
224
|
+
|
225
|
+
# test non-consecutive jobscript indices (i.e. 0,1 merged across tasks in previous
|
226
|
+
# step); separate jobscripts 0,2,3 due to resource hashes, combined 3,4 due to shared
|
227
|
+
# upstream dependencies:
|
228
|
+
jobscripts = {
|
229
|
+
0: {"resource_hash": 0, "dependencies": {}, "is_array": False},
|
230
|
+
2: {
|
231
|
+
"resource_hash": 1,
|
232
|
+
"dependencies": {0: "DEP_DATA"},
|
233
|
+
"is_array": False,
|
234
|
+
},
|
235
|
+
3: {
|
236
|
+
"resource_hash": 0,
|
237
|
+
"dependencies": {0: "DEP_DATA", 2: "DEP_DATA"},
|
238
|
+
"is_array": False,
|
239
|
+
},
|
240
|
+
4: {
|
241
|
+
"resource_hash": 0,
|
242
|
+
"dependencies": {0: "DEP_DATA", 3: "DEP_DATA"},
|
243
|
+
"is_array": False,
|
244
|
+
},
|
245
|
+
}
|
246
|
+
assert resolve_jobscript_blocks(jobscripts) == [
|
247
|
+
{"resources": None, "is_array": False, "blocks": [{"dependencies": {}}]},
|
248
|
+
{
|
249
|
+
"resources": None,
|
250
|
+
"is_array": False,
|
251
|
+
"blocks": [{"dependencies": {(0, 0): "DEP_DATA"}}],
|
252
|
+
},
|
253
|
+
{
|
254
|
+
"resources": None,
|
255
|
+
"is_array": False,
|
256
|
+
"blocks": [
|
257
|
+
{"dependencies": {(0, 0): "DEP_DATA", (1, 0): "DEP_DATA"}},
|
258
|
+
{"dependencies": {(0, 0): "DEP_DATA", (2, 0): "DEP_DATA"}},
|
259
|
+
],
|
260
|
+
},
|
261
|
+
]
|
262
|
+
|
263
|
+
|
264
|
+
def test_is_job_array_raises_on_bad_scheduler():
|
265
|
+
resources = hf.ElementResources(use_job_array=True)
|
266
|
+
resources.set_defaults()
|
267
|
+
with pytest.raises(ValueError):
|
268
|
+
is_jobscript_array(resources=resources, num_elements=2, store=None)
|
269
|
+
|
270
|
+
|
271
|
+
def test_force_array(null_config, tmp_path):
|
272
|
+
wk = make_workflow(
|
273
|
+
[[{"p1": None}, ("p2",), "t1"]],
|
274
|
+
path=tmp_path,
|
275
|
+
local_sequences={0: [("inputs.p1", 2, 0)]},
|
276
|
+
name="w1",
|
277
|
+
overwrite=False,
|
278
|
+
)
|
279
|
+
sub = wk.add_submission(force_array=True)
|
280
|
+
assert len(sub.jobscripts) == 1
|
281
|
+
assert sub.jobscripts[0].is_array
|
282
|
+
|
283
|
+
|
284
|
+
def test_merge_jobscript_multi_dependence(null_config, tmp_path):
|
285
|
+
s1, s2, s3 = make_schemas(
|
286
|
+
({}, ("p1", "p2"), "t1"),
|
287
|
+
(
|
288
|
+
{
|
289
|
+
"p1": None,
|
290
|
+
},
|
291
|
+
("p3",),
|
292
|
+
"t2",
|
293
|
+
),
|
294
|
+
({"p1": None, "p3": None}, tuple(), "t3"),
|
295
|
+
)
|
296
|
+
wk = hf.Workflow.from_template_data(
|
297
|
+
template_name="test_merge_js",
|
298
|
+
workflow_name="test_merge_js",
|
299
|
+
overwrite=True,
|
300
|
+
path=tmp_path,
|
301
|
+
tasks=[
|
302
|
+
hf.Task(schema=s1, repeats=2),
|
303
|
+
hf.Task(schema=s2),
|
304
|
+
hf.Task(schema=s3),
|
305
|
+
],
|
306
|
+
)
|
307
|
+
sub = wk.add_submission()
|
308
|
+
assert len(sub.jobscripts) == 1
|
309
|
+
assert len(sub.jobscripts[0].blocks) == 1
|
310
|
+
|
311
|
+
|
312
|
+
def test_merge_jobscript_multi_dependence_non_array_source(null_config, tmp_path):
|
313
|
+
# the second two jobscripts should merge
|
314
|
+
s1, s2, s3 = make_schemas(
|
315
|
+
({}, ("p1", "p2"), "t1"),
|
316
|
+
(
|
317
|
+
{
|
318
|
+
"p1": None,
|
319
|
+
},
|
320
|
+
("p3",),
|
321
|
+
"t2",
|
322
|
+
),
|
323
|
+
({"p1": None, "p3": None}, tuple(), "t3"),
|
324
|
+
)
|
325
|
+
wk = hf.Workflow.from_template_data(
|
326
|
+
template_name="wk_test_merge",
|
327
|
+
path=tmp_path,
|
328
|
+
tasks=[
|
329
|
+
hf.Task(schema=s1),
|
330
|
+
hf.Task(schema=s2, repeats=2),
|
331
|
+
hf.Task(schema=s3),
|
332
|
+
],
|
333
|
+
)
|
334
|
+
sub = wk.add_submission(force_array=True)
|
335
|
+
|
336
|
+
assert len(sub.jobscripts) == 2
|
337
|
+
assert len(sub.jobscripts[0].blocks) == 1
|
338
|
+
assert len(sub.jobscripts[1].blocks) == 1
|
339
|
+
|
340
|
+
|
341
|
+
def test_multi_block_jobscript_multi_dependence(null_config, tmp_path):
|
342
|
+
|
343
|
+
s1, s2, s3, s4 = make_schemas(
|
344
|
+
({"p1": None}, ("p2", "p3"), "t1"),
|
345
|
+
({"p2": None}, ("p4",), "t2"),
|
346
|
+
({"p4": None}, ("p5",), "t3"),
|
347
|
+
({"p3": None, "p5": None}, (), "t4"),
|
348
|
+
)
|
349
|
+
tasks = [
|
350
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
351
|
+
hf.Task(schema=s2),
|
352
|
+
hf.Task(schema=s3),
|
353
|
+
hf.Task(schema=s4),
|
354
|
+
]
|
355
|
+
wk = hf.Workflow.from_template_data(
|
356
|
+
template_name="test_js_blocks",
|
357
|
+
workflow_name="test_js_blocks",
|
358
|
+
tasks=tasks,
|
359
|
+
path=tmp_path,
|
360
|
+
)
|
361
|
+
sub = wk.add_submission()
|
362
|
+
assert len(sub.jobscripts) == 1
|
363
|
+
assert len(sub.jobscripts[0].blocks) == 1
|
364
|
+
|
365
|
+
|
366
|
+
def test_multi_block_jobscript_multi_dependence_distinct_resources(null_config, tmp_path):
|
367
|
+
|
368
|
+
s1, s2, s3, s4 = make_schemas(
|
369
|
+
({"p1": None}, ("p2", "p3"), "t1"),
|
370
|
+
({"p2": None}, ("p4",), "t2"),
|
371
|
+
({"p4": None}, ("p5",), "t3"),
|
372
|
+
({"p3": None, "p5": None}, (), "t4"),
|
373
|
+
)
|
374
|
+
tasks = [
|
375
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
376
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
377
|
+
hf.Task(schema=s3),
|
378
|
+
hf.Task(schema=s4),
|
379
|
+
]
|
380
|
+
wk = hf.Workflow.from_template_data(
|
381
|
+
template_name="test_js_blocks",
|
382
|
+
workflow_name="test_js_blocks",
|
383
|
+
tasks=tasks,
|
384
|
+
path=tmp_path,
|
385
|
+
)
|
386
|
+
sub = wk.add_submission()
|
387
|
+
assert len(sub.jobscripts) == 3
|
388
|
+
assert len(sub.jobscripts[0].blocks) == 1
|
389
|
+
assert len(sub.jobscripts[1].blocks) == 1
|
390
|
+
assert len(sub.jobscripts[2].blocks) == 2
|
391
|
+
|
392
|
+
|
393
|
+
def test_multi_block_jobscript_multi_dependence_distinct_resources_sequence_and_group(
|
394
|
+
null_config, tmp_path
|
395
|
+
):
|
396
|
+
|
397
|
+
s1, s2, s3 = make_schemas(
|
398
|
+
({"p1": None}, ("p2",), "t1"),
|
399
|
+
({"p2": None}, ("p4",), "t2"),
|
400
|
+
({"p4": None}, ("p5",), "t3"),
|
401
|
+
)
|
402
|
+
s4 = hf.TaskSchema(
|
403
|
+
objective="t4",
|
404
|
+
inputs=[hf.SchemaInput("p2", group="g1"), hf.SchemaInput("p5", group="g1")],
|
405
|
+
actions=[
|
406
|
+
hf.Action(
|
407
|
+
commands=[
|
408
|
+
hf.Command("echo $((<<sum(parameter:p2)>> + <<sum(parameter:p5)>>))")
|
409
|
+
]
|
410
|
+
)
|
411
|
+
],
|
412
|
+
)
|
413
|
+
tasks = [
|
414
|
+
hf.Task(
|
415
|
+
schema=s1,
|
416
|
+
sequences=[hf.ValueSequence(path="inputs.p1", values=[1, 2])],
|
417
|
+
groups=[hf.ElementGroup(name="g1")],
|
418
|
+
),
|
419
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
420
|
+
hf.Task(schema=s3, groups=[hf.ElementGroup(name="g1")]),
|
421
|
+
hf.Task(schema=s4),
|
422
|
+
]
|
423
|
+
wk = hf.Workflow.from_template_data(
|
424
|
+
template_name="test_js_blocks",
|
425
|
+
workflow_name="test_js_blocks",
|
426
|
+
tasks=tasks,
|
427
|
+
overwrite=True,
|
428
|
+
path=tmp_path,
|
429
|
+
)
|
430
|
+
sub = wk.add_submission()
|
431
|
+
assert len(sub.jobscripts) == 3
|
432
|
+
assert len(sub.jobscripts[0].blocks) == 1
|
433
|
+
assert len(sub.jobscripts[1].blocks) == 1
|
434
|
+
assert len(sub.jobscripts[2].blocks) == 2
|
435
|
+
|
436
|
+
|
437
|
+
def test_combine_scripts_unset_False_jobscript_hash_equivalence(null_config, tmp_path):
|
438
|
+
|
439
|
+
s1 = hf.TaskSchema(
|
440
|
+
objective="t1",
|
441
|
+
actions=[
|
442
|
+
hf.Action(
|
443
|
+
script="<<script:main_script_test_direct_in.py>>",
|
444
|
+
script_data_in="direct",
|
445
|
+
script_data_out="direct",
|
446
|
+
script_exe="python_script",
|
447
|
+
environments=[hf.ActionEnvironment(environment="python_env")],
|
448
|
+
),
|
449
|
+
hf.Action(commands=[hf.Command(command='echo "hello!"')]),
|
450
|
+
],
|
451
|
+
)
|
452
|
+
t1 = hf.Task(schema=s1)
|
453
|
+
wk = hf.Workflow.from_template_data(
|
454
|
+
tasks=[t1],
|
455
|
+
resources={
|
456
|
+
"any": {
|
457
|
+
"combine_scripts": False, # only applies to the Python script action
|
458
|
+
},
|
459
|
+
},
|
460
|
+
template_name="combine_scripts_test",
|
461
|
+
path=tmp_path,
|
462
|
+
)
|
463
|
+
sub = wk.add_submission()
|
464
|
+
|
465
|
+
# test that even though `combine_scripts` is not set on second action (because it is
|
466
|
+
# not a Python script action), the resources have an equivalent hash and thus only one
|
467
|
+
# jobscript is generated:
|
468
|
+
|
469
|
+
iter_1 = wk.tasks.t1.elements[0].iterations[0]
|
470
|
+
act_1 = iter_1.action_runs[0].action
|
471
|
+
act_2 = iter_1.action_runs[1].action
|
472
|
+
|
473
|
+
res_1 = iter_1.get_resources_obj(act_1)
|
474
|
+
res_2 = iter_1.get_resources_obj(act_2)
|
475
|
+
|
476
|
+
# set to False on first action:
|
477
|
+
assert iter_1.get_resources_obj(act_1).combine_scripts == False
|
478
|
+
|
479
|
+
# not set on second action:
|
480
|
+
assert iter_1.get_resources_obj(act_2).combine_scripts == None
|
481
|
+
|
482
|
+
# hashes equivalent:
|
483
|
+
assert res_1.get_jobscript_hash() == res_2.get_jobscript_hash()
|
484
|
+
|
485
|
+
assert len(sub.jobscripts) == 1
|
486
|
+
|
487
|
+
|
488
|
+
def test_JS_parallelism_default_zarr(null_config, tmp_path):
|
489
|
+
t1 = hf.Task(
|
490
|
+
schema=hf.task_schemas.test_t1_conditional_OS,
|
491
|
+
inputs={"p1": 100},
|
492
|
+
)
|
493
|
+
wk = hf.Workflow.from_template_data(
|
494
|
+
template_name="test_JS_parallelism_default_set_zarr",
|
495
|
+
path=tmp_path,
|
496
|
+
tasks=[t1],
|
497
|
+
store="zarr",
|
498
|
+
)
|
499
|
+
|
500
|
+
wk.add_submission() # do not set JS_parallelism
|
501
|
+
|
502
|
+
# zarr supports JS parallelism, so by default should be set to "scheduled":
|
503
|
+
assert wk.submissions[0].JS_parallelism == "scheduled"
|
504
|
+
|
505
|
+
|
506
|
+
def test_JS_parallelism_default_json(null_config, tmp_path):
|
507
|
+
t1 = hf.Task(
|
508
|
+
schema=hf.task_schemas.test_t1_conditional_OS,
|
509
|
+
inputs={"p1": 100},
|
510
|
+
)
|
511
|
+
wk = hf.Workflow.from_template_data(
|
512
|
+
template_name="test_JS_parallelism_default_set_json",
|
513
|
+
path=tmp_path,
|
514
|
+
tasks=[t1],
|
515
|
+
store="json",
|
516
|
+
)
|
517
|
+
|
518
|
+
wk.add_submission() # do not set JS_parallelism
|
519
|
+
|
520
|
+
# json does not support JS parallelism, so by default should be set to False:
|
521
|
+
assert wk.submissions[0].JS_parallelism is False
|
522
|
+
|
523
|
+
|
524
|
+
def test_jobscript_block_run_IDs_equivalence_JSON_Zarr(null_config, tmp_path):
|
525
|
+
"""The zarr store keeps jobscript-block run IDs in separate arrays, so test
|
526
|
+
equivalence."""
|
527
|
+
|
528
|
+
s1, s2, s3, s4 = make_schemas(
|
529
|
+
({"p1": None}, ("p2", "p3"), "t1"),
|
530
|
+
({"p2": None}, ("p4",), "t2"),
|
531
|
+
({"p4": None}, ("p5",), "t3"),
|
532
|
+
({"p3": None, "p5": None}, (), "t4"),
|
533
|
+
)
|
534
|
+
tasks_zarr = [
|
535
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
536
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
537
|
+
hf.Task(schema=s3),
|
538
|
+
hf.Task(schema=s4),
|
539
|
+
]
|
540
|
+
wk_zarr = hf.Workflow.from_template_data(
|
541
|
+
template_name="test_js_blocks_zarr",
|
542
|
+
tasks=tasks_zarr,
|
543
|
+
path=tmp_path,
|
544
|
+
store="zarr",
|
545
|
+
)
|
546
|
+
sub_zarr = wk_zarr.add_submission()
|
547
|
+
|
548
|
+
tasks_json = [
|
549
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
550
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
551
|
+
hf.Task(schema=s3),
|
552
|
+
hf.Task(schema=s4),
|
553
|
+
]
|
554
|
+
wk_json = hf.Workflow.from_template_data(
|
555
|
+
template_name="test_js_blocks_json",
|
556
|
+
tasks=tasks_json,
|
557
|
+
path=tmp_path,
|
558
|
+
store="json",
|
559
|
+
)
|
560
|
+
sub_json = wk_json.add_submission()
|
561
|
+
|
562
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
563
|
+
|
564
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
565
|
+
js_json = sub_json.jobscripts[js_idx]
|
566
|
+
assert np.array_equal(js_zarr.all_EAR_IDs, js_json.all_EAR_IDs)
|
567
|
+
|
568
|
+
# reload both workflows from disk, and check again, since above will check data from
|
569
|
+
# in-memory modified Submission object
|
570
|
+
sub_json = wk_json.reload().submissions[0]
|
571
|
+
sub_zarr = wk_zarr.reload().submissions[0]
|
572
|
+
|
573
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
574
|
+
|
575
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
576
|
+
js_json = sub_json.jobscripts[js_idx]
|
577
|
+
assert np.array_equal(js_zarr.all_EAR_IDs, js_json.all_EAR_IDs)
|
578
|
+
|
579
|
+
|
580
|
+
def test_jobscript_task_element_maps_equivalence_JSON_Zarr(null_config, tmp_path):
|
581
|
+
"""The zarr store keeps jobscript-block task-element maps in separate arrays, so test
|
582
|
+
equivalence."""
|
583
|
+
|
584
|
+
s1, s2, s3, s4 = make_schemas(
|
585
|
+
({"p1": None}, ("p2", "p3"), "t1"),
|
586
|
+
({"p2": None}, ("p4",), "t2"),
|
587
|
+
({"p4": None}, ("p5",), "t3"),
|
588
|
+
({"p3": None, "p5": None}, (), "t4"),
|
589
|
+
)
|
590
|
+
tasks_zarr = [
|
591
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
592
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
593
|
+
hf.Task(schema=s3),
|
594
|
+
hf.Task(schema=s4),
|
595
|
+
]
|
596
|
+
wk_zarr = hf.Workflow.from_template_data(
|
597
|
+
template_name="test_js_blocks_zarr",
|
598
|
+
tasks=tasks_zarr,
|
599
|
+
path=tmp_path,
|
600
|
+
store="zarr",
|
601
|
+
)
|
602
|
+
sub_zarr = wk_zarr.add_submission()
|
603
|
+
|
604
|
+
tasks_json = [
|
605
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
606
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
607
|
+
hf.Task(schema=s3),
|
608
|
+
hf.Task(schema=s4),
|
609
|
+
]
|
610
|
+
wk_json = hf.Workflow.from_template_data(
|
611
|
+
template_name="test_js_blocks_json",
|
612
|
+
tasks=tasks_json,
|
613
|
+
path=tmp_path,
|
614
|
+
store="json",
|
615
|
+
)
|
616
|
+
sub_json = wk_json.add_submission()
|
617
|
+
|
618
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
619
|
+
|
620
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
621
|
+
assert len(js_zarr.blocks) == len(sub_json.jobscripts[js_idx].blocks)
|
622
|
+
for blk_idx, js_blk_zarr in enumerate(js_zarr.blocks):
|
623
|
+
js_blk_json = sub_json.jobscripts[js_idx].blocks[blk_idx]
|
624
|
+
assert js_blk_zarr.task_elements == js_blk_json.task_elements
|
625
|
+
|
626
|
+
# reload both workflows from disk, and check again, since above will check data from
|
627
|
+
# in-memory modified Submission object
|
628
|
+
sub_json = wk_json.reload().submissions[0]
|
629
|
+
sub_zarr = wk_zarr.reload().submissions[0]
|
630
|
+
|
631
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
632
|
+
|
633
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
634
|
+
assert len(js_zarr.blocks) == len(sub_json.jobscripts[js_idx].blocks)
|
635
|
+
for blk_idx, js_blk_zarr in enumerate(js_zarr.blocks):
|
636
|
+
js_blk_json = sub_json.jobscripts[js_idx].blocks[blk_idx]
|
637
|
+
assert js_blk_zarr.task_elements == js_blk_json.task_elements
|
638
|
+
|
639
|
+
|
640
|
+
def test_jobscript_task_actions_equivalence_JSON_Zarr(null_config, tmp_path):
|
641
|
+
"""The zarr store keeps jobscript-block task-actions in separate arrays, so test
|
642
|
+
equivalence."""
|
643
|
+
|
644
|
+
s1, s2, s3, s4 = make_schemas(
|
645
|
+
({"p1": None}, ("p2", "p3"), "t1"),
|
646
|
+
({"p2": None}, ("p4",), "t2"),
|
647
|
+
({"p4": None}, ("p5",), "t3"),
|
648
|
+
({"p3": None, "p5": None}, (), "t4"),
|
649
|
+
)
|
650
|
+
tasks_zarr = [
|
651
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
652
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
653
|
+
hf.Task(schema=s3),
|
654
|
+
hf.Task(schema=s4),
|
655
|
+
]
|
656
|
+
wk_zarr = hf.Workflow.from_template_data(
|
657
|
+
template_name="test_js_blocks_zarr",
|
658
|
+
tasks=tasks_zarr,
|
659
|
+
path=tmp_path,
|
660
|
+
store="zarr",
|
661
|
+
)
|
662
|
+
sub_zarr = wk_zarr.add_submission()
|
663
|
+
|
664
|
+
tasks_json = [
|
665
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
666
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
667
|
+
hf.Task(schema=s3),
|
668
|
+
hf.Task(schema=s4),
|
669
|
+
]
|
670
|
+
wk_json = hf.Workflow.from_template_data(
|
671
|
+
template_name="test_js_blocks_json",
|
672
|
+
tasks=tasks_json,
|
673
|
+
path=tmp_path,
|
674
|
+
store="json",
|
675
|
+
)
|
676
|
+
sub_json = wk_json.add_submission()
|
677
|
+
|
678
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
679
|
+
|
680
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
681
|
+
assert len(js_zarr.blocks) == len(sub_json.jobscripts[js_idx].blocks)
|
682
|
+
for blk_idx, js_blk_zarr in enumerate(js_zarr.blocks):
|
683
|
+
js_blk_json = sub_json.jobscripts[js_idx].blocks[blk_idx]
|
684
|
+
assert np.array_equal(js_blk_zarr.task_actions, js_blk_json.task_actions)
|
685
|
+
|
686
|
+
# reload both workflows from disk, and check again, since above will check data from
|
687
|
+
# in-memory modified Submission object
|
688
|
+
sub_json = wk_json.reload().submissions[0]
|
689
|
+
sub_zarr = wk_zarr.reload().submissions[0]
|
690
|
+
|
691
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
692
|
+
|
693
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
694
|
+
assert len(js_zarr.blocks) == len(sub_json.jobscripts[js_idx].blocks)
|
695
|
+
for blk_idx, js_blk_zarr in enumerate(js_zarr.blocks):
|
696
|
+
js_blk_json = sub_json.jobscripts[js_idx].blocks[blk_idx]
|
697
|
+
assert np.array_equal(js_blk_zarr.task_actions, js_blk_json.task_actions)
|
698
|
+
|
699
|
+
|
700
|
+
def test_jobscript_dependencies_equivalence_JSON_Zarr(null_config, tmp_path):
|
701
|
+
"""The zarr store keeps jobscript-block dependencies in separate arrays, so test
|
702
|
+
equivalence."""
|
703
|
+
|
704
|
+
s1, s2, s3, s4 = make_schemas(
|
705
|
+
({"p1": None}, ("p2", "p3"), "t1"),
|
706
|
+
({"p2": None}, ("p4",), "t2"),
|
707
|
+
({"p4": None}, ("p5",), "t3"),
|
708
|
+
({"p3": None, "p5": None}, (), "t4"),
|
709
|
+
)
|
710
|
+
tasks_zarr = [
|
711
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
712
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
713
|
+
hf.Task(schema=s3),
|
714
|
+
hf.Task(schema=s4),
|
715
|
+
]
|
716
|
+
wk_zarr = hf.Workflow.from_template_data(
|
717
|
+
template_name="test_js_blocks_zarr",
|
718
|
+
tasks=tasks_zarr,
|
719
|
+
path=tmp_path,
|
720
|
+
store="zarr",
|
721
|
+
)
|
722
|
+
sub_zarr = wk_zarr.add_submission()
|
723
|
+
|
724
|
+
tasks_json = [
|
725
|
+
hf.Task(schema=s1, inputs={"p1": 101}),
|
726
|
+
hf.Task(schema=s2, resources={"any": {"num_cores": 2}}),
|
727
|
+
hf.Task(schema=s3),
|
728
|
+
hf.Task(schema=s4),
|
729
|
+
]
|
730
|
+
wk_json = hf.Workflow.from_template_data(
|
731
|
+
template_name="test_js_blocks_json",
|
732
|
+
tasks=tasks_json,
|
733
|
+
path=tmp_path,
|
734
|
+
store="json",
|
735
|
+
)
|
736
|
+
sub_json = wk_json.add_submission()
|
737
|
+
|
738
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
739
|
+
|
740
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
741
|
+
assert len(js_zarr.blocks) == len(sub_json.jobscripts[js_idx].blocks)
|
742
|
+
for blk_idx, js_blk_zarr in enumerate(js_zarr.blocks):
|
743
|
+
js_blk_json = sub_json.jobscripts[js_idx].blocks[blk_idx]
|
744
|
+
assert js_blk_zarr.dependencies == js_blk_json.dependencies
|
745
|
+
|
746
|
+
# reload both workflows from disk, and check again, since above will check data from
|
747
|
+
# in-memory modified Submission object
|
748
|
+
sub_json = wk_json.reload().submissions[0]
|
749
|
+
sub_zarr = wk_zarr.reload().submissions[0]
|
750
|
+
|
751
|
+
assert len(sub_zarr.jobscripts) == len(sub_json.jobscripts)
|
752
|
+
|
753
|
+
for js_idx, js_zarr in enumerate(sub_zarr.jobscripts):
|
754
|
+
assert len(js_zarr.blocks) == len(sub_json.jobscripts[js_idx].blocks)
|
755
|
+
for blk_idx, js_blk_zarr in enumerate(js_zarr.blocks):
|
756
|
+
js_blk_json = sub_json.jobscripts[js_idx].blocks[blk_idx]
|
757
|
+
assert js_blk_zarr.dependencies == js_blk_json.dependencies
|