hpcflow-new2 0.2.0a179__py3-none-any.whl → 0.2.0a181__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 (70) hide show
  1. hpcflow/_version.py +1 -1
  2. hpcflow/data/demo_data_manifest/__init__.py +3 -0
  3. hpcflow/sdk/__init__.py +4 -1
  4. hpcflow/sdk/app.py +160 -15
  5. hpcflow/sdk/cli.py +14 -0
  6. hpcflow/sdk/cli_common.py +83 -0
  7. hpcflow/sdk/config/__init__.py +4 -0
  8. hpcflow/sdk/config/callbacks.py +25 -2
  9. hpcflow/sdk/config/cli.py +4 -1
  10. hpcflow/sdk/config/config.py +188 -14
  11. hpcflow/sdk/config/config_file.py +91 -3
  12. hpcflow/sdk/config/errors.py +33 -0
  13. hpcflow/sdk/core/__init__.py +2 -0
  14. hpcflow/sdk/core/actions.py +492 -35
  15. hpcflow/sdk/core/cache.py +22 -0
  16. hpcflow/sdk/core/command_files.py +221 -5
  17. hpcflow/sdk/core/commands.py +57 -0
  18. hpcflow/sdk/core/element.py +407 -8
  19. hpcflow/sdk/core/environment.py +92 -0
  20. hpcflow/sdk/core/errors.py +245 -61
  21. hpcflow/sdk/core/json_like.py +72 -14
  22. hpcflow/sdk/core/loop.py +122 -21
  23. hpcflow/sdk/core/loop_cache.py +34 -9
  24. hpcflow/sdk/core/object_list.py +172 -26
  25. hpcflow/sdk/core/parallel.py +14 -0
  26. hpcflow/sdk/core/parameters.py +478 -25
  27. hpcflow/sdk/core/rule.py +31 -1
  28. hpcflow/sdk/core/run_dir_files.py +12 -2
  29. hpcflow/sdk/core/task.py +407 -80
  30. hpcflow/sdk/core/task_schema.py +70 -9
  31. hpcflow/sdk/core/test_utils.py +35 -0
  32. hpcflow/sdk/core/utils.py +101 -4
  33. hpcflow/sdk/core/validation.py +13 -1
  34. hpcflow/sdk/core/workflow.py +316 -96
  35. hpcflow/sdk/core/zarr_io.py +23 -0
  36. hpcflow/sdk/data/__init__.py +13 -0
  37. hpcflow/sdk/demo/__init__.py +3 -0
  38. hpcflow/sdk/helper/__init__.py +3 -0
  39. hpcflow/sdk/helper/cli.py +9 -0
  40. hpcflow/sdk/helper/helper.py +28 -0
  41. hpcflow/sdk/helper/watcher.py +33 -0
  42. hpcflow/sdk/log.py +40 -0
  43. hpcflow/sdk/persistence/__init__.py +14 -4
  44. hpcflow/sdk/persistence/base.py +289 -23
  45. hpcflow/sdk/persistence/json.py +29 -0
  46. hpcflow/sdk/persistence/pending.py +217 -107
  47. hpcflow/sdk/persistence/store_resource.py +58 -2
  48. hpcflow/sdk/persistence/utils.py +8 -0
  49. hpcflow/sdk/persistence/zarr.py +68 -1
  50. hpcflow/sdk/runtime.py +52 -10
  51. hpcflow/sdk/submission/__init__.py +3 -0
  52. hpcflow/sdk/submission/jobscript.py +198 -9
  53. hpcflow/sdk/submission/jobscript_info.py +13 -0
  54. hpcflow/sdk/submission/schedulers/__init__.py +60 -0
  55. hpcflow/sdk/submission/schedulers/direct.py +53 -0
  56. hpcflow/sdk/submission/schedulers/sge.py +45 -7
  57. hpcflow/sdk/submission/schedulers/slurm.py +45 -8
  58. hpcflow/sdk/submission/schedulers/utils.py +4 -0
  59. hpcflow/sdk/submission/shells/__init__.py +11 -1
  60. hpcflow/sdk/submission/shells/base.py +32 -1
  61. hpcflow/sdk/submission/shells/bash.py +36 -1
  62. hpcflow/sdk/submission/shells/os_version.py +18 -6
  63. hpcflow/sdk/submission/shells/powershell.py +22 -0
  64. hpcflow/sdk/submission/submission.py +88 -3
  65. hpcflow/sdk/typing.py +10 -1
  66. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/METADATA +3 -3
  67. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/RECORD +70 -70
  68. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/LICENSE +0 -0
  69. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/WHEEL +0 -0
  70. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a181.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,8 @@
