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.
Files changed (176) hide show
  1. hpcflow/__pyinstaller/hook-hpcflow.py +9 -6
  2. hpcflow/_version.py +1 -1
  3. hpcflow/app.py +1 -0
  4. hpcflow/data/scripts/bad_script.py +2 -0
  5. hpcflow/data/scripts/do_nothing.py +2 -0
  6. hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
  7. hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
  8. hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
  9. hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
  10. hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
  11. hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
  12. hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
  13. hpcflow/data/scripts/input_file_generator_basic.py +3 -0
  14. hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
  15. hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
  16. hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
  17. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
  18. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
  19. hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
  20. hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
  21. hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
  22. hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
  23. hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +1 -1
  24. hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
  25. hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
  26. hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
  27. hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
  28. hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
  29. hpcflow/data/scripts/output_file_parser_basic.py +3 -0
  30. hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
  31. hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
  32. hpcflow/data/scripts/script_exit_test.py +5 -0
  33. hpcflow/data/template_components/environments.yaml +1 -1
  34. hpcflow/sdk/__init__.py +26 -15
  35. hpcflow/sdk/app.py +2192 -768
  36. hpcflow/sdk/cli.py +506 -296
  37. hpcflow/sdk/cli_common.py +105 -7
  38. hpcflow/sdk/config/__init__.py +1 -1
  39. hpcflow/sdk/config/callbacks.py +115 -43
  40. hpcflow/sdk/config/cli.py +126 -103
  41. hpcflow/sdk/config/config.py +674 -318
  42. hpcflow/sdk/config/config_file.py +131 -95
  43. hpcflow/sdk/config/errors.py +125 -84
  44. hpcflow/sdk/config/types.py +148 -0
  45. hpcflow/sdk/core/__init__.py +25 -1
  46. hpcflow/sdk/core/actions.py +1771 -1059
  47. hpcflow/sdk/core/app_aware.py +24 -0
  48. hpcflow/sdk/core/cache.py +139 -79
  49. hpcflow/sdk/core/command_files.py +263 -287
  50. hpcflow/sdk/core/commands.py +145 -112
  51. hpcflow/sdk/core/element.py +828 -535
  52. hpcflow/sdk/core/enums.py +192 -0
  53. hpcflow/sdk/core/environment.py +74 -93
  54. hpcflow/sdk/core/errors.py +455 -52
  55. hpcflow/sdk/core/execute.py +207 -0
  56. hpcflow/sdk/core/json_like.py +540 -272
  57. hpcflow/sdk/core/loop.py +751 -347
  58. hpcflow/sdk/core/loop_cache.py +164 -47
  59. hpcflow/sdk/core/object_list.py +370 -207
  60. hpcflow/sdk/core/parameters.py +1100 -627
  61. hpcflow/sdk/core/rule.py +59 -41
  62. hpcflow/sdk/core/run_dir_files.py +21 -37
  63. hpcflow/sdk/core/skip_reason.py +7 -0
  64. hpcflow/sdk/core/task.py +1649 -1339
  65. hpcflow/sdk/core/task_schema.py +308 -196
  66. hpcflow/sdk/core/test_utils.py +191 -114
  67. hpcflow/sdk/core/types.py +440 -0
  68. hpcflow/sdk/core/utils.py +485 -309
  69. hpcflow/sdk/core/validation.py +82 -9
  70. hpcflow/sdk/core/workflow.py +2544 -1178
  71. hpcflow/sdk/core/zarr_io.py +98 -137
  72. hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
  73. hpcflow/sdk/demo/cli.py +53 -33
  74. hpcflow/sdk/helper/cli.py +18 -15
  75. hpcflow/sdk/helper/helper.py +75 -63
  76. hpcflow/sdk/helper/watcher.py +61 -28
  77. hpcflow/sdk/log.py +122 -71
  78. hpcflow/sdk/persistence/__init__.py +8 -31
  79. hpcflow/sdk/persistence/base.py +1360 -606
  80. hpcflow/sdk/persistence/defaults.py +6 -0
  81. hpcflow/sdk/persistence/discovery.py +38 -0
  82. hpcflow/sdk/persistence/json.py +568 -188
  83. hpcflow/sdk/persistence/pending.py +382 -179
  84. hpcflow/sdk/persistence/store_resource.py +39 -23
  85. hpcflow/sdk/persistence/types.py +318 -0
  86. hpcflow/sdk/persistence/utils.py +14 -11
  87. hpcflow/sdk/persistence/zarr.py +1337 -433
  88. hpcflow/sdk/runtime.py +44 -41
  89. hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
  90. hpcflow/sdk/submission/jobscript.py +1651 -692
  91. hpcflow/sdk/submission/schedulers/__init__.py +167 -39
  92. hpcflow/sdk/submission/schedulers/direct.py +121 -81
  93. hpcflow/sdk/submission/schedulers/sge.py +170 -129
  94. hpcflow/sdk/submission/schedulers/slurm.py +291 -268
  95. hpcflow/sdk/submission/schedulers/utils.py +12 -2
  96. hpcflow/sdk/submission/shells/__init__.py +14 -15
  97. hpcflow/sdk/submission/shells/base.py +150 -29
  98. hpcflow/sdk/submission/shells/bash.py +283 -173
  99. hpcflow/sdk/submission/shells/os_version.py +31 -30
  100. hpcflow/sdk/submission/shells/powershell.py +228 -170
  101. hpcflow/sdk/submission/submission.py +1014 -335
  102. hpcflow/sdk/submission/types.py +140 -0
  103. hpcflow/sdk/typing.py +182 -12
  104. hpcflow/sdk/utils/arrays.py +71 -0
  105. hpcflow/sdk/utils/deferred_file.py +55 -0
  106. hpcflow/sdk/utils/hashing.py +16 -0
  107. hpcflow/sdk/utils/patches.py +12 -0
  108. hpcflow/sdk/utils/strings.py +33 -0
  109. hpcflow/tests/api/test_api.py +32 -0
  110. hpcflow/tests/conftest.py +27 -6
  111. hpcflow/tests/data/multi_path_sequences.yaml +29 -0
  112. hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
  113. hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
  114. hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
  115. hpcflow/tests/scripts/test_input_file_generators.py +282 -0
  116. hpcflow/tests/scripts/test_main_scripts.py +866 -85
  117. hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
  118. hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
  119. hpcflow/tests/shells/wsl/test_wsl_submission.py +12 -4
  120. hpcflow/tests/unit/test_action.py +262 -75
  121. hpcflow/tests/unit/test_action_rule.py +9 -4
  122. hpcflow/tests/unit/test_app.py +33 -6
  123. hpcflow/tests/unit/test_cache.py +46 -0
  124. hpcflow/tests/unit/test_cli.py +134 -1
  125. hpcflow/tests/unit/test_command.py +71 -54
  126. hpcflow/tests/unit/test_config.py +142 -16
  127. hpcflow/tests/unit/test_config_file.py +21 -18
  128. hpcflow/tests/unit/test_element.py +58 -62
  129. hpcflow/tests/unit/test_element_iteration.py +50 -1
  130. hpcflow/tests/unit/test_element_set.py +29 -19
  131. hpcflow/tests/unit/test_group.py +4 -2
  132. hpcflow/tests/unit/test_input_source.py +116 -93
  133. hpcflow/tests/unit/test_input_value.py +29 -24
  134. hpcflow/tests/unit/test_jobscript_unit.py +757 -0
  135. hpcflow/tests/unit/test_json_like.py +44 -35
  136. hpcflow/tests/unit/test_loop.py +1396 -84
  137. hpcflow/tests/unit/test_meta_task.py +325 -0
  138. hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
  139. hpcflow/tests/unit/test_object_list.py +17 -12
  140. hpcflow/tests/unit/test_parameter.py +29 -7
  141. hpcflow/tests/unit/test_persistence.py +237 -42
  142. hpcflow/tests/unit/test_resources.py +20 -18
  143. hpcflow/tests/unit/test_run.py +117 -6
  144. hpcflow/tests/unit/test_run_directories.py +29 -0
  145. hpcflow/tests/unit/test_runtime.py +2 -1
  146. hpcflow/tests/unit/test_schema_input.py +23 -15
  147. hpcflow/tests/unit/test_shell.py +23 -2
  148. hpcflow/tests/unit/test_slurm.py +8 -7
  149. hpcflow/tests/unit/test_submission.py +38 -89
  150. hpcflow/tests/unit/test_task.py +352 -247
  151. hpcflow/tests/unit/test_task_schema.py +33 -20
  152. hpcflow/tests/unit/test_utils.py +9 -11
  153. hpcflow/tests/unit/test_value_sequence.py +15 -12
  154. hpcflow/tests/unit/test_workflow.py +114 -83
  155. hpcflow/tests/unit/test_workflow_template.py +0 -1
  156. hpcflow/tests/unit/utils/test_arrays.py +40 -0
  157. hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
  158. hpcflow/tests/unit/utils/test_hashing.py +65 -0
  159. hpcflow/tests/unit/utils/test_patches.py +5 -0
  160. hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
  161. hpcflow/tests/workflows/__init__.py +0 -0
  162. hpcflow/tests/workflows/test_directory_structure.py +31 -0
  163. hpcflow/tests/workflows/test_jobscript.py +334 -1
  164. hpcflow/tests/workflows/test_run_status.py +198 -0
  165. hpcflow/tests/workflows/test_skip_downstream.py +696 -0
  166. hpcflow/tests/workflows/test_submission.py +140 -0
  167. hpcflow/tests/workflows/test_workflows.py +160 -15
  168. hpcflow/tests/workflows/test_zip.py +18 -0
  169. hpcflow/viz_demo.ipynb +6587 -3
  170. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/METADATA +8 -4
  171. hpcflow_new2-0.2.0a199.dist-info/RECORD +221 -0
  172. hpcflow/sdk/core/parallel.py +0 -21
  173. hpcflow_new2-0.2.0a189.dist-info/RECORD +0 -158
  174. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/LICENSE +0 -0
  175. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/WHEEL +0 -0
  176. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a199.dist-info}/entry_points.txt +0 -0
