hpcflow-new2 0.2.0a188__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.
- hpcflow/__pyinstaller/hook-hpcflow.py +8 -6
- hpcflow/_version.py +1 -1
- hpcflow/app.py +1 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +1 -1
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
- hpcflow/sdk/__init__.py +21 -15
- hpcflow/sdk/app.py +2133 -770
- hpcflow/sdk/cli.py +281 -250
- hpcflow/sdk/cli_common.py +6 -2
- hpcflow/sdk/config/__init__.py +1 -1
- hpcflow/sdk/config/callbacks.py +77 -42
- hpcflow/sdk/config/cli.py +126 -103
- hpcflow/sdk/config/config.py +578 -311
- hpcflow/sdk/config/config_file.py +131 -95
- hpcflow/sdk/config/errors.py +112 -85
- hpcflow/sdk/config/types.py +145 -0
- hpcflow/sdk/core/actions.py +1054 -994
- hpcflow/sdk/core/app_aware.py +24 -0
- hpcflow/sdk/core/cache.py +81 -63
- hpcflow/sdk/core/command_files.py +275 -185
- hpcflow/sdk/core/commands.py +111 -107
- hpcflow/sdk/core/element.py +724 -503
- hpcflow/sdk/core/enums.py +192 -0
- hpcflow/sdk/core/environment.py +74 -93
- hpcflow/sdk/core/errors.py +398 -51
- hpcflow/sdk/core/json_like.py +540 -272
- hpcflow/sdk/core/loop.py +380 -334
- hpcflow/sdk/core/loop_cache.py +160 -43
- hpcflow/sdk/core/object_list.py +370 -207
- hpcflow/sdk/core/parameters.py +728 -600
- hpcflow/sdk/core/rule.py +59 -41
- hpcflow/sdk/core/run_dir_files.py +33 -22
- hpcflow/sdk/core/task.py +1546 -1325
- hpcflow/sdk/core/task_schema.py +240 -196
- hpcflow/sdk/core/test_utils.py +126 -88
- hpcflow/sdk/core/types.py +387 -0
- hpcflow/sdk/core/utils.py +410 -305
- hpcflow/sdk/core/validation.py +82 -9
- hpcflow/sdk/core/workflow.py +1192 -1028
- hpcflow/sdk/core/zarr_io.py +98 -137
- hpcflow/sdk/demo/cli.py +46 -33
- hpcflow/sdk/helper/cli.py +18 -16
- hpcflow/sdk/helper/helper.py +75 -63
- hpcflow/sdk/helper/watcher.py +61 -28
- hpcflow/sdk/log.py +83 -59
- hpcflow/sdk/persistence/__init__.py +8 -31
- hpcflow/sdk/persistence/base.py +988 -586
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +38 -0
- hpcflow/sdk/persistence/json.py +408 -153
- hpcflow/sdk/persistence/pending.py +158 -123
- hpcflow/sdk/persistence/store_resource.py +37 -22
- hpcflow/sdk/persistence/types.py +307 -0
- hpcflow/sdk/persistence/utils.py +14 -11
- hpcflow/sdk/persistence/zarr.py +477 -420
- hpcflow/sdk/runtime.py +44 -41
- hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
- hpcflow/sdk/submission/jobscript.py +444 -404
- hpcflow/sdk/submission/schedulers/__init__.py +133 -40
- hpcflow/sdk/submission/schedulers/direct.py +97 -71
- hpcflow/sdk/submission/schedulers/sge.py +132 -126
- hpcflow/sdk/submission/schedulers/slurm.py +263 -268
- hpcflow/sdk/submission/schedulers/utils.py +7 -2
- hpcflow/sdk/submission/shells/__init__.py +14 -15
- hpcflow/sdk/submission/shells/base.py +102 -29
- hpcflow/sdk/submission/shells/bash.py +72 -55
- hpcflow/sdk/submission/shells/os_version.py +31 -30
- hpcflow/sdk/submission/shells/powershell.py +37 -29
- hpcflow/sdk/submission/submission.py +203 -257
- hpcflow/sdk/submission/types.py +143 -0
- hpcflow/sdk/typing.py +163 -12
- hpcflow/tests/conftest.py +8 -6
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
- hpcflow/tests/scripts/test_main_scripts.py +60 -30
- hpcflow/tests/shells/wsl/test_wsl_submission.py +6 -4
- hpcflow/tests/unit/test_action.py +86 -75
- hpcflow/tests/unit/test_action_rule.py +9 -4
- hpcflow/tests/unit/test_app.py +13 -6
- hpcflow/tests/unit/test_cli.py +1 -1
- hpcflow/tests/unit/test_command.py +71 -54
- hpcflow/tests/unit/test_config.py +20 -15
- hpcflow/tests/unit/test_config_file.py +21 -18
- hpcflow/tests/unit/test_element.py +58 -62
- hpcflow/tests/unit/test_element_iteration.py +3 -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_json_like.py +44 -35
- hpcflow/tests/unit/test_loop.py +65 -58
- hpcflow/tests/unit/test_object_list.py +17 -12
- hpcflow/tests/unit/test_parameter.py +16 -7
- hpcflow/tests/unit/test_persistence.py +48 -35
- hpcflow/tests/unit/test_resources.py +20 -18
- hpcflow/tests/unit/test_run.py +8 -3
- hpcflow/tests/unit/test_runtime.py +2 -1
- hpcflow/tests/unit/test_schema_input.py +23 -15
- hpcflow/tests/unit/test_shell.py +3 -2
- hpcflow/tests/unit/test_slurm.py +8 -7
- hpcflow/tests/unit/test_submission.py +39 -19
- 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/workflows/test_jobscript.py +2 -1
- hpcflow/tests/workflows/test_workflows.py +18 -13
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/METADATA +2 -1
- hpcflow_new2-0.2.0a190.dist-info/RECORD +165 -0
- hpcflow/sdk/core/parallel.py +0 -21
- hpcflow_new2-0.2.0a188.dist-info/RECORD +0 -158
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/entry_points.txt +0 -0
@@ -7,15 +7,33 @@ from __future__ import annotations
|
|
7
7
|
from collections import defaultdict
|
8
8
|
import contextlib
|
9
9
|
from dataclasses import dataclass, field, fields
|
10
|
-
from datetime import datetime
|
11
10
|
|
12
|
-
from typing import Any,
|
11
|
+
from typing import Any, Generic, TYPE_CHECKING
|
13
12
|
|
14
13
|
from hpcflow.sdk.log import TimeIt
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
from hpcflow.sdk.persistence.types import (
|
15
|
+
AnySTask,
|
16
|
+
AnySElement,
|
17
|
+
AnySElementIter,
|
18
|
+
AnySEAR,
|
19
|
+
AnySParameter,
|
20
|
+
)
|
21
|
+
|
22
|
+
if TYPE_CHECKING:
|
23
|
+
from collections.abc import Mapping, Sequence
|
24
|
+
from datetime import datetime
|
25
|
+
from logging import Logger
|
26
|
+
from .base import PersistentStore, FileDescriptor, LoopDescriptor
|
27
|
+
from ..app import BaseApp
|
28
|
+
from ..typing import ParamSource
|
29
|
+
from ..core.json_like import JSONDocument
|
30
|
+
|
31
|
+
|
32
|
+
class PendingChanges(
|
33
|
+
Generic[AnySTask, AnySElement, AnySElementIter, AnySEAR, AnySParameter]
|
34
|
+
):
|
35
|
+
"""
|
36
|
+
Class to store pending changes and merge them into a persistent store.
|
19
37
|
|
20
38
|
Parameters
|
21
39
|
----------
|
@@ -27,70 +45,91 @@ class PendingChanges:
|
|
27
45
|
Map of resources, used when processing commits.
|
28
46
|
"""
|
29
47
|
|
30
|
-
|
31
|
-
|
48
|
+
# These would be in the docstring except they render really wrongly!
|
49
|
+
# Type Parameters
|
50
|
+
# ---------------
|
51
|
+
# AnySTask
|
52
|
+
# The type of stored tasks.
|
53
|
+
# AnySElement
|
54
|
+
# The type of stored elements.
|
55
|
+
# AnySElementIter
|
56
|
+
# The type of stored element iterations.
|
57
|
+
# AnySEAR
|
58
|
+
# The type of stored EARs.
|
59
|
+
# AnySParameter
|
60
|
+
# The type of stored parameters.
|
61
|
+
|
62
|
+
def __init__(
|
63
|
+
self,
|
64
|
+
app: BaseApp,
|
65
|
+
store: PersistentStore[
|
66
|
+
AnySTask, AnySElement, AnySElementIter, AnySEAR, AnySParameter
|
67
|
+
],
|
68
|
+
resource_map: CommitResourceMap,
|
69
|
+
):
|
70
|
+
self._app = app
|
32
71
|
self.store = store
|
33
72
|
self.resource_map = resource_map
|
34
73
|
|
35
74
|
#: Keys are new task IDs.
|
36
|
-
self.add_tasks:
|
75
|
+
self.add_tasks: dict[int, AnySTask] = {}
|
37
76
|
#: Keys are loop IDs, values are loop descriptors.
|
38
|
-
self.add_loops:
|
77
|
+
self.add_loops: dict[int, LoopDescriptor] = {}
|
39
78
|
#: Keys are submission IDs, values are submission descriptors.
|
40
|
-
self.add_submissions:
|
79
|
+
self.add_submissions: dict[int, JSONDocument] = {}
|
41
80
|
#: Keys are element IDs.
|
42
|
-
self.add_elements:
|
81
|
+
self.add_elements: dict[int, AnySElement] = {}
|
43
82
|
#: Keys are element iteration IDs.
|
44
|
-
self.add_elem_iters:
|
83
|
+
self.add_elem_iters: dict[int, AnySElementIter] = {}
|
45
84
|
#: Keys are element action run IDs.
|
46
|
-
self.add_EARs:
|
85
|
+
self.add_EARs: dict[int, AnySEAR] = {}
|
47
86
|
#: Keys are parameter indices and values are tuples whose first element is data
|
48
87
|
#: to add and whose second element is the source dict for the new data.
|
49
|
-
self.add_parameters:
|
88
|
+
self.add_parameters: dict[int, AnySParameter] = {}
|
50
89
|
#: Workflow-related files (inputs, outputs) added to the persistent store.
|
51
|
-
self.add_files:
|
90
|
+
self.add_files: list[FileDescriptor] = []
|
52
91
|
#: Template components to add.
|
53
|
-
self.add_template_components:
|
92
|
+
self.add_template_components: dict[str, dict[str, dict]] = {}
|
54
93
|
#: Keys are element set IDs, values are descriptors.
|
55
|
-
self.add_element_sets:
|
94
|
+
self.add_element_sets: dict[int, list[Mapping]] = {}
|
56
95
|
|
57
96
|
#: Keys are task IDs, and values are element IDs to add to that task.
|
58
|
-
self.add_elem_IDs:
|
97
|
+
self.add_elem_IDs: dict[int, list[int]] = {}
|
59
98
|
#: Keys are element IDs, and values are iteration IDs to add to that element.
|
60
|
-
self.add_elem_iter_IDs:
|
99
|
+
self.add_elem_iter_IDs: dict[int, list[int]] = {}
|
61
100
|
#: Keys are element iteration IDs, then EAR action index, and values are EAR IDs.
|
62
101
|
#: This is a list of EAR IDs to add to a given element iteration action.
|
63
|
-
self.add_elem_iter_EAR_IDs:
|
102
|
+
self.add_elem_iter_EAR_IDs: dict[int, dict[int, list[int]]] = {}
|
64
103
|
#: Submission parts to add.
|
65
|
-
self.add_submission_parts:
|
104
|
+
self.add_submission_parts: dict[int, dict[str, list[int]]] = {}
|
66
105
|
|
67
106
|
#: IDs of EARs to mark as initialised.
|
68
|
-
self.set_EARs_initialised:
|
107
|
+
self.set_EARs_initialised: list[int] = []
|
69
108
|
#: Submission IDs to attach to EARs.
|
70
|
-
self.set_EAR_submission_indices:
|
109
|
+
self.set_EAR_submission_indices: dict[int, int] = {}
|
71
110
|
#: IDs of EARs to mark as skipped.
|
72
|
-
self.set_EAR_skips:
|
111
|
+
self.set_EAR_skips: list[int] = []
|
73
112
|
#: Keys are EAR IDs and values are tuples of start time, and start dir snapshot.
|
74
|
-
self.set_EAR_starts:
|
113
|
+
self.set_EAR_starts: dict[int, tuple[datetime, dict[str, Any], str]] = {}
|
75
114
|
#: Keys are EAR IDs and values are tuples of end time, end dir snapshot, exit
|
76
115
|
#: code, and success boolean.
|
77
|
-
self.set_EAR_ends:
|
116
|
+
self.set_EAR_ends: dict[int, tuple[datetime, dict[str, Any], int, bool]] = {}
|
78
117
|
|
79
118
|
#: Keys are IDs of jobscripts.
|
80
|
-
self.set_js_metadata:
|
119
|
+
self.set_js_metadata: dict[int, dict[int, dict[str, Any]]] = {}
|
81
120
|
|
82
121
|
#: Keys are IDs of parameters to add or modify.
|
83
|
-
self.set_parameters:
|
122
|
+
self.set_parameters: dict[int, tuple[Any, bool]] = {}
|
84
123
|
|
85
124
|
#: Keys are parameter indices and values are dict parameter sources to merge
|
86
125
|
#: with existing source of that parameter.
|
87
|
-
self.update_param_sources:
|
126
|
+
self.update_param_sources: dict[int, ParamSource] = {}
|
88
127
|
#: Keys are indices of loops, values are descriptions of what to update.
|
89
|
-
self.update_loop_indices:
|
128
|
+
self.update_loop_indices: dict[int, dict[str, int]] = {}
|
90
129
|
#: Keys are indices of loops, values are number of iterations.
|
91
|
-
self.update_loop_num_iters:
|
130
|
+
self.update_loop_num_iters: dict[int, list[list[list[int] | int]]] = {}
|
92
131
|
#: Keys are indices of loops, values are list of parent names.
|
93
|
-
self.update_loop_parents:
|
132
|
+
self.update_loop_parents: dict[int, list[str]] = {}
|
94
133
|
|
95
134
|
self.reset(is_init=True) # set up initial data structures
|
96
135
|
|
@@ -124,25 +163,22 @@ class PendingChanges:
|
|
124
163
|
or bool(self.update_loop_parents)
|
125
164
|
)
|
126
165
|
|
127
|
-
def where_pending(self) ->
|
166
|
+
def where_pending(self) -> list[str]:
|
128
167
|
"""
|
129
168
|
Get the list of items for which there is some outstanding pending items.
|
130
169
|
"""
|
131
|
-
|
132
|
-
|
133
|
-
for k, v in self.__dict__.items()
|
134
|
-
if k not in ("app", "store", "resource_map") and bool(v)
|
135
|
-
]
|
170
|
+
excluded = {"app", "store", "resource_map"}
|
171
|
+
return [k for k, v in self.__dict__.items() if k not in excluded and bool(v)]
|
136
172
|
|
137
173
|
@property
|
138
|
-
def logger(self):
|
174
|
+
def logger(self) -> Logger:
|
139
175
|
"""
|
140
176
|
The logger.
|
141
177
|
"""
|
142
|
-
return self.
|
178
|
+
return self._app.persistence_logger
|
143
179
|
|
144
180
|
@TimeIt.decorator
|
145
|
-
def commit_all(self):
|
181
|
+
def commit_all(self) -> None:
|
146
182
|
"""Commit all pending changes to disk."""
|
147
183
|
self.logger.info(f"committing all pending changes: {self.where_pending()}")
|
148
184
|
|
@@ -155,7 +191,9 @@ class PendingChanges:
|
|
155
191
|
with contextlib.ExitStack() as stack:
|
156
192
|
for res in resources:
|
157
193
|
# TODO: only enter required resources!
|
158
|
-
stack.enter_context(
|
194
|
+
stack.enter_context(
|
195
|
+
self.store.using_resource(res, "update") # type: ignore[call-overload]
|
196
|
+
)
|
159
197
|
for meth in methods:
|
160
198
|
getattr(self, meth)()
|
161
199
|
|
@@ -166,7 +204,7 @@ class PendingChanges:
|
|
166
204
|
"""Commit pending tasks to disk."""
|
167
205
|
if self.add_tasks:
|
168
206
|
tasks = self.store.get_tasks_by_IDs(self.add_tasks)
|
169
|
-
task_ids =
|
207
|
+
task_ids = set(self.add_tasks)
|
170
208
|
self.logger.debug(f"commit: adding pending tasks with IDs: {task_ids!r}")
|
171
209
|
self.store._append_tasks(tasks)
|
172
210
|
self.store.num_tasks_cache = None # invalidate cache
|
@@ -182,7 +220,7 @@ class PendingChanges:
|
|
182
220
|
if self.add_loops:
|
183
221
|
# retrieve pending loops, including pending changes to num_added_iterations:
|
184
222
|
loops = self.store.get_loops_by_IDs(self.add_loops)
|
185
|
-
loop_ids =
|
223
|
+
loop_ids = set(self.add_loops)
|
186
224
|
self.logger.debug(f"commit: adding pending loops with indices {loop_ids!r}")
|
187
225
|
self.store._append_loops(loops)
|
188
226
|
|
@@ -203,7 +241,7 @@ class PendingChanges:
|
|
203
241
|
if self.add_submissions:
|
204
242
|
# retrieve pending submissions:
|
205
243
|
subs = self.store.get_submissions_by_ID(self.add_submissions)
|
206
|
-
sub_ids =
|
244
|
+
sub_ids = set(self.add_submissions)
|
207
245
|
self.logger.debug(
|
208
246
|
f"commit: adding pending submissions with indices {sub_ids!r}"
|
209
247
|
)
|
@@ -216,7 +254,7 @@ class PendingChanges:
|
|
216
254
|
Commit pending submission parts to disk.
|
217
255
|
"""
|
218
256
|
if self.add_submission_parts:
|
219
|
-
self.logger.debug(
|
257
|
+
self.logger.debug("commit: adding pending submission parts")
|
220
258
|
self.store._append_submission_parts(self.add_submission_parts)
|
221
259
|
self._clear_add_submission_parts()
|
222
260
|
|
@@ -241,7 +279,7 @@ class PendingChanges:
|
|
241
279
|
"""
|
242
280
|
if self.add_elements:
|
243
281
|
elems = self.store.get_elements(self.add_elements)
|
244
|
-
elem_ids =
|
282
|
+
elem_ids = set(self.add_elements)
|
245
283
|
self.logger.debug(f"commit: adding pending elements with IDs: {elem_ids!r}")
|
246
284
|
self.store._append_elements(elems)
|
247
285
|
# pending iter IDs that belong to pending elements are now committed:
|
@@ -257,7 +295,7 @@ class PendingChanges:
|
|
257
295
|
"""
|
258
296
|
# TODO: could be batched up?
|
259
297
|
for task_id, es_js in self.add_element_sets.items():
|
260
|
-
self.logger.debug(
|
298
|
+
self.logger.debug("commit: adding pending element sets.")
|
261
299
|
self.store._append_element_sets(task_id, es_js)
|
262
300
|
self._clear_add_element_sets()
|
263
301
|
|
@@ -282,8 +320,8 @@ class PendingChanges:
|
|
282
320
|
Commit pending element iterations to disk.
|
283
321
|
"""
|
284
322
|
if self.add_elem_iters:
|
285
|
-
iters = self.store.get_element_iterations(self.add_elem_iters
|
286
|
-
iter_ids =
|
323
|
+
iters = self.store.get_element_iterations(self.add_elem_iters)
|
324
|
+
iter_ids = set(self.add_elem_iters)
|
287
325
|
self.logger.debug(
|
288
326
|
f"commit: adding pending element iterations with IDs: {iter_ids!r}"
|
289
327
|
)
|
@@ -321,7 +359,7 @@ class PendingChanges:
|
|
321
359
|
"""
|
322
360
|
if self.add_EARs:
|
323
361
|
EARs = self.store.get_EARs(self.add_EARs)
|
324
|
-
EAR_ids = list(self.add_EARs
|
362
|
+
EAR_ids = list(self.add_EARs)
|
325
363
|
self.logger.debug(f"commit: adding pending EARs with IDs: {EAR_ids!r}")
|
326
364
|
self.store._append_EARs(EARs)
|
327
365
|
self.store.num_EARs_cache = None # invalidate cache
|
@@ -370,7 +408,7 @@ class PendingChanges:
|
|
370
408
|
f"{self.set_EAR_submission_indices!r}."
|
371
409
|
)
|
372
410
|
self.store._update_EAR_submission_indices(self.set_EAR_submission_indices)
|
373
|
-
for EAR_ID_i in self.set_EAR_submission_indices
|
411
|
+
for EAR_ID_i in self.set_EAR_submission_indices:
|
374
412
|
self.store.EAR_cache.pop(EAR_ID_i, None) # invalidate cache
|
375
413
|
self._clear_set_EAR_submission_indices()
|
376
414
|
|
@@ -433,25 +471,24 @@ class PendingChanges:
|
|
433
471
|
"""Make pending parameters persistent."""
|
434
472
|
if self.add_parameters:
|
435
473
|
params = self.store.get_parameters(self.add_parameters)
|
436
|
-
param_ids = list(self.add_parameters
|
474
|
+
param_ids = list(self.add_parameters)
|
437
475
|
self.logger.debug(f"commit: adding pending parameters IDs: {param_ids!r}")
|
438
476
|
self.store._append_parameters(params)
|
439
477
|
self._clear_add_parameters()
|
440
478
|
|
441
479
|
if self.set_parameters:
|
442
|
-
param_ids = list(self.set_parameters
|
480
|
+
param_ids = list(self.set_parameters)
|
443
481
|
self.logger.debug(f"commit: setting values of parameter IDs {param_ids!r}.")
|
444
482
|
self.store._set_parameter_values(self.set_parameters)
|
445
483
|
for id_i in param_ids:
|
446
484
|
self.store.parameter_cache.pop(id_i, None)
|
447
|
-
|
448
485
|
self._clear_set_parameters()
|
449
486
|
|
450
487
|
@TimeIt.decorator
|
451
488
|
def commit_files(self) -> None:
|
452
489
|
"""Add pending files to the files directory."""
|
453
490
|
if self.add_files:
|
454
|
-
self.logger.debug(
|
491
|
+
self.logger.debug("commit: adding pending files to the files directory.")
|
455
492
|
self.store._append_files(self.add_files)
|
456
493
|
self._clear_add_files()
|
457
494
|
|
@@ -461,7 +498,7 @@ class PendingChanges:
|
|
461
498
|
Commit pending template components to disk.
|
462
499
|
"""
|
463
500
|
if self.add_template_components:
|
464
|
-
self.logger.debug(
|
501
|
+
self.logger.debug("commit: adding template components.")
|
465
502
|
self.store._update_template_components(self.store.get_template_components())
|
466
503
|
self._clear_add_template_components()
|
467
504
|
|
@@ -469,7 +506,7 @@ class PendingChanges:
|
|
469
506
|
def commit_param_sources(self) -> None:
|
470
507
|
"""Make pending changes to parameter sources persistent."""
|
471
508
|
if self.update_param_sources:
|
472
|
-
param_ids = list(self.update_param_sources
|
509
|
+
param_ids = list(self.update_param_sources)
|
473
510
|
self.logger.debug(f"commit: updating sources of parameter IDs {param_ids!r}.")
|
474
511
|
self.store._update_parameter_sources(self.update_param_sources)
|
475
512
|
for id_i in param_ids:
|
@@ -507,82 +544,82 @@ class PendingChanges:
|
|
507
544
|
self.store._update_loop_parents(index, parents)
|
508
545
|
self._clear_update_loop_parents()
|
509
546
|
|
510
|
-
def _clear_add_tasks(self):
|
547
|
+
def _clear_add_tasks(self) -> None:
|
511
548
|
self.add_tasks = {}
|
512
549
|
|
513
|
-
def _clear_add_loops(self):
|
550
|
+
def _clear_add_loops(self) -> None:
|
514
551
|
self.add_loops = {}
|
515
552
|
|
516
|
-
def _clear_add_submissions(self):
|
553
|
+
def _clear_add_submissions(self) -> None:
|
517
554
|
self.add_submissions = {}
|
518
555
|
|
519
|
-
def _clear_add_submission_parts(self):
|
556
|
+
def _clear_add_submission_parts(self) -> None:
|
520
557
|
self.add_submission_parts = defaultdict(dict)
|
521
558
|
|
522
|
-
def _clear_add_elements(self):
|
559
|
+
def _clear_add_elements(self) -> None:
|
523
560
|
self.add_elements = {}
|
524
561
|
|
525
|
-
def _clear_add_element_sets(self):
|
562
|
+
def _clear_add_element_sets(self) -> None:
|
526
563
|
self.add_element_sets = defaultdict(list)
|
527
564
|
|
528
|
-
def _clear_add_elem_iters(self):
|
565
|
+
def _clear_add_elem_iters(self) -> None:
|
529
566
|
self.add_elem_iters = {}
|
530
567
|
|
531
|
-
def _clear_add_EARs(self):
|
568
|
+
def _clear_add_EARs(self) -> None:
|
532
569
|
self.add_EARs = {}
|
533
570
|
|
534
|
-
def _clear_add_elem_IDs(self):
|
571
|
+
def _clear_add_elem_IDs(self) -> None:
|
535
572
|
self.add_elem_IDs = defaultdict(list)
|
536
573
|
|
537
|
-
def _clear_add_elem_iter_IDs(self):
|
574
|
+
def _clear_add_elem_iter_IDs(self) -> None:
|
538
575
|
self.add_elem_iter_IDs = defaultdict(list)
|
539
576
|
|
540
|
-
def _clear_add_elem_iter_EAR_IDs(self):
|
577
|
+
def _clear_add_elem_iter_EAR_IDs(self) -> None:
|
541
578
|
self.add_elem_iter_EAR_IDs = defaultdict(lambda: defaultdict(list))
|
542
579
|
|
543
|
-
def _clear_set_EARs_initialised(self):
|
580
|
+
def _clear_set_EARs_initialised(self) -> None:
|
544
581
|
self.set_EARs_initialised = []
|
545
582
|
|
546
|
-
def _clear_set_EAR_submission_indices(self):
|
583
|
+
def _clear_set_EAR_submission_indices(self) -> None:
|
547
584
|
self.set_EAR_submission_indices = {}
|
548
585
|
|
549
|
-
def _clear_set_EAR_starts(self):
|
586
|
+
def _clear_set_EAR_starts(self) -> None:
|
550
587
|
self.set_EAR_starts = {}
|
551
588
|
|
552
|
-
def _clear_set_EAR_ends(self):
|
589
|
+
def _clear_set_EAR_ends(self) -> None:
|
553
590
|
self.set_EAR_ends = {}
|
554
591
|
|
555
|
-
def _clear_set_EAR_skips(self):
|
592
|
+
def _clear_set_EAR_skips(self) -> None:
|
556
593
|
self.set_EAR_skips = []
|
557
594
|
|
558
|
-
def _clear_set_js_metadata(self):
|
595
|
+
def _clear_set_js_metadata(self) -> None:
|
559
596
|
self.set_js_metadata = defaultdict(lambda: defaultdict(dict))
|
560
597
|
|
561
|
-
def _clear_add_parameters(self):
|
598
|
+
def _clear_add_parameters(self) -> None:
|
562
599
|
self.add_parameters = {}
|
563
600
|
|
564
|
-
def _clear_add_files(self):
|
601
|
+
def _clear_add_files(self) -> None:
|
565
602
|
self.add_files = []
|
566
603
|
|
567
|
-
def _clear_add_template_components(self):
|
604
|
+
def _clear_add_template_components(self) -> None:
|
568
605
|
self.add_template_components = defaultdict(dict)
|
569
606
|
|
570
|
-
def _clear_set_parameters(self):
|
607
|
+
def _clear_set_parameters(self) -> None:
|
571
608
|
self.set_parameters = {}
|
572
609
|
|
573
|
-
def _clear_update_param_sources(self):
|
610
|
+
def _clear_update_param_sources(self) -> None:
|
574
611
|
self.update_param_sources = {}
|
575
612
|
|
576
|
-
def _clear_update_loop_indices(self):
|
613
|
+
def _clear_update_loop_indices(self) -> None:
|
577
614
|
self.update_loop_indices = defaultdict(dict)
|
578
615
|
|
579
|
-
def _clear_update_loop_num_iters(self):
|
616
|
+
def _clear_update_loop_num_iters(self) -> None:
|
580
617
|
self.update_loop_num_iters = {}
|
581
618
|
|
582
|
-
def _clear_update_loop_parents(self):
|
619
|
+
def _clear_update_loop_parents(self) -> None:
|
583
620
|
self.update_loop_parents = {}
|
584
621
|
|
585
|
-
def reset(self, is_init=False) -> None:
|
622
|
+
def reset(self, is_init: bool = False) -> None:
|
586
623
|
"""Clear all pending data and prepare to accept new pending data."""
|
587
624
|
|
588
625
|
if not is_init and not self:
|
@@ -640,65 +677,67 @@ class CommitResourceMap:
|
|
640
677
|
"""
|
641
678
|
|
642
679
|
#: Resources for :py:meth:`~.PendingChanges.commit_tasks`.
|
643
|
-
commit_tasks:
|
680
|
+
commit_tasks: tuple[str, ...] | None = tuple()
|
644
681
|
#: Resources for :py:meth:`~.PendingChanges.commit_loops`.
|
645
|
-
commit_loops:
|
682
|
+
commit_loops: tuple[str, ...] | None = tuple()
|
646
683
|
#: Resources for :py:meth:`~.PendingChanges.commit_submissions`.
|
647
|
-
commit_submissions:
|
684
|
+
commit_submissions: tuple[str, ...] | None = tuple()
|
648
685
|
#: Resources for :py:meth:`~.PendingChanges.commit_submission_parts`.
|
649
|
-
commit_submission_parts:
|
686
|
+
commit_submission_parts: tuple[str, ...] | None = tuple()
|
650
687
|
#: Resources for :py:meth:`~.PendingChanges.commit_elem_IDs`.
|
651
|
-
commit_elem_IDs:
|
688
|
+
commit_elem_IDs: tuple[str, ...] | None = tuple()
|
652
689
|
#: Resources for :py:meth:`~.PendingChanges.commit_elements`.
|
653
|
-
commit_elements:
|
690
|
+
commit_elements: tuple[str, ...] | None = tuple()
|
654
691
|
#: Resources for :py:meth:`~.PendingChanges.commit_element_sets`.
|
655
|
-
commit_element_sets:
|
692
|
+
commit_element_sets: tuple[str, ...] | None = tuple()
|
656
693
|
#: Resources for :py:meth:`~.PendingChanges.commit_elem_iter_IDs`.
|
657
|
-
commit_elem_iter_IDs:
|
694
|
+
commit_elem_iter_IDs: tuple[str, ...] | None = tuple()
|
658
695
|
#: Resources for :py:meth:`~.PendingChanges.commit_elem_iters`.
|
659
|
-
commit_elem_iters:
|
696
|
+
commit_elem_iters: tuple[str, ...] | None = tuple()
|
660
697
|
#: Resources for :py:meth:`~.PendingChanges.commit_elem_iter_EAR_IDs`.
|
661
|
-
commit_elem_iter_EAR_IDs:
|
698
|
+
commit_elem_iter_EAR_IDs: tuple[str, ...] | None = tuple()
|
662
699
|
#: Resources for :py:meth:`~.PendingChanges.commit_EARs_initialised`.
|
663
|
-
commit_EARs_initialised:
|
700
|
+
commit_EARs_initialised: tuple[str, ...] | None = tuple()
|
664
701
|
#: Resources for :py:meth:`~.PendingChanges.commit_EARs`.
|
665
|
-
commit_EARs:
|
702
|
+
commit_EARs: tuple[str, ...] | None = tuple()
|
666
703
|
#: Resources for :py:meth:`~.PendingChanges.commit_EAR_submission_indices`.
|
667
|
-
commit_EAR_submission_indices:
|
704
|
+
commit_EAR_submission_indices: tuple[str, ...] | None = tuple()
|
668
705
|
#: Resources for :py:meth:`~.PendingChanges.commit_EAR_skips`.
|
669
|
-
commit_EAR_skips:
|
706
|
+
commit_EAR_skips: tuple[str, ...] | None = tuple()
|
670
707
|
#: Resources for :py:meth:`~.PendingChanges.commit_EAR_starts`.
|
671
|
-
commit_EAR_starts:
|
708
|
+
commit_EAR_starts: tuple[str, ...] | None = tuple()
|
672
709
|
#: Resources for :py:meth:`~.PendingChanges.commit_EAR_ends`.
|
673
|
-
commit_EAR_ends:
|
710
|
+
commit_EAR_ends: tuple[str, ...] | None = tuple()
|
674
711
|
#: Resources for :py:meth:`~.PendingChanges.commit_js_metadata`.
|
675
|
-
commit_js_metadata:
|
712
|
+
commit_js_metadata: tuple[str, ...] | None = tuple()
|
676
713
|
#: Resources for :py:meth:`~.PendingChanges.commit_parameters`.
|
677
|
-
commit_parameters:
|
714
|
+
commit_parameters: tuple[str, ...] | None = tuple()
|
678
715
|
#: Resources for :py:meth:`~.PendingChanges.commit_files`.
|
679
|
-
commit_files:
|
716
|
+
commit_files: tuple[str, ...] | None = tuple()
|
680
717
|
#: Resources for :py:meth:`~.PendingChanges.commit_template_components`.
|
681
|
-
commit_template_components:
|
718
|
+
commit_template_components: tuple[str, ...] | None = tuple()
|
682
719
|
#: Resources for :py:meth:`~.PendingChanges.commit_param_sources`.
|
683
|
-
commit_param_sources:
|
720
|
+
commit_param_sources: tuple[str, ...] | None = tuple()
|
684
721
|
#: Resources for :py:meth:`~.PendingChanges.commit_loop_indices`.
|
685
|
-
commit_loop_indices:
|
722
|
+
commit_loop_indices: tuple[str, ...] | None = tuple()
|
686
723
|
#: Resources for :py:meth:`~.PendingChanges.commit_loop_num_iters`.
|
687
|
-
commit_loop_num_iters:
|
724
|
+
commit_loop_num_iters: tuple[str, ...] | None = tuple()
|
688
725
|
#: Resources for :py:meth:`~.PendingChanges.commit_loop_parents`.
|
689
|
-
commit_loop_parents:
|
726
|
+
commit_loop_parents: tuple[str, ...] | None = tuple()
|
690
727
|
#: A dict whose keys are tuples of resource labels and whose values are lists
|
691
728
|
#: of :py:class:`PendingChanges` commit method names that require those resources.
|
692
729
|
#:
|
693
730
|
#: This grouping allows us to batch up commit methods by resource requirements,
|
694
731
|
#: which in turn means we can potentially minimise, e.g., the number of network
|
695
732
|
#: requests.
|
696
|
-
groups:
|
733
|
+
groups: Mapping[tuple[str, ...], Sequence[str]] = field(
|
734
|
+
init=False, repr=False, compare=False
|
735
|
+
)
|
697
736
|
|
698
737
|
def __post_init__(self):
|
699
738
|
self.groups = self._group_by_resource()
|
700
739
|
|
701
|
-
def _group_by_resource(self) ->
|
740
|
+
def _group_by_resource(self) -> Mapping[tuple[str, ...], Sequence[str]]:
|
702
741
|
"""
|
703
742
|
Get a dict whose keys are tuples of resource labels and whose values are
|
704
743
|
lists of :py:class:`PendingChanges` commit method names that require those
|
@@ -708,8 +747,9 @@ class CommitResourceMap:
|
|
708
747
|
which in turn means we can potentially minimise e.g. the number of network
|
709
748
|
requests.
|
710
749
|
"""
|
711
|
-
groups = {}
|
712
|
-
|
750
|
+
groups: dict[tuple[str, ...], list[str]] = {}
|
751
|
+
# The dicts are pretending to be insertion-ordered sets
|
752
|
+
cur_res_group: tuple[dict[str, None], list[str]] | None = None
|
713
753
|
for fld in fields(self):
|
714
754
|
if not fld.name.startswith("commit_"):
|
715
755
|
continue
|
@@ -718,28 +758,23 @@ class CommitResourceMap:
|
|
718
758
|
if not cur_res_group:
|
719
759
|
# start a new resource group: a mapping between resource labels and the
|
720
760
|
# commit methods that require those resources:
|
721
|
-
cur_res_group =
|
761
|
+
cur_res_group = (dict.fromkeys(res_labels), [fld.name])
|
722
762
|
|
723
763
|
elif not res_labels or set(res_labels).intersection(cur_res_group[0]):
|
724
764
|
# there is some overlap between resource labels required in the current
|
725
765
|
# group and this commit method, so we merge resource labels and add the
|
726
766
|
# new commit method:
|
727
|
-
cur_res_group[0]
|
767
|
+
cur_res_group[0].update(dict.fromkeys(res_labels))
|
728
768
|
cur_res_group[1].append(fld.name)
|
729
769
|
|
730
770
|
else:
|
731
771
|
# no overlap between resource labels required in the current group and
|
732
772
|
# those required by this commit method, so append the current group, and
|
733
773
|
# start a new group for this commit method:
|
734
|
-
|
735
|
-
|
736
|
-
groups[tuple(cur_res_group[0])].extend(cur_res_group[1])
|
737
|
-
cur_res_group = [list(res_labels), [fld.name]]
|
774
|
+
groups.setdefault(tuple(cur_res_group[0]), []).extend(cur_res_group[1])
|
775
|
+
cur_res_group = (dict.fromkeys(res_labels), [fld.name])
|
738
776
|
|
739
777
|
if cur_res_group:
|
740
|
-
|
741
|
-
groups[tuple(cur_res_group[0])] = []
|
742
|
-
|
743
|
-
groups[tuple(cur_res_group[0])].extend(cur_res_group[1])
|
778
|
+
groups.setdefault(tuple(cur_res_group[0]), []).extend(cur_res_group[1])
|
744
779
|
|
745
780
|
return groups
|