1
- # Store* classes represent the element-metadata in the store, in a store-agnostic way
1
+ """
2
+ Base persistence models.
3
+
4
+ Store* classes represent the element-metadata in the store, in a store-agnostic way.
5
+ """
2
6
  from __future__ import annotations
3
7
  from abc import ABC
4
8
 
@@ -50,46 +54,81 @@ PARAM_DATA_NOT_SET = 0
50
54
 
51
55
 
52
56
  def update_param_source_dict(source, update):
57
+ """
58
+ Combine two dicts into a new dict that is ordered on its keys.
59
+ """
53
60
  return dict(sorted({**source, **update}.items()))
54
61
 
55
62
 
56
63
  @dataclass
57
64
  class PersistentStoreFeatures:
58
- """Class to represent the features provided by a persistent store.
65
+ """
66
+ Represents the features provided by a persistent store.
59
67
 
60
68
  Parameters
61
69
  ----------
62
- create
70
+ create:
63
71
  If True, a new workflow can be created using this store.
64
- edit
72
+ edit:
65
73
  If True, the workflow can be modified.
66
- jobscript_parallelism
74
+ jobscript_parallelism:
67
75
  If True, the store supports workflows running multiple independent jobscripts
68
76
  simultaneously.
69
- EAR_parallelism
77
+ EAR_parallelism:
70
78
  If True, the store supports workflows running multiple EARs simultaneously.
71
- schedulers
72
- If True, the store supports submitting workflows to a scheduler
73
- submission
79
+ schedulers:
80
+ If True, the store supports submitting workflows to a scheduler.
81
+ submission:
74
82
  If True, the store supports submission. If False, the store can be considered to
75
83
  be an archive, which would need transforming to another store type before
76
84
  submission.
77
85
  """
78
86
 
87
+ #: Whether a new workflow can be created using this store.
79
88
  create: bool = False
89
+ #: Whether the workflow can be modified.
80
90
  edit: bool = False
91
+ #: Whetherthe store supports workflows running multiple independent jobscripts
92
+ #: simultaneously.
81
93
  jobscript_parallelism: bool = False
94
+ #: Whether the store supports workflows running multiple EARs simultaneously.
82
95
  EAR_parallelism: bool = False
96
+ #: Whether the store supports submitting workflows to a scheduler.
83
97
  schedulers: bool = False
98
+ #: Whether the store supports submission. If not, the store can be considered to
99
+ #: be an archive, which would need transforming to another store type before
100
+ #: submission.
84
101
  submission: bool = False
85
102
 
86
103
 
87
104
  @dataclass
88
105
  class StoreTask:
106
+ """
107
+ Represents a task in a persistent store.
108
+
109
+ Parameters
110
+ ----------
111
+ id_:
112
+ The ID of the task.
113
+ index:
114
+ The index of the task within its workflow.
115
+ is_pending:
116
+ Whether the task has changes not yet persisted.
117
+ element_IDs:
118
+ The IDs of elements in the task.
119
+ task_template:
120
+ Description of the template for the task.
121
+ """
122
+
123
+ #: The ID of the task.
89
124
  id_: int
125
+ #: The index of the task within its workflow.
90
126
  index: int
127
+ #: Whether the task has changes not yet persisted.
91
128
  is_pending: bool
129
+ #: The IDs of elements in the task.
92
130
  element_IDs: List[int]
131
+ #: Description of the template for the task.
93
132
  task_template: Optional[Dict] = None
94
133
 
95
134
  def encode(self) -> Tuple[int, Dict, Dict]:
@@ -124,21 +163,43 @@ class StoreTask:
124
163
  @dataclass
125
164
  class StoreElement:
126
165
  """