@@ -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
- class ConfigError(Exception):
7
- """Raised when a valid configuration can not be associated with the current
8
- invocation."""
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Sequence, Iterable
10
+ from .types import ConfigMetadata
11
+ from ..typing import PathLike
9
12
 
10
- pass
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=None):
19
- self.message = message or (
20
- f"Specified name {name!r} is not a valid meta-data or configurable "
21
- f"configuration item."
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=None):
32
- self.message = message or (
33
- f"Specified configuration override {name!r} is not a valid configurable item."
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
- self.message = message or (f"Specified name {name!r} is not a configurable item.")
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=None):
54
- self.message = message or f"Configuration item {name!r} is already not set."
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
- pass
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=None):
72
- self.message = message or (
73
- f"Callback function {callback.__name__!r} for configuration item {name!r} "
74
- f"failed with exception: \n\n{str(err)}"
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=None):
84
- self.message = message or (
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=None):
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__(self.message)
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__(self, invoc_key, file_path, available_keys) -> None:
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
- self.message = (
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
- self.message = message + (f"config {self.meta_data}\n" if meta_data else "")
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=None):
133
- self.message = message or (
134
- f"The default configuration specified in the `ConfigOptions` object is "
135
- f"invalid.\n\n{validation_err}"
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=None):
144
- self.message = message or (
145
- f"Cannot modify value for invalid config item {name!r}. Use the `config list`"
146
- f" sub-command to list all configurable items."
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=None):
155
- self.message = message or (
156
- f"The config file has not been modified. Invalid JSON string for config item "
157
- f"{name!r}. {json_str!r}\n\n{err!r}"
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=None):
166
- self.message = message or (
167
- f"The configuration has not been modified. Requested modification to item "
168
- f"{name!r} would invalidate the config in the following way."
169
- f"\n\n{validation_err}"
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=None):
178
- self.message = message or (
179
- f"Failed to update the config file for modification of config items {names!r}."
180
- f"\n\n{err!r}"
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=None):
190
- self.message = message or (
191
- f"The configuration has not been modified. The config item {name!r} has type "
192
- f"{typ!r} and so cannot be modified in that way."
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=None):
201
- self.message = message or (
202
- f"The configuration has not been modified. The config item {name!r} has length "
203
- f"{length!r} and so cannot be popped with index {index}."
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=None):
212
- self.message = message or (
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=None):
222
- self.message = message or (
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
- super().__init__(self.message)
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
@@ -1,6 +1,6 @@
1
1
  """Core programmatic models for hpcflow.
2
2
 
3
- EAR abort exit code is set to 64 [1].
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
+ )