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
hpcflow/sdk/config/errors.py
CHANGED
@@ -2,12 +2,20 @@
|
|
2
2
|
Miscellaneous configuration-related errors.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from __future__ import annotations
|
6
|
+
from typing import Any, TYPE_CHECKING
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from collections.abc import Sequence, Iterable
|
10
|
+
from .types import ConfigMetadata
|
11
|
+
from ..typing import PathLike
|
9
12
|
|
10
|
-
|
13
|
+
|
14
|
+
class ConfigError(Exception):
|
15
|
+
"""
|
16
|
+
Raised when a valid configuration can not be associated with the current
|
17
|
+
invocation.
|
18
|
+
"""
|
11
19
|
|
12
20
|
|
13
21
|
class ConfigUnknownItemError(ConfigError):
|
@@ -15,12 +23,14 @@ class ConfigUnknownItemError(ConfigError):
|
|
15
23
|
Raised when the configuration contains an unknown item.
|
16
24
|
"""
|
17
25
|
|
18
|
-
def __init__(self, name, message=
|
19
|
-
|
20
|
-
|
21
|
-
|
26
|
+
def __init__(self, name: str, message: str = ""):
|
27
|
+
super().__init__(
|
28
|
+
message
|
29
|
+
or (
|
30
|
+
f"Specified name {name!r} is not a valid meta-data or configurable "
|
31
|
+
f"configuration item."
|
32
|
+
)
|
22
33
|
)
|
23
|
-
super().__init__(self.message)
|
24
34
|
|
25
35
|
|
26
36
|
class ConfigUnknownOverrideError(ConfigError):
|
@@ -28,11 +38,13 @@ class ConfigUnknownOverrideError(ConfigError):
|
|
28
38
|
Raised when the configuration override contains an unknown item.
|
29
39
|
"""
|
30
40
|
|
31
|
-
def __init__(self, name, message=
|
32
|
-
|
33
|
-
|
41
|
+
def __init__(self, name: str, message: str = ""):
|
42
|
+
super().__init__(
|
43
|
+
message
|
44
|
+
or (
|
45
|
+
f"Specified configuration override {name!r} is not a valid configurable item."
|
46
|
+
)
|
34
47
|
)
|
35
|
-
super().__init__(self.message)
|
36
48
|
|
37
49
|
|
38
50
|
class ConfigNonConfigurableError(ConfigError):
|
@@ -40,8 +52,14 @@ class ConfigNonConfigurableError(ConfigError):
|
|
40
52
|
Raised when the configuration contains an item that can't be configured.
|
41
53
|
"""
|
42
54
|
|
43
|
-
def __init__(self, name, message=None):
|
44
|
-
|
55
|
+
def __init__(self, name: str | Iterable[str], message: str | None = None):
|
56
|
+
if not message:
|
57
|
+
if not isinstance(name, str):
|
58
|
+
names_str = ", ".join(f"{i!r}" for i in name)
|
59
|
+
msg = f"Specified names {names_str} are not configurable items."
|
60
|
+
else:
|
61
|
+
msg = f"Specified name {name!r} is not a configurable item."
|
62
|
+
self.message = message or msg
|
45
63
|
super().__init__(self.message)
|
46
64
|
|
47
65
|
|
@@ -50,9 +68,8 @@ class ConfigItemAlreadyUnsetError(ConfigError):
|
|
50
68
|
Raised when the configuration tries to unset an unset item.
|
51
69
|
"""
|
52
70
|
|
53
|
-
def __init__(self, name, message=
|
54
|
-
|
55
|
-
super().__init__(self.message)
|
71
|
+
def __init__(self, name: str, message: str = ""):
|
72
|
+
super().__init__(message or f"Configuration item {name!r} is already not set.")
|
56
73
|
|
57
74
|
|
58
75
|
class ConfigFileValidationError(ConfigError):
|
@@ -60,7 +77,8 @@ class ConfigFileValidationError(ConfigError):
|
|
60
77
|
Raised when the configuration file fails validation.
|
61
78
|
"""
|
62
79
|
|
63
|
-
|
80
|
+
def __init__(self, msg: str) -> None:
|
81
|
+
super().__init__(msg)
|
64
82
|
|
65
83
|
|
66
84
|
class ConfigItemCallbackError(ConfigError):
|
@@ -68,23 +86,24 @@ class ConfigItemCallbackError(ConfigError):
|
|
68
86
|
Raised when a configuration callback errors.
|
69
87
|
"""
|
70
88
|
|
71
|
-
def __init__(self, name, callback, err, message=
|
72
|
-
|
73
|
-
|
74
|
-
|
89
|
+
def __init__(self, name: str, callback: Any, err: Any, message: str = ""):
|
90
|
+
super().__init__(
|
91
|
+
message
|
92
|
+
or (
|
93
|
+
f"Callback function {callback.__name__!r} for configuration item {name!r} "
|
94
|
+
f"failed with exception: \n\n{str(err)}"
|
95
|
+
)
|
75
96
|
)
|
76
|
-
super().__init__(self.message)
|
77
97
|
|
78
98
|
|
79
99
|
class ConfigFileInvocationIncompatibleError(ConfigError):
|
80
100
|
"""Raised when, given the run time information of the invocation, no compatible
|
81
101
|
configuration can be found in the config file."""
|
82
102
|
|
83
|
-
def __init__(self, message=
|
84
|
-
|
85
|
-
"No config could be found that matches the current invocation."
|
103
|
+
def __init__(self, message: str | None = ""):
|
104
|
+
super().__init__(
|
105
|
+
message or ("No config could be found that matches the current invocation.")
|
86
106
|
)
|
87
|
-
super().__init__(self.message)
|
88
107
|
|
89
108
|
|
90
109
|
class ConfigFileInvocationUnknownMatchKey(ConfigError):
|
@@ -92,134 +111,156 @@ class ConfigFileInvocationUnknownMatchKey(ConfigError):
|
|
92
111
|
Raised when the configuration contains an invalid match key.
|
93
112
|
"""
|
94
113
|
|
95
|
-
def __init__(self, match_key, message=
|
96
|
-
self.message = message or (
|
97
|
-
f"Specified match key ({match_key!r}) is not a valid run time info "
|
98
|
-
f"attribute."
|
99
|
-
)
|
114
|
+
def __init__(self, match_key: str, message: str = ""):
|
100
115
|
self.match_key = match_key
|
101
|
-
super().__init__(
|
116
|
+
super().__init__(
|
117
|
+
message
|
118
|
+
or (
|
119
|
+
f"Specified match key ({match_key!r}) is not a valid run time info "
|
120
|
+
f"attribute."
|
121
|
+
)
|
122
|
+
)
|
102
123
|
|
103
124
|
|
104
125
|
class ConfigInvocationKeyNotFoundError(ConfigError):
|
105
126
|
"""Raised when a configuration invocation key is passed but it is not a valid key."""
|
106
127
|
|
107
|
-
def __init__(
|
128
|
+
def __init__(
|
129
|
+
self, invoc_key: str, file_path: PathLike, available_keys: Sequence[str]
|
130
|
+
):
|
108
131
|
self.invoc_key = invoc_key
|
109
132
|
self.file_path = file_path
|
110
133
|
self.available_keys = available_keys
|
111
|
-
|
134
|
+
super().__init__(
|
112
135
|
f"Invocation key {self.invoc_key!r} does not exist in configuration file. "
|
113
136
|
f"Available keys in configuration file {str(self.file_path)!r} are "
|
114
137
|
f"{self.available_keys!r}."
|
115
138
|
)
|
116
|
-
super().__init__(self.message)
|
117
139
|
|
118
140
|
|
119
141
|
class ConfigValidationError(ConfigError):
|
120
142
|
"""Raised when the matching config data is invalid."""
|
121
143
|
|
122
|
-
def __init__(self, message, meta_data=None):
|
144
|
+
def __init__(self, message: str, meta_data: ConfigMetadata | None = None):
|
123
145
|
self.meta_data = meta_data
|
124
|
-
|
125
|
-
super().__init__(self.message)
|
146
|
+
super().__init__(message + (f"config {self.meta_data}\n" if meta_data else ""))
|
126
147
|
|
127
148
|
|
128
149
|
class ConfigDefaultValidationError(ConfigError):
|
129
150
|
"""Raised when the specified default configuration in the `ConfigOptions` object is
|
130
151
|
invalid."""
|
131
152
|
|
132
|
-
def __init__(self, validation_err, message=
|
133
|
-
|
134
|
-
|
135
|
-
|
153
|
+
def __init__(self, validation_err: Any, message: str = ""):
|
154
|
+
super().__init__(
|
155
|
+
message
|
156
|
+
or (
|
157
|
+
f"The default configuration specified in the `ConfigOptions` object is "
|
158
|
+
f"invalid.\n\n{validation_err}"
|
159
|
+
)
|
136
160
|
)
|
137
|
-
super().__init__(self.message)
|
138
161
|
|
139
162
|
|
140
163
|
class ConfigChangeInvalidError(ConfigError):
|
141
164
|
"""Raised when trying to set an invalid key in the Config."""
|
142
165
|
|
143
|
-
def __init__(self, name, message=
|
144
|
-
|
145
|
-
|
146
|
-
|
166
|
+
def __init__(self, name: str, message: str = ""):
|
167
|
+
super().__init__(
|
168
|
+
message
|
169
|
+
or (
|
170
|
+
f"Cannot modify value for invalid config item {name!r}. Use the `config list`"
|
171
|
+
f" sub-command to list all configurable items."
|
172
|
+
)
|
147
173
|
)
|
148
|
-
super().__init__(self.message)
|
149
174
|
|
150
175
|
|
151
176
|
class ConfigChangeInvalidJSONError(ConfigError):
|
152
177
|
"""Raised when attempting to set a config key using an invalid JSON string."""
|
153
178
|
|
154
|
-
def __init__(self, name, json_str, err, message=
|
155
|
-
|
156
|
-
|
157
|
-
|
179
|
+
def __init__(self, name: str, json_str: str, err: Any, message: str = ""):
|
180
|
+
super().__init__(
|
181
|
+
message
|
182
|
+
or (
|
183
|
+
f"The config file has not been modified. Invalid JSON string for config item "
|
184
|
+
f"{name!r}. {json_str!r}\n\n{err!r}"
|
185
|
+
)
|
158
186
|
)
|
159
|
-
super().__init__(self.message)
|
160
187
|
|
161
188
|
|
162
189
|
class ConfigChangeValidationError(ConfigError):
|
163
190
|
"""Raised when a change to the configurable data would invalidate the config."""
|
164
191
|
|
165
|
-
def __init__(self, name, validation_err, message=
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
192
|
+
def __init__(self, name: str, validation_err: Any, message: str = ""):
|
193
|
+
super().__init__(
|
194
|
+
message
|
195
|
+
or (
|
196
|
+
f"The configuration has not been modified. Requested modification to item "
|
197
|
+
f"{name!r} would invalidate the config in the following way."
|
198
|
+
f"\n\n{validation_err}"
|
199
|
+
)
|
170
200
|
)
|
171
|
-
super().__init__(self.message)
|
172
201
|
|
173
202
|
|
174
203
|
class ConfigChangeFileUpdateError(ConfigError):
|
175
204
|
"""Raised when the updating of the config YAML file fails."""
|
176
205
|
|
177
|
-
def __init__(self, names, err, message=
|
178
|
-
|
179
|
-
|
180
|
-
|
206
|
+
def __init__(self, names: Sequence[str], err, message: str = ""):
|
207
|
+
super().__init__(
|
208
|
+
message
|
209
|
+
or (
|
210
|
+
f"Failed to update the config file for modification of config items {names!r}."
|
211
|
+
f"\n\n{err!r}"
|
212
|
+
)
|
181
213
|
)
|
182
|
-
super().__init__(self.message)
|
183
214
|
|
184
215
|
|
185
216
|
class ConfigChangeTypeInvalidError(ConfigError):
|
186
217
|
"""Raised when trying to modify a config item using a list operation, when the config
|
187
218
|
item is not a list."""
|
188
219
|
|
189
|
-
def __init__(self, name, typ, message=
|
190
|
-
|
191
|
-
|
192
|
-
|
220
|
+
def __init__(self, name: str, typ: type, message: str = ""):
|
221
|
+
super().__init__(
|
222
|
+
message
|
223
|
+
or (
|
224
|
+
f"The configuration has not been modified. The config item {name!r} has type "
|
225
|
+
f"{typ!r} and so cannot be modified in that way."
|
226
|
+
)
|
193
227
|
)
|
194
|
-
super().__init__(self.message)
|
195
228
|
|
196
229
|
|
197
230
|
class ConfigChangePopIndexError(ConfigError):
|
198
231
|
"""Raised when trying to pop an item from a config item with an invalid index."""
|
199
232
|
|
200
|
-
def __init__(self, name, length, index, message=
|
201
|
-
|
202
|
-
|
203
|
-
|
233
|
+
def __init__(self, name: str, length: int, index: int, message: str = ""):
|
234
|
+
super().__init__(
|
235
|
+
message
|
236
|
+
or (
|
237
|
+
f"The configuration has not been modified. The config item {name!r} has length "
|
238
|
+
f"{length!r} and so cannot be popped with index {index}."
|
239
|
+
)
|
204
240
|
)
|
205
|
-
super().__init__(self.message)
|
206
241
|
|
207
242
|
|
208
243
|
class MissingTaskSchemaFileError(ConfigError):
|
209
244
|
"""Raised when a task schema file specified in the config file does not exist."""
|
210
245
|
|
211
|
-
def __init__(self, file_name, err, message=
|
212
|
-
|
213
|
-
f"The task schema file {file_name!r} cannot be found. \n{err!s}"
|
246
|
+
def __init__(self, file_name: str, err: Any, message: str = ""):
|
247
|
+
super().__init__(
|
248
|
+
message or (f"The task schema file {file_name!r} cannot be found. \n{err!s}")
|
214
249
|
)
|
215
|
-
super().__init__(self.message)
|
216
250
|
|
217
251
|
|
218
252
|
class MissingEnvironmentFileError(ConfigError):
|
219
253
|
"""Raised when an environment file specified in the config file does not exist."""
|
220
254
|
|
221
|
-
def __init__(self, file_name, err, message=
|
222
|
-
|
223
|
-
f"The environment file {file_name!r} cannot be found. \n{err!s}"
|
255
|
+
def __init__(self, file_name: str, err: Any, message: str = ""):
|
256
|
+
super().__init__(
|
257
|
+
message or (f"The environment file {file_name!r} cannot be found. \n{err!s}")
|
224
258
|
)
|
225
|
-
|
259
|
+
|
260
|
+
|
261
|
+
class ConfigReadOnlyError(ConfigError):
|
262
|
+
pass
|
263
|
+
|
264
|
+
|
265
|
+
class UnknownMetaTaskConstitutiveSchema(ValueError):
|
266
|
+
pass
|
@@ -0,0 +1,148 @@
|
|
1
|
+
"""
|
2
|
+
Types used in configuration.
|
3
|
+
"""
|
4
|
+
|
5
|
+
from __future__ import annotations
|
6
|
+
from typing import TYPE_CHECKING
|
7
|
+
from typing_extensions import TypeAlias, TypedDict, TypeVar
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
from collections.abc import Callable, Sequence
|
11
|
+
from pathlib import Path
|
12
|
+
from typing import Any
|
13
|
+
from typing_extensions import NotRequired
|
14
|
+
from .config import Config
|
15
|
+
from ..core.validation import Schema
|
16
|
+
|
17
|
+
|
18
|
+
T = TypeVar("T")
|
19
|
+
#: Type of a getter callback.
|
20
|
+
GetterCallback: TypeAlias = "Callable[[Config, T], T]"
|
21
|
+
#: Type of a setter callback.
|
22
|
+
SetterCallback: TypeAlias = "Callable[[Config, T], Any]"
|
23
|
+
#: Type of a unsetter callback.
|
24
|
+
UnsetterCallback: TypeAlias = "Callable[[Config], None]"
|
25
|
+
|
26
|
+
|
27
|
+
class SGEParallelEnvsDescriptor(TypedDict):
|
28
|
+
"""
|
29
|
+
SGE parallel environment descriptor.
|
30
|
+
"""
|
31
|
+
|
32
|
+
#: Number of supported cores.
|
33
|
+
num_cores: list[int]
|
34
|
+
|
35
|
+
|
36
|
+
class SLURMPartitionsDescriptor(TypedDict):
|
37
|
+
"""
|
38
|
+
SLURM partition descriptor.
|
39
|
+
"""
|
40
|
+
|
41
|
+
#: Number of supported cores.
|
42
|
+
num_cores: NotRequired[list[int]]
|
43
|
+
#: Number of cores per node.
|
44
|
+
num_cores_per_node: NotRequired[list[int]]
|
45
|
+
#: Number of supported nodes.
|
46
|
+
num_nodes: NotRequired[list[int]]
|
47
|
+
#: Possible parallel modes.
|
48
|
+
parallel_modes: NotRequired[list[str]]
|
49
|
+
|
50
|
+
|
51
|
+
class SchedulerConfigDescriptor(TypedDict):
|
52
|
+
"""
|
53
|
+
Scheduler configuration descriptor.
|
54
|
+
"""
|
55
|
+
|
56
|
+
#: Default values.
|
57
|
+
defaults: dict[str, Any]
|
58
|
+
#: SGE parallel environments, by name.
|
59
|
+
parallel_environments: NotRequired[dict[str, SGEParallelEnvsDescriptor]]
|
60
|
+
#: SLURM partitions, by name.
|
61
|
+
partitions: NotRequired[dict[str, SLURMPartitionsDescriptor]]
|
62
|
+
|
63
|
+
|
64
|
+
class ShellConfigDescriptor(TypedDict):
|
65
|
+
"""
|
66
|
+
Shell configuration descriptor.
|
67
|
+
"""
|
68
|
+
|
69
|
+
#: Default values.
|
70
|
+
defaults: dict[str, Any]
|
71
|
+
|
72
|
+
|
73
|
+
class ConfigDescriptor(TypedDict):
|
74
|
+
"""
|
75
|
+
Configuration descriptor.
|
76
|
+
"""
|
77
|
+
|
78
|
+
#: Execution machine.
|
79
|
+
machine: NotRequired[str]
|
80
|
+
#: Where to log.
|
81
|
+
log_file_path: NotRequired[str]
|
82
|
+
#: Where to find execution environments.
|
83
|
+
environment_sources: NotRequired[list[str]]
|
84
|
+
#: Where to find task schemas.
|
85
|
+
task_schema_sources: NotRequired[list[str]]
|
86
|
+
#: Where to find command files.
|
87
|
+
command_file_sources: NotRequired[list[str]]
|
88
|
+
#: Where to find parameter implementations.
|
89
|
+
parameter_sources: NotRequired[list[str]]
|
90
|
+
#: Default scheduler.
|
91
|
+
default_scheduler: NotRequired[str]
|
92
|
+
#: Default shell.
|
93
|
+
default_shell: NotRequired[str]
|
94
|
+
#: Supported schedulers.
|
95
|
+
schedulers: NotRequired[dict[str, SchedulerConfigDescriptor]]
|
96
|
+
#: Supported shells.
|
97
|
+
shells: NotRequired[dict[str, ShellConfigDescriptor]]
|
98
|
+
|
99
|
+
|
100
|
+
class InvocationDescriptor(TypedDict):
|
101
|
+
"""
|
102
|
+
Invocation descriptor.
|
103
|
+
"""
|
104
|
+
|
105
|
+
#: Used to set up the environment.
|
106
|
+
environment_setup: str | None
|
107
|
+
#: setting to apply if matched.
|
108
|
+
match: dict[str, str | list[str]]
|
109
|
+
|
110
|
+
|
111
|
+
class DefaultConfiguration(TypedDict):
|
112
|
+
"""
|
113
|
+
The default configuration.
|
114
|
+
"""
|
115
|
+
|
116
|
+
#: Default invocation.
|
117
|
+
invocation: InvocationDescriptor
|
118
|
+
#: Default configuration.
|
119
|
+
config: ConfigDescriptor
|
120
|
+
|
121
|
+
|
122
|
+
#: A configuration dictionary.
|
123
|
+
ConfigDict: TypeAlias = "dict[str, dict[str, DefaultConfiguration]]"
|
124
|
+
|
125
|
+
|
126
|
+
class ConfigMetadata(TypedDict):
|
127
|
+
"""
|
128
|
+
Metadata supported by the :class:`Config` class.
|
129
|
+
"""
|
130
|
+
|
131
|
+
#: Location of directory containing the config file.
|
132
|
+
config_directory: Path
|
133
|
+
#: Name of the config file.
|
134
|
+
config_file_name: str
|
135
|
+
#: Full path to the config file.
|
136
|
+
config_file_path: Path
|
137
|
+
#: The contents of the config file.
|
138
|
+
config_file_contents: str
|
139
|
+
#: The key identifying the config section within the config file.
|
140
|
+
config_key: str
|
141
|
+
#: Schemas that apply to the config.
|
142
|
+
config_schemas: Sequence[Schema]
|
143
|
+
#: The user that invoked things.
|
144
|
+
invoking_user_id: str
|
145
|
+
#: The user hosting things.
|
146
|
+
host_user_id: str
|
147
|
+
#: Path to file holding description of :attr:``host_user_id``.
|
148
|
+
host_user_id_file_path: Path
|
hpcflow/sdk/core/__init__.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
"""Core programmatic models for hpcflow.
|
2
2
|
|
3
|
-
EAR abort exit code is set to 64
|
3
|
+
EAR abort exit code is set to 64. EAR skipped exit code is set to 65.
|
4
4
|
|
5
5
|
References
|
6
6
|
----------
|
@@ -8,7 +8,31 @@ https://tldp.org/LDP/abs/html/exitcodes.html
|
|
8
8
|
|
9
9
|
"""
|
10
10
|
|
11
|
+
import numpy as np
|
12
|
+
|
11
13
|
#: Formats supported for templates.
|
12
14
|
ALL_TEMPLATE_FORMATS = ("yaml", "json")
|
13
15
|
#: The exit code used by an EAR when it aborts.
|
14
16
|
ABORT_EXIT_CODE = 64
|
17
|
+
SKIPPED_EXIT_CODE = 65
|
18
|
+
NO_COMMANDS_EXIT_CODE = 66
|
19
|
+
RUN_DIR_ARR_DTYPE = [
|
20
|
+
("task_insert_ID", np.uint8),
|
21
|
+
("element_idx", np.uint32),
|
22
|
+
("iteration_idx", np.uint32),
|
23
|
+
("action_idx", np.uint8),
|
24
|
+
("run_idx", np.uint8),
|
25
|
+
("element_depth", np.uint8),
|
26
|
+
("iteration_depth", np.uint8),
|
27
|
+
]
|
28
|
+
_uint8_max = np.iinfo(np.uint8).max
|
29
|
+
_uint32_max = np.iinfo(np.uint32).max
|
30
|
+
RUN_DIR_ARR_FILL = (
|
31
|
+
_uint8_max,
|
32
|
+
_uint32_max,
|
33
|
+
_uint32_max,
|
34
|
+
_uint8_max,
|
35
|
+
_uint8_max,
|
36
|
+
_uint8_max,
|
37
|
+
_uint8_max,
|
38
|
+
)
|