166
+ Represents an element in a persistent store.
167
+
127
168
  Parameters
128
169
  ----------
129
- index
170
+ id_:
171
+ The ID of the element.
172
+ is_pending:
173
+ Whether the element has changes not yet persisted.
174
+ index:
130
175
  Index of the element within its parent task.
131
- iteration_IDs
176
+ es_idx:
177
+ Index of the element set containing this element.
178
+ seq_idx:
179
+ Value sequence index map.
180
+ src_idx:
181
+ Data source index map.
182
+ task_ID:
183
+ ID of the task that contains this element.
184
+ iteration_IDs:
132
185
  IDs of element-iterations that belong to this element.
133
186
  """
134
187
 
188
+ #: The ID of the element.
135
189
  id_: int
190
+ #: Whether the element has changes not yet persisted.
136
191
  is_pending: bool
192
+ #: Index of the element within its parent task.
137
193
  index: int
194
+ #: Index of the element set containing this element.
138
195
  es_idx: int
196
+ #: Value sequence index map.
139
197
  seq_idx: Dict[str, int]
198
+ #: Data source index map.
140
199
  src_idx: Dict[str, int]
200
+ #: ID of the task that contains this element.
141
201
  task_ID: int
202
+ #: IDs of element-iterations that belong to this element.
142
203
  iteration_IDs: List[int]
143
204
 
144
205
  def encode(self) -> Dict:
@@ -185,24 +246,45 @@ class StoreElement:
185
246
  @dataclass
186
247
  class StoreElementIter:
187
248
  """
249
+ Represents an element iteration in a persistent store.
250
+
188
251
  Parameters
189
252
  ----------
190
- data_idx
253
+ id_:
254
+ The ID of this element iteration.
255
+ is_pending:
256
+ Whether the element iteration has changes not yet persisted.
257
+ element_ID:
258
+ Which element is an iteration for.
259
+ EARs_initialised:
260
+ Whether EARs have been initialised for this element iteration.
261
+ EAR_IDs:
262
+ Maps task schema action indices to EARs by ID.
263
+ data_idx:
191
264
  Overall data index for the element-iteration, which maps parameter names to
192
265
  parameter data indices.
193
- EAR_IDs
194
- Maps task schema action indices to EARs by ID.
195
- schema_parameters
266
+ schema_parameters:
196
267
  List of parameters defined by the associated task schema.
268
+ loop_idx:
269
+ What loops are being handled here and where they're up to.
197
270
  """
198
271
 
272
+ #: The ID of this element iteration.
199
273
  id_: int
274
+ #: Whether the element iteration has changes not yet persisted.
200
275
  is_pending: bool
276
+ #: Which element is an iteration for.
201
277
  element_ID: int
278
+ #: Whether EARs have been initialised for this element iteration.
202
279
  EARs_initialised: bool
280
+ #: Maps task schema action indices to EARs by ID.
203
281
  EAR_IDs: Dict[int, List[int]]
282
+ #: Overall data index for the element-iteration, which maps parameter names to
283
+ #: parameter data indices.
204
284
  data_idx: Dict[str, int]
285
+ #: List of parameters defined by the associated task schema.
205
286
  schema_parameters: List[str]
287
+ #: What loops are being handled here and where they're up to.
206
288
  loop_idx: Dict[str, int] = field(default_factory=dict)
207
289
 
208
290
  def encode(self) -> Dict:
@@ -296,31 +378,75 @@ class StoreElementIter:
296
378
  @dataclass
297
379
  class StoreEAR:
298
380
  """
