hpcflow-new2 0.2.0a189__py3-none-any.whl → 0.2.0a190__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 (115) hide show
  1. hpcflow/__pyinstaller/hook-hpcflow.py +8 -6
  2. hpcflow/_version.py +1 -1
  3. hpcflow/app.py +1 -0
  4. hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +1 -1
  5. hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
  6. hpcflow/sdk/__init__.py +21 -15
  7. hpcflow/sdk/app.py +2133 -770
  8. hpcflow/sdk/cli.py +281 -250
  9. hpcflow/sdk/cli_common.py +6 -2
  10. hpcflow/sdk/config/__init__.py +1 -1
  11. hpcflow/sdk/config/callbacks.py +77 -42
  12. hpcflow/sdk/config/cli.py +126 -103
  13. hpcflow/sdk/config/config.py +578 -311
  14. hpcflow/sdk/config/config_file.py +131 -95
  15. hpcflow/sdk/config/errors.py +112 -85
  16. hpcflow/sdk/config/types.py +145 -0
  17. hpcflow/sdk/core/actions.py +1054 -994
  18. hpcflow/sdk/core/app_aware.py +24 -0
  19. hpcflow/sdk/core/cache.py +81 -63
  20. hpcflow/sdk/core/command_files.py +275 -185
  21. hpcflow/sdk/core/commands.py +111 -107
  22. hpcflow/sdk/core/element.py +724 -503
  23. hpcflow/sdk/core/enums.py +192 -0
  24. hpcflow/sdk/core/environment.py +74 -93
  25. hpcflow/sdk/core/errors.py +398 -51
  26. hpcflow/sdk/core/json_like.py +540 -272
  27. hpcflow/sdk/core/loop.py +380 -334
  28. hpcflow/sdk/core/loop_cache.py +160 -43
  29. hpcflow/sdk/core/object_list.py +370 -207
  30. hpcflow/sdk/core/parameters.py +728 -600
  31. hpcflow/sdk/core/rule.py +59 -41
  32. hpcflow/sdk/core/run_dir_files.py +33 -22
  33. hpcflow/sdk/core/task.py +1546 -1325
  34. hpcflow/sdk/core/task_schema.py +240 -196
  35. hpcflow/sdk/core/test_utils.py +126 -88
  36. hpcflow/sdk/core/types.py +387 -0
  37. hpcflow/sdk/core/utils.py +410 -305
  38. hpcflow/sdk/core/validation.py +82 -9
  39. hpcflow/sdk/core/workflow.py +1192 -1028
  40. hpcflow/sdk/core/zarr_io.py +98 -137
  41. hpcflow/sdk/demo/cli.py +46 -33
  42. hpcflow/sdk/helper/cli.py +18 -16
  43. hpcflow/sdk/helper/helper.py +75 -63
  44. hpcflow/sdk/helper/watcher.py +61 -28
  45. hpcflow/sdk/log.py +83 -59
  46. hpcflow/sdk/persistence/__init__.py +8 -31
  47. hpcflow/sdk/persistence/base.py +988 -586
  48. hpcflow/sdk/persistence/defaults.py +6 -0
  49. hpcflow/sdk/persistence/discovery.py +38 -0
  50. hpcflow/sdk/persistence/json.py +408 -153
  51. hpcflow/sdk/persistence/pending.py +158 -123
  52. hpcflow/sdk/persistence/store_resource.py +37 -22
  53. hpcflow/sdk/persistence/types.py +307 -0
  54. hpcflow/sdk/persistence/utils.py +14 -11
  55. hpcflow/sdk/persistence/zarr.py +477 -420
  56. hpcflow/sdk/runtime.py +44 -41
  57. hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
  58. hpcflow/sdk/submission/jobscript.py +444 -404
  59. hpcflow/sdk/submission/schedulers/__init__.py +133 -40
  60. hpcflow/sdk/submission/schedulers/direct.py +97 -71
  61. hpcflow/sdk/submission/schedulers/sge.py +132 -126
  62. hpcflow/sdk/submission/schedulers/slurm.py +263 -268
  63. hpcflow/sdk/submission/schedulers/utils.py +7 -2
  64. hpcflow/sdk/submission/shells/__init__.py +14 -15
  65. hpcflow/sdk/submission/shells/base.py +102 -29
  66. hpcflow/sdk/submission/shells/bash.py +72 -55
  67. hpcflow/sdk/submission/shells/os_version.py +31 -30
  68. hpcflow/sdk/submission/shells/powershell.py +37 -29
  69. hpcflow/sdk/submission/submission.py +203 -257
  70. hpcflow/sdk/submission/types.py +143 -0
  71. hpcflow/sdk/typing.py +163 -12
  72. hpcflow/tests/conftest.py +8 -6
  73. hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
  74. hpcflow/tests/scripts/test_main_scripts.py +60 -30
  75. hpcflow/tests/shells/wsl/test_wsl_submission.py +6 -4
  76. hpcflow/tests/unit/test_action.py +86 -75
  77. hpcflow/tests/unit/test_action_rule.py +9 -4
  78. hpcflow/tests/unit/test_app.py +13 -6
  79. hpcflow/tests/unit/test_cli.py +1 -1
  80. hpcflow/tests/unit/test_command.py +71 -54
  81. hpcflow/tests/unit/test_config.py +20 -15
  82. hpcflow/tests/unit/test_config_file.py +21 -18
  83. hpcflow/tests/unit/test_element.py +58 -62
  84. hpcflow/tests/unit/test_element_iteration.py +3 -1
  85. hpcflow/tests/unit/test_element_set.py +29 -19
  86. hpcflow/tests/unit/test_group.py +4 -2
  87. hpcflow/tests/unit/test_input_source.py +116 -93
  88. hpcflow/tests/unit/test_input_value.py +29 -24
  89. hpcflow/tests/unit/test_json_like.py +44 -35
  90. hpcflow/tests/unit/test_loop.py +65 -58
  91. hpcflow/tests/unit/test_object_list.py +17 -12
  92. hpcflow/tests/unit/test_parameter.py +16 -7
  93. hpcflow/tests/unit/test_persistence.py +48 -35
  94. hpcflow/tests/unit/test_resources.py +20 -18
  95. hpcflow/tests/unit/test_run.py +8 -3
  96. hpcflow/tests/unit/test_runtime.py +2 -1
  97. hpcflow/tests/unit/test_schema_input.py +23 -15
  98. hpcflow/tests/unit/test_shell.py +3 -2
  99. hpcflow/tests/unit/test_slurm.py +8 -7
  100. hpcflow/tests/unit/test_submission.py +39 -19
  101. hpcflow/tests/unit/test_task.py +352 -247
  102. hpcflow/tests/unit/test_task_schema.py +33 -20
  103. hpcflow/tests/unit/test_utils.py +9 -11
  104. hpcflow/tests/unit/test_value_sequence.py +15 -12
  105. hpcflow/tests/unit/test_workflow.py +114 -83
  106. hpcflow/tests/unit/test_workflow_template.py +0 -1
  107. hpcflow/tests/workflows/test_jobscript.py +2 -1
  108. hpcflow/tests/workflows/test_workflows.py +18 -13
  109. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/METADATA +2 -1
  110. hpcflow_new2-0.2.0a190.dist-info/RECORD +165 -0
  111. hpcflow/sdk/core/parallel.py +0 -21
  112. hpcflow_new2-0.2.0a189.dist-info/RECORD +0 -158
  113. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/LICENSE +0 -0
  114. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/WHEEL +0 -0
  115. {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,387 @@
1
+ """
2
+ Types to support the core SDK.
3
+ """
4
+ from __future__ import annotations
5
+ from typing import Any, Literal, Protocol, TYPE_CHECKING
6
+ from typing_extensions import NotRequired, TypeAlias, TypedDict
7
+
8
+ if TYPE_CHECKING:
9
+ from collections.abc import Mapping, Sequence
10
+ from datetime import datetime, timedelta
11
+ import numpy as np
12
+ from valida.conditions import ConditionLike # type: ignore
13
+ from .actions import ActionScope
14
+ from .command_files import FileSpec
15
+ from .enums import ParallelMode, ParameterPropagationMode
16
+ from .object_list import ResourceList
17
+ from .parameters import (
18
+ InputSource,
19
+ InputValue,
20
+ Parameter,
21
+ ResourceSpec,
22
+ )
23
+ from .task import InputStatus
24
+ from ..persistence.types import ParamSource
25
+
26
+
27
+ class ParameterDependence(TypedDict):
28
+ """
29
+ Dependency descriptor for a parameter.
30
+ """
31
+
32
+ #: The input file writers that can use the parameter.
33
+ input_file_writers: list[FileSpec]
34
+ #: The commands that can use the parameter.
35
+ commands: list[int]
36
+
37
+
38
+ class ScriptData(TypedDict, total=False):
39
+ """
40
+ Descriptor for data relating to a script.
41
+ """
42
+
43
+ #: The format of the data.
44
+ format: str
45
+ #: Whether the data is required for all iterations.
46
+ all_iterations: NotRequired[bool]
47
+
48
+
49
+ class JobscriptSubmissionFailureArgs(TypedDict):
50
+ """
51
+ Arguments that can be expanded to create a
52
+ :class:`JobscriptSubmissionFailure`.
53
+ """
54
+
55
+ #: The command that was submitted.
56
+ submit_cmd: list[str]
57
+ #: The jobscript index.
58
+ js_idx: int
59
+ #: The jobscript path.
60
+ js_path: str
61
+ #: Where to write stdout.
62
+ stdout: NotRequired[str]
63
+ #: Where to write stderr.
64
+ stderr: NotRequired[str]
65
+ #: The exception from the exec of the subprocess.
66
+ subprocess_exc: NotRequired[Exception]
67
+ #: The exception from parsing the job ID.
68
+ job_ID_parse_exc: NotRequired[Exception]
69
+
70
+
71
+ class ElementDescriptor(TypedDict):
72
+ """
73
+ Descriptor for elements.
74
+ """
75
+
76
+ #: The statuses of inputs.
77
+ input_statuses: Mapping[str, InputStatus]
78
+ #: The sources of inputs.
79
+ input_sources: Mapping[str, InputSource]
80
+ #: The insertion ID.
81
+ task_insert_ID: int
82
+
83
+
84
+ class _DependentDescriptor(TypedDict):
85
+ #: The names of groups of dependents.
86
+ group_names: tuple[str, ...]
87
+
88
+
89
+ class DependentDescriptor(_DependentDescriptor, total=False):
90
+ """
91
+ Descriptor for dependents.
92
+ """
93
+
94
+
95
+ class IterableParam(TypedDict):
96
+ """
97
+ The type of the descriptor for an iterable parameter.
98
+ """
99
+
100
+ #: Identifier for the input task supplying the parameter.
101
+ input_task: int
102
+ #: Identifiers for the output tasks consuming the parameter.
103
+ output_tasks: list[int]
104
+
105
+
106
+ #: Type of an address.
107
+ Address: TypeAlias = "list[int | float | str]"
108
+ #: Type of something numeric.
109
+ Numeric: TypeAlias = "int | float | np.number"
110
+
111
+
112
+ class LabelInfo(TypedDict):
113
+ """
114
+ Information about a label.
115
+ """
116
+
117
+ #: The label propagation mode, if known.
118
+ propagation_mode: NotRequired[ParameterPropagationMode]
119
+ #: The group containing the label, if known.
120
+ group: NotRequired[str]
121
+ #: The default value for the label, if known.
122
+ default_value: NotRequired[InputValue]
123
+
124
+
125
+ class LabellingDescriptor(TypedDict):
126
+ """
127
+ Descriptor for a labelling.
128
+ """
129
+
130
+ #: The type with the label.
131
+ labelled_type: str
132
+ #: The propagation mode for the label.
133
+ propagation_mode: ParameterPropagationMode
134
+ #: The group containing the label.
135
+ group: str | None
136
+ #: The default value for the label, if known.
137
+ default_value: NotRequired[InputValue]
138
+
139
+
140
+ class ResourceSpecArgs(TypedDict):
141
+ """
142
+ Supported keyword arguments for a ResourceSpec.
143
+ """
144
+
145
+ #: Which scope does this apply to.
146
+ scope: NotRequired[ActionScope | str]
147
+ #: Which scratch space to use.
148
+ scratch: NotRequired[str]
149
+ #: Which parallel mode to use.
150
+ parallel_mode: NotRequired[str | ParallelMode]
151
+ #: How many cores to request.
152
+ num_cores: NotRequired[int]
153
+ #: How many cores per compute node to request.
154
+ num_cores_per_node: NotRequired[int]
155
+ #: How many threads to request.
156
+ num_threads: NotRequired[int]
157
+ #: How many compute nodes to request.
158
+ num_nodes: NotRequired[int]
159
+ #: Which scheduler to use.
160
+ scheduler: NotRequired[str]
161
+ #: Which system shell to use.
162
+ shell: NotRequired[str]
163
+ #: Whether to use array jobs.
164
+ use_job_array: NotRequired[bool]
165
+ #: If using array jobs, up to how many items should be in the job array.
166
+ max_array_items: NotRequired[int]
167
+ #: How long to run for.
168
+ time_limit: NotRequired[str | timedelta]
169
+ #: Additional arguments to pass to the scheduler.
170
+ scheduler_args: NotRequired[dict[str, Any]]
171
+ #: Additional arguments to pass to the shell.
172
+ shell_args: NotRequired[dict[str, Any]]
173
+ #: Which OS to use.
174
+ os_name: NotRequired[str]
175
+ #: Which execution environments to use.
176
+ environments: NotRequired[dict[str, dict[str, Any]]]
177
+ #: Which SGE parallel environment to request.
178
+ SGE_parallel_env: NotRequired[str]
179
+ #: Which SLURM partition to request.
180
+ SLURM_partition: NotRequired[str]
181
+ #: How many SLURM tasks to request.
182
+ SLURM_num_tasks: NotRequired[str]
183
+ #: How many SLURM tasks per compute node to request.
184
+ SLURM_num_tasks_per_node: NotRequired[str]
185
+ #: How many compute nodes to request.
186
+ SLURM_num_nodes: NotRequired[str]
187
+ #: How many CPU cores to ask for per SLURM task.
188
+ SLURM_num_cpus_per_task: NotRequired[str]
189
+
190
+
191
+ # Used in declaration of Resources below
192
+ _R: TypeAlias = "ResourceSpec | ResourceSpecArgs | dict"
193
+ #: The type of things we can normalise to a :py:class:`ResourceList`.
194
+ Resources: TypeAlias = "_R | ResourceList | None | Sequence[_R]"
195
+
196
+
197
+ class SchemaInputKwargs(TypedDict):
198
+ """
199
+ Just used when deep copying `SchemaInput`.
200
+ """
201
+
202
+ #: The parameter.
203
+ parameter: Parameter | str
204
+ #: Whether this is multiple.
205
+ multiple: bool
206
+ #: The labels.
207
+ labels: dict[str, LabelInfo] | None
208
+
209
+
210
+ class RuleArgs(TypedDict):
211
+ """
212
+ The keyword arguments that may be used to create a Rule.
213
+ """
214
+
215
+ #: If present, check this attribute exists.
216
+ check_exists: NotRequired[str]
217
+ #: If present, check this attribute does *not* exist.
218
+ check_missing: NotRequired[str]
219
+ #: Where to look up the attribute to check.
220
+ #: If not present, determined by context.
221
+ path: NotRequired[str]
222
+ #: If present, a general condition to check (or kwargs used to generate one).
223
+ condition: NotRequired[dict[str, Any] | ConditionLike]
224
+ #: If present, a cast to apply prior to running the general check.
225
+ cast: NotRequired[str]
226
+ #: Optional descriptive text.
227
+ doc: NotRequired[str]
228
+
229
+
230
+ class ActParameterDependence(TypedDict):
231
+ """
232
+ Action parameter dependency descriptor.
233
+ """
234
+
235
+ #: The input file writers that produce the parameter.
236
+ input_file_writers: list[tuple[int, FileSpec]]
237
+ #: The commands that produce the parameter.
238
+ commands: list[tuple[int, int]]
239
+
240
+
241
+ #: A relevant path when applying an update.
242
+ RelevantPath: TypeAlias = "ParentPath | UpdatePath | SiblingPath"
243
+
244
+
245
+ class RepeatsDescriptor(TypedDict):
246
+ """
247
+ Descriptor for repeats.
248
+ """
249
+
250
+ #: Name of the repeat.
251
+ name: str
252
+ #: The repeat count.
253
+ number: int
254
+ #: The nesting order. Normally an integer; non-integer values have special meanings.
255
+ nesting_order: float
256
+
257
+
258
+ class MultiplicityDescriptor(TypedDict):
259
+ """
260
+ Descriptor for multiplicities.
261
+ """
262
+
263
+ #: The size of the multiplicity.
264
+ multiplicity: int
265
+ #: The nesting order. Normally an integer; non-integer values have special meanings.
266
+ nesting_order: float
267
+ #: The path to the multiplicity.
268
+ path: str
269
+
270
+
271
+ class ParentPath(TypedDict):
272
+ """
273
+ A `RelevantPath` that is a path to a parent.
274
+ """
275
+
276
+ #: Type ID.
277
+ type: Literal["parent"]
278
+ relative_path: Sequence[str]
279
+
280
+
281
+ class UpdatePath(TypedDict):
282
+ """
283
+ A `RelevantPath` that is a path to an update.
284
+ """
285
+
286
+ #: Type ID.
287
+ type: Literal["update"]
288
+ update_path: Sequence[str]
289
+
290
+
291
+ class SiblingPath(TypedDict):
292
+ """
293
+ A `RelevantPath` that is a path to a sibling.
294
+ """
295
+
296
+ #: Type ID.
297
+ type: Literal["sibling"]
298
+
299
+
300
+ class RelevantData(TypedDict):
301
+ """
302
+ Data relevant to performing an update.
303
+ """
304
+
305
+ #: The data to set.
306
+ data: list[Any] | Any
307
+ #: Which method to use for handling the data, if any.
308
+ value_class_method: list[str | None] | str | None
309
+ #: Whether the value is set.
310
+ is_set: bool | list[bool]
311
+ #: Whether the value is multiple.
312
+ is_multi: bool
313
+
314
+
315
+ class CreationInfo(TypedDict):
316
+ """
317
+ Descriptor for creation information about a workflow.
318
+ """
319
+
320
+ #: Description of information about the application.
321
+ app_info: dict[str, Any]
322
+ #: When the workflow was created.
323
+ create_time: datetime
324
+ #: Unique identifier for the workflow.
325
+ id: str
326
+
327
+
328
+ class WorkflowTemplateTaskData(TypedDict):
329
+ """
330
+ Descriptor for information about tasks described in a workflow template.
331
+ """
332
+
333
+ #: The schema, if known.
334
+ schema: NotRequired[Any | list[Any]]
335
+ #: The element sets, if known.
336
+ element_sets: NotRequired[list["WorkflowTemplateTaskData"]]
337
+ #: The output labels, if known.
338
+ output_labels: NotRequired[list[str]]
339
+
340
+
341
+ class Pending(TypedDict):
342
+ """
343
+ Pending update information. Internal use only.
344
+ """
345
+
346
+ #: Template components to update.
347
+ template_components: dict[str, list[int]]
348
+ #: Tasks to update.
349
+ tasks: list[int]
350
+ #: Loops to update.
351
+ loops: list[int]
352
+ #: Submissions to update.
353
+ submissions: list[int]
354
+
355
+
356
+ class AbstractFileSystem(Protocol):
357
+ """
358
+ Type constraints for an abstract file system.
359
+ """
360
+
361
+ # Because a dependency is not fully typed...
362
+ def exists(self, path: str) -> bool:
363
+ """Test if a path points to a file or directory that exists."""
364
+
365
+ def rename(self, from_: str, to: str, *, recursive: bool = False) -> None:
366
+ """Rename a file or directory."""
367
+
368
+ def rm(self, path: str, *, recursive: bool = False) -> None:
369
+ """Delete a file or directory."""
370
+
371
+ def glob(self, pattern: str) -> list[str]:
372
+ """List files in a directory that match a pattern."""
373
+
374
+
375
+ class ResourcePersistingWorkflow(Protocol):
376
+ """
377
+ An object to pass to :py:meth:`ResourceSpec.make_persistent` that handles
378
+ persisting resources.
379
+ """
380
+
381
+ def _add_parameter_data(self, data: Any, source: ParamSource) -> int:
382
+ ...
383
+
384
+ def check_parameters_exist(self, id_lst: int | list[int]) -> bool:
385
+ """
386
+ Check if all the parameters exist.
387
+ """