381
+ Represents an element action run in a persistent store.
382
+
299
383
  Parameters
300
384
  ----------
301
- data_idx
385
+ id_:
386
+ The ID of this element action run.
387
+ is_pending:
388
+ Whether the element action run has changes not yet persisted.
389
+ elem_iter_ID:
390
+ What element iteration owns this EAR.
391
+ action_idx:
392
+ The task schema action associated with this EAR.
393
+ commands_idx:
394
+ The indices of the commands in the EAR.
395
+ data_idx:
302
396
  Maps parameter names within this EAR to parameter data indices.
303
- metadata
397
+ submission_idx:
398
+ Which submission contained this EAR, if known.
399
+ skip:
400
+ Whether to skip this EAR.
401
+ success:
402
+ Whether this EAR was successful, if known.
403
+ start_time:
404
+ When this EAR started, if known.
405
+ end_time:
406
+ When this EAR finished, if known.
407
+ snapshot_start:
408
+ Snapshot of files at EAR start, if recorded.
409
+ snapshot_end:
410
+ Snapshot of files at EAR end, if recorded.
411
+ exit_code:
412
+ The exit code of the underlying executable, if known.
413
+ metadata:
304
414
  Metadata concerning e.g. the state of the EAR.
305
- action_idx
306
- The task schema action associated with this EAR.
415
+ run_hostname:
416
+ Where this EAR was submitted to run, if known.
307
417
  """
308
418
 
419
+ #: The ID of this element action run.
309
420
  id_: int
421
+ #: Whether the element action run has changes not yet persisted.
310
422
  is_pending: bool
423
+ #: What element iteration owns this EAR.
311
424
  elem_iter_ID: int
425
+ #: The task schema action associated with this EAR.
312
426
  action_idx: int
427
+ #: The indices of the commands in the EAR.
313
428
  commands_idx: List[int]
429
+ #: Maps parameter names within this EAR to parameter data indices.
314
430
  data_idx: Dict[str, int]
431
+ #: Which submission contained this EAR, if known.
315
432
  submission_idx: Optional[int] = None
433
+ #: Whether to skip this EAR.
316
434
  skip: Optional[bool] = False
435
+ #: Whether this EAR was successful, if known.
317
436
  success: Optional[bool] = None
437
+ #: When this EAR started, if known.
318
438
  start_time: Optional[datetime] = None
439
+ #: When this EAR finished, if known.
319
440
  end_time: Optional[datetime] = None
441
+ #: Snapshot of files at EAR start, if recorded.
320
442
  snapshot_start: Optional[Dict] = None
443
+ #: Snapshot of files at EAR end, if recorded.
321
444
  snapshot_end: Optional[Dict] = None
445
+ #: The exit code of the underlying executable, if known.
322
446
  exit_code: Optional[int] = None
447
+ #: Metadata concerning e.g. the state of the EAR.
323
448
  metadata: Dict[str, Any] = None
449
+ #: Where this EAR was submitted to run, if known.
324
450
  run_hostname: Optional[str] = None
325
451
 
326
452
  @staticmethod
@@ -434,11 +560,36 @@ class StoreEAR:
434
560
 
435
561
  @dataclass
436
562
  class StoreParameter:
563
+ """
564
+ Represents a parameter in a persistent store.
565
+
566
+ Parameters
567
+ ----------
568
+ id_:
569
+ The ID of this parameter.
570
+ is_pending:
571
+ Whether the parameter has changes not yet persisted.
572
+ is_set:
573
+ Whether the parameter is set.
574
+ data:
575
+ Description of the value of the parameter.
576
+ file:
577
+ Description of the file this parameter represents.
578
+ source:
579
+ Description of where this parameter originated.
580
+ """
581
+
582
+ #: The ID of this parameter.
437
583
  id_: int
584
+ #: Whether the parameter has changes not yet persisted.
438
585
  is_pending: bool
586
+ #: Whether the parameter is set.
439
587
  is_set: bool
588
+ #: Description of the value of the parameter.
440
589
  data: Any
590
+ #: Description of the file this parameter represents.
441
591
  file: Dict
592
+ #: Description of where this parameter originated.
442
593
  source: Dict
443
594
 
444
595
  _encoders = {}
@@ -647,6 +798,21 @@ class StoreParameter:
647
798
 
648
799
 
649
800
  class PersistentStore(ABC):
801
+ """
802
+ An abstract class representing a persistent workflow store.
803
+
804
+ Parameters
805
+ ----------
806
+ app: App
807
+ The main hpcflow core.
808
+ workflow: ~hpcflow.app.Workflow
809
+ The workflow being persisted.
810
+ path: pathlib.Path
811
+ Where to hold the store.
812
+ fs: fsspec.AbstractFileSystem
813
+ Optionally, information about how to access the store.
814
+ """
815
+
650
816
  _store_task_cls = StoreTask
651
817
  _store_elem_cls = StoreElement
652
818
  _store_iter_cls = StoreElementIter
@@ -672,14 +838,23 @@ class PersistentStore(ABC):
672
838
 
673
839
  @property
674
840
  def logger(self):
841
+ """
842
+ The logger to use.
843
+ """
675
844
  return self.app.persistence_logger
676
845
 
677
846
  @property
678
847
  def ts_fmt(self) -> str:
848
+ """
849
+ The format for timestamps.
850
+ """
679
851
  return self.workflow.ts_fmt
680
852
 
681
853
  @property
682
854
  def has_pending(self):
855
+ """
856
+ Whether there are any pending changes.
857
+ """
683
858
  return bool(self._pending)
684
859
 
685
860
  @property
@@ -689,6 +864,9 @@ class PersistentStore(ABC):
689
864
 
690
865
  @property
691
866
  def use_cache(self):
867
+ """
868
+ Whether to use a cache.
869
+ """
692
870
  return self._use_cache
693
871
 
694
872
  @property
@@ -914,6 +1092,9 @@ class PersistentStore(ABC):
914
1092
  self._pending.commit_all()
915
1093
 
916
1094
  def add_template_components(self, temp_comps: Dict, save: bool = True) -> None:
1095
+ """
1096
+ Add template components to the workflow.
1097
+ """
917
1098
  all_tc = self.get_template_components()
918
1099
  for name, dat in temp_comps.items():
919
1100
  if name in all_tc:
@@ -976,6 +1157,9 @@ class PersistentStore(ABC):
976
1157
  self.save()
977
1158
 
978
1159
  def add_element_set(self, task_id: int, es_js: Dict, save: bool = True):
1160
+ """
1161
+ Add an element set to a task.
1162
+ """
979
1163
  self._pending.add_element_sets[task_id].append(es_js)
980
1164
  if save:
981
1165
  self.save()
@@ -1058,6 +1242,9 @@ class PersistentStore(ABC):
1058
1242
  def add_submission_part(
1059
1243
  self, sub_idx: int, dt_str: str, submitted_js_idx: List[int], save: bool = True
1060
1244
  ):
1245
+ """
1246
+ Add a submission part.
1247
+ """
1061
1248
  self._pending.add_submission_parts[sub_idx][dt_str] = submitted_js_idx
1062
1249
  if save:
1063
1250
  self.save()
@@ -1066,11 +1253,17 @@ class PersistentStore(ABC):
1066
1253
  def set_EAR_submission_index(
1067
1254
  self, EAR_ID: int, sub_idx: int, save: bool = True
1068
1255
  ) -> None:
1256
+ """
1257
+ Set the submission index for an element action run.
1258
+ """
1069
1259
  self._pending.set_EAR_submission_indices[EAR_ID] = sub_idx
1070
1260
  if save:
1071
1261
  self.save()
1072
1262
 
1073
1263
  def set_EAR_start(self, EAR_ID: int, save: bool = True) -> datetime:
1264
+ """
1265
+ Mark an element action run as started.
1266
+ """
1074
1267
  dt = datetime.utcnow()
1075
1268
  ss_js = self.app.RunDirAppFiles.take_snapshot()
1076
1269
  run_hostname = socket.gethostname()
@@ -1082,6 +1275,9 @@ class PersistentStore(ABC):
1082
1275
  def set_EAR_end(
1083
1276
  self, EAR_ID: int, exit_code: int, success: bool, save: bool = True
1084
1277
  ) -> datetime:
1278
+ """
1279
+ Mark an element action run as finished.
1280
+ """
1085
1281
  # TODO: save output files
1086
1282
  dt = datetime.utcnow()
1087
1283
  ss_js = self.app.RunDirAppFiles.take_snapshot()
@@ -1091,11 +1287,17 @@ class PersistentStore(ABC):
1091
1287
  return dt
1092
1288
 
1093
1289
  def set_EAR_skip(self, EAR_ID: int, save: bool = True) -> None:
1290
+ """
1291
+ Mark an element action run as skipped.
1292
+ """
1094
1293
  self._pending.set_EAR_skips.append(EAR_ID)
1095
1294
  if save:
1096
1295
  self.save()
1097
1296
 
1098
1297
  def set_EARs_initialised(self, iter_ID: int, save: bool = True) -> None:
1298
+ """
1299
+ Mark an element action run as initialised.
1300
+ """
1099
1301
  self._pending.set_EARs_initialised.append(iter_ID)
1100
1302
  if save:
1101
1303
  self.save()
@@ -1116,6 +1318,9 @@ class PersistentStore(ABC):
1116
1318
  process_ID: Optional[int] = None,
1117
1319
  save: bool = True,
1118
1320
  ):
1321
+ """
1322
+ Set the metadata for a job script.
1323
+ """
1119
1324
  if version_info:
1120
1325
  self._pending.set_js_metadata[sub_idx][js_idx]["version_info"] = version_info
1121
1326
  if submit_time:
@@ -1229,6 +1434,9 @@ class PersistentStore(ABC):
1229
1434
  clean_up: bool = False,
1230
1435
  save: bool = True,
1231
1436
  ):
1437
+ """
1438
+ Set details of a file, including whether it is associated with a parameter.
1439
+ """
1232
1440
  self.logger.debug(f"Setting new file")
1233
1441
  file_param_dat = self._prepare_set_file(
1234
1442
  store_contents=store_contents,
@@ -1255,6 +1463,9 @@ class PersistentStore(ABC):
1255
1463
  filename: str = None,
1256
1464
  save: bool = True,
1257
1465
  ):
1466
+ """
1467
+ Add a file that will be associated with a parameter.
1468
+ """
1258
1469
  self.logger.debug(f"Adding new file")
1259
1470
  file_param_dat = self._prepare_set_file(
1260
1471
  store_contents=store_contents,
@@ -1291,14 +1502,23 @@ class PersistentStore(ABC):
1291
1502
  fp.write(dat["contents"])
1292
1503
 
1293
1504
  def add_set_parameter(self, data: Any, source: Dict, save: bool = True) -> int:
1505
+ """
1506
+ Add a parameter that is set to a value.
1507
+ """
1294
1508
  return self._add_parameter(data=data, is_set=True, source=source, save=save)
1295
1509
 
1296
1510
  def add_unset_parameter(self, source: Dict, save: bool = True) -> int:
1511
+ """
1512
+ Add a parameter that is not set to any value.
1513
+ """
1297
1514
  return self._add_parameter(data=None, is_set=False, source=source, save=save)
1298
1515
 
1299
1516
  def set_parameter_value(
1300
1517
  self, param_id: int, value: Any, is_file: bool = False, save: bool = True
1301
1518
  ):
1519
+ """
1520
+ Set the value of a parameter.
1521
+ """
1302
1522
  self.logger.debug(
1303
1523
  f"Setting store parameter ID {param_id} value with type: {type(value)!r})."
1304
1524
  )
@@ -1310,6 +1530,9 @@ class PersistentStore(ABC):
1310
1530
  def update_param_source(
1311
1531
  self, param_sources: Dict[int, Dict], save: bool = True
1312
1532
  ) -> None:
1533
+ """
1534
+ Set the source of a parameter.
1535
+ """
1313
1536
  self.logger.debug(f"Updating parameter sources with {param_sources!r}.")
1314
1537
  self._pending.update_param_sources.update(param_sources)
1315
1538
  if save:
@@ -1318,6 +1541,9 @@ class PersistentStore(ABC):
1318
1541
  def update_loop_num_iters(
1319
1542
  self, index: int, num_added_iters: int, save: bool = True
1320
1543
  ) -> None:
1544
+ """
1545
+ Add iterations to a loop.
1546
+ """
1321
1547
  self.logger.debug(
1322
1548
  f"Updating loop {index!r} num added iterations to {num_added_iters!r}."
1323
1549
  )
@@ -1333,6 +1559,9 @@ class PersistentStore(ABC):
1333
1559
  parents: List[str],
1334
1560
  save: bool = True,
1335
1561
  ) -> None:
1562
+ """
1563
+ Set the parents of a loop.
1564
+ """
1336
1565
  self.logger.debug(
1337
1566
  f"Updating loop {index!r} parents to {parents!r}, and num added iterations "
1338
1567
  f"to {num_added_iters}."
@@ -1355,6 +1584,9 @@ class PersistentStore(ABC):
1355
1584
  return tc
1356
1585
 
1357
1586
  def get_template(self) -> Dict:
1587
+ """
1588
+ Get the workflow template.
1589
+ """
1358
1590
  return self._get_persistent_template()
1359
1591
 
1360
1592
  def _get_task_id_to_idx_map(self) -> Dict[int, int]:
@@ -1362,6 +1594,9 @@ class PersistentStore(ABC):
1362
1594
 
1363
1595
  @TimeIt.decorator
1364
1596
  def get_task(self, task_idx: int) -> AnySTask:
1597
+ """
1598
+ Get a task.
1599
+ """
1365
1600
  return self.get_tasks()[task_idx]
1366
1601
 
1367
1602
  def _process_retrieved_tasks(self, tasks: List[AnySTask]) -> List[AnySTask]:
@@ -1394,6 +1629,9 @@ class PersistentStore(ABC):
1394
1629
  return loops_new
1395
1630
 
1396
1631
  def get_tasks_by_IDs(self, id_lst: Iterable[int]) -> List[AnySTask]:
1632
+ """
1633
+ Get tasks with the given IDs.
1634
+ """
1397
1635
  # separate pending and persistent IDs:
1398
1636
  id_set = set(id_lst)
1399
1637
  all_pending = set(self._pending.add_tasks)
@@ -1461,6 +1699,9 @@ class PersistentStore(ABC):
1461
1699
 
1462
1700
  @TimeIt.decorator
1463
1701
  def get_submissions_by_ID(self, id_lst: Iterable[int]) -> Dict[int, Dict]:
1702
+ """
1703
+ Get submissions with the given IDs.
1704
+ """
1464
1705
  # separate pending and persistent IDs:
1465
1706
  id_set = set(id_lst)
1466
1707
  all_pending = set(self._pending.add_submissions)
@@ -1477,6 +1718,9 @@ class PersistentStore(ABC):
1477
1718
 
1478
1719
  @TimeIt.decorator
1479
1720
  def get_elements(self, id_lst: Iterable[int]) -> List[AnySElement]:
1721
+ """
1722
+ Get elements with the given IDs.
1723
+ """
1480
1724
  self.logger.debug(f"PersistentStore.get_elements: id_lst={id_lst!r}")
1481
1725
 
1482
1726
  # separate pending and persistent IDs:
@@ -1504,6 +1748,9 @@ class PersistentStore(ABC):
1504
1748
 
1505
1749
  @TimeIt.decorator
1506
1750
  def get_element_iterations(self, id_lst: Iterable[int]) -> List[AnySElementIter]:
1751
+ """
1752
+ Get element iterations with the given IDs.
1753
+ """
1507
1754
  self.logger.debug(f"PersistentStore.get_element_iterations: id_lst={id_lst!r}")
1508
1755
 
1509
1756
  # separate pending and persistent IDs:
@@ -1540,6 +1787,9 @@ class PersistentStore(ABC):
1540
1787
 
1541
1788
  @TimeIt.decorator
1542
1789
  def get_EARs(self, id_lst: Iterable[int]) -> List[AnySEAR]:
1790
+ """
1791
+ Get element action runs with the given IDs.
1792
+ """
1543
1793
  self.logger.debug(f"PersistentStore.get_EARs: id_lst={id_lst!r}")
1544
1794
 
1545
1795
  # separate pending and persistent IDs:
@@ -1624,6 +1874,9 @@ class PersistentStore(ABC):
1624
1874
  return self._get_cached_persistent_items(id_lst, self.parameter_cache)
1625
1875
 
1626
1876
  def get_EAR_skipped(self, EAR_ID: int) -> bool:
1877
+ """
1878
+ Whether the element action run with the given ID was skipped.
1879
+ """
1627
1880
  self.logger.debug(f"PersistentStore.get_EAR_skipped: EAR_ID={EAR_ID!r}")
1628
1881
  return self.get_EARs([EAR_ID])[0].skip
1629
1882
 
@@ -1634,11 +1887,17 @@ class PersistentStore(ABC):
1634
1887
  **kwargs: Dict,
1635
1888
  ) -> List[AnySParameter]:
1636
1889
  """
1890
+ Get parameters with the given IDs.
1891
+
1637
1892
  Parameters
1638
1893
  ----------
1639
- kwargs :
1640
- dataset_copy : bool
1641
- For Zarr stores only. If True, copy arrays as NumPy arrays.
1894
+ id_lst:
1895
+ The IDs of the parameters to get.
1896
+
1897
+ Keyword Arguments
1898
+ -----------------
1899
+ dataset_copy: bool
1900
+ For Zarr stores only. If True, copy arrays as NumPy arrays.
1642
1901
  """
1643
1902
  # separate pending and persistent IDs:
1644
1903
  id_set = set(id_lst)
@@ -1656,6 +1915,9 @@ class PersistentStore(ABC):
1656
1915
 
1657
1916
  @TimeIt.decorator
1658
1917
  def get_parameter_set_statuses(self, id_lst: Iterable[int]) -> List[bool]:
1918
+ """
1919
+ Get whether the parameters with the given IDs are set.
1920
+ """
1659
1921
  # separate pending and persistent IDs:
1660
1922
  id_set = set(id_lst)
1661
1923
  all_pending = set(self._pending.add_parameters)
@@ -1670,6 +1932,9 @@ class PersistentStore(ABC):
1670
1932
 
1671
1933
  @TimeIt.decorator
1672
1934
  def get_parameter_sources(self, id_lst: Iterable[int]) -> List[Dict]:
1935
+ """
1936
+ Get the sources of the parameters with the given IDs.
1937
+ """
1673
1938
  # separate pending and persistent IDs:
1674
1939
  id_set = set(id_lst)
1675
1940
  all_pending = set(self._pending.add_parameters)
@@ -1698,7 +1963,8 @@ class PersistentStore(ABC):
1698
1963
  task_id,
1699
1964
  idx_lst: Optional[Iterable[int]] = None,
1700
1965
  ) -> List[Dict]:
1701
- """Get element data by an indices within a given task.
1966
+ """
1967
+ Get element data by an indices within a given task.
1702
1968
 
1703
1969
  Element iterations and EARs belonging to the elements are included.
1704
1970