hpcflow-new2 0.2.0a179__py3-none-any.whl → 0.2.0a180__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.0a180.dist-info}/METADATA +1 -1
  67. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/RECORD +70 -70
  68. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/LICENSE +0 -0
  69. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/WHEEL +0 -0
  70. {hpcflow_new2-0.2.0a179.dist-info → hpcflow_new2-0.2.0a180.dist-info}/entry_points.txt +0 -0
@@ -1,3 +1,7 @@
1
+ """
2
+ Elements are components of tasks.
3
+ """
4
+
1
5
  from __future__ import annotations
2
6
  import copy
3
7
  from dataclasses import dataclass, field
@@ -89,7 +93,8 @@ class _ElementPrefixedParameter:
89
93
 
90
94
  @property
91
95
  def prefixed_names_unlabelled(self) -> Dict[str, List[str]]:
92
- """Get a mapping between inputs types and associated labels.
96
+ """
97
+ A mapping between input types and associated labels.
93
98
 
94
99
  If the schema input for a given input type has `multiple=False` (even if a label
95
100
  is defined), the values for that input type will be an empty list.
@@ -101,6 +106,9 @@ class _ElementPrefixedParameter:
101
106
 
102
107
  @property
103
108
  def prefixed_names_unlabelled_str(self):
109
+ """
110
+ A description of the prefixed names.
111
+ """
104
112
  return ", ".join(i for i in self.prefixed_names_unlabelled)
105
113
 
106
114
  def __repr__(self):
@@ -137,6 +145,19 @@ class _ElementPrefixedParameter:
137
145
 
138
146
 
139
147
  class ElementInputs(_ElementPrefixedParameter):
148
+ """
149
+ The inputs to an element.
150
+
151
+ Parameters
152
+ ----------
153
+ element_iteration: ElementIteration
154
+ Which iteration does this refer to?
155
+ element_action: ~hpcflow.app.ElementAction
156
+ Which action does this refer to?
157
+ element_action_run: ~hpcflow.app.ElementActionRun
158
+ Which EAR does this refer to?
159
+ """
160
+
140
161
  def __init__(
141
162
  self,
142
163
  element_iteration: Optional[app.ElementIteration] = None,
@@ -147,6 +168,19 @@ class ElementInputs(_ElementPrefixedParameter):
147
168
 
148
169
 
149
170
  class ElementOutputs(_ElementPrefixedParameter):
171
+ """
172
+ The outputs from an element.
173
+
174
+ Parameters
175
+ ----------
176
+ element_iteration: ElementIteration
177
+ Which iteration does this refer to?
178
+ element_action: ~hpcflow.app.ElementAction
179
+ Which action does this refer to?
180
+ element_action_run: ~hpcflow.app.ElementActionRun
181
+ Which EAR does this refer to?
182
+ """
183
+
150
184
  def __init__(
151
185
  self,
152
186
  element_iteration: Optional[app.ElementIteration] = None,
@@ -157,6 +191,19 @@ class ElementOutputs(_ElementPrefixedParameter):
157
191
 
158
192
 
159
193
  class ElementInputFiles(_ElementPrefixedParameter):
194
+ """
195
+ The input files to an element.
196
+
197
+ Parameters
198
+ ----------
199
+ element_iteration: ElementIteration
200
+ Which iteration does this refer to?
201
+ element_action: ~hpcflow.app.ElementAction
202
+ Which action does this refer to?
203
+ element_action_run: ~hpcflow.app.ElementActionRun
204
+ Which EAR does this refer to?
205
+ """
206
+
160
207
  def __init__(
161
208
  self,
162
209
  element_iteration: Optional[app.ElementIteration] = None,
@@ -169,6 +216,19 @@ class ElementInputFiles(_ElementPrefixedParameter):
169
216
 
170
217
 
171
218
  class ElementOutputFiles(_ElementPrefixedParameter):
219
+ """
220
+ The output files from an element.
221
+
222
+ Parameters
223
+ ----------
224
+ element_iteration: ElementIteration
225
+ Which iteration does this refer to?
226
+ element_action: ~hpcflow.app.ElementAction
227
+ Which action does this refer to?
228
+ element_action_run: ~hpcflow.app.ElementActionRun
229
+ Which EAR does this refer to?
230
+ """
231
+
172
232
  def __init__(
173
233
  self,
174
234
  element_iteration: Optional[app.ElementIteration] = None,
@@ -182,33 +242,108 @@ class ElementOutputFiles(_ElementPrefixedParameter):
182
242
 
183
243
  @dataclass
184
244
  class ElementResources(JSONLike):
245
+ """
246
+ The resources an element requires.
247
+
248
+ Note
249
+ ----
250
+ It is common to leave most of these unspecified.
251
+ Many of them have complex interactions with each other.
252
+
253
+ Parameters
254
+ ----------
255
+ scratch: str
256
+ Which scratch space to use.
257
+ parallel_mode: ParallelMode
258
+ Which parallel mode to use.
259
+ num_cores: int
260
+ How many cores to request.
261
+ num_cores_per_node: int
262
+ How many cores per compute node to request.
263
+ num_threads: int
264
+ How many threads to request.
265
+ num_nodes: int
266
+ How many compute nodes to request.
267
+ scheduler: str
268
+ Which scheduler to use.
269
+ shell: str
270
+ Which system shell to use.
271
+ use_job_array: bool
272
+ Whether to use array jobs.
273
+ max_array_items: int
274
+ If using array jobs, up to how many items should be in the job array.
275
+ time_limit: str
276
+ How long to run for.
277
+ scheduler_args: dict[str, Any]
278
+ Additional arguments to pass to the scheduler.
279
+ shell_args: dict[str, Any]
280
+ Additional arguments to pass to the shell.
281
+ os_name: str
282
+ Which OS to use.
283
+ environments: dict
284
+ Which execution environments to use.
285
+ SGE_parallel_env: str
286
+ Which SGE parallel environment to request.
287
+ SLURM_partition: str
288
+ Which SLURM partition to request.
289
+ SLURM_num_tasks: str
290
+ How many SLURM tasks to request.
291
+ SLURM_num_tasks_per_node: str
292
+ How many SLURM tasks per compute node to request.
293
+ SLURM_num_nodes: str
294
+ How many compute nodes to request.
295
+ SLURM_num_cpus_per_task: str
296
+ How many CPU cores to ask for per SLURM task.
297
+ """
298
+
185
299
  # TODO: how to specify e.g. high-memory requirement?
186
300
 
301
+ #: Which scratch space to use.
187
302
  scratch: Optional[str] = None
303
+ #: Which parallel mode to use.
188
304
  parallel_mode: Optional[ParallelMode] = None
305
+ #: How many cores to request.
189
306
  num_cores: Optional[int] = None
307
+ #: How many cores per compute node to request.
190
308
  num_cores_per_node: Optional[int] = None
309
+ #: How many threads to request.
191
310
  num_threads: Optional[int] = None
311
+ #: How many compute nodes to request.
192
312
  num_nodes: Optional[int] = None
313
+
314
+ #: Which scheduler to use.
193
315
  scheduler: Optional[str] = None
316
+ #: Which system shell to use.
194
317
  shell: Optional[str] = None
318
+ #: Whether to use array jobs.
195
319
  use_job_array: Optional[bool] = None
320
+ #: If using array jobs, up to how many items should be in the job array.
196
321
  max_array_items: Optional[int] = None
322
+ #: How long to run for.
197
323
  time_limit: Optional[str] = None
198
-
324
+ #: Additional arguments to pass to the scheduler.
199
325
  scheduler_args: Optional[Dict] = None
326
+ #: Additional arguments to pass to the shell.
200
327
  shell_args: Optional[Dict] = None
328
+ #: Which OS to use.
201
329
  os_name: Optional[str] = None
330
+ #: Which execution environments to use.
202
331
  environments: Optional[Dict] = None
203
332
 
204
333
  # SGE scheduler specific:
334
+ #: Which SGE parallel environment to request.
205
335
  SGE_parallel_env: str = None
206
336
 
207
337
  # SLURM scheduler specific:
338
+ #: Which SLURM partition to request.
208
339
  SLURM_partition: str = None
340
+ #: How many SLURM tasks to request.
209
341
  SLURM_num_tasks: str = None
342
+ #: How many SLURM tasks per compute node to request.
210
343
  SLURM_num_tasks_per_node: str = None
344
+ #: How many compute nodes to request.
211
345
  SLURM_num_nodes: str = None
346
+ #: How many CPU cores to ask for per SLURM task.
212
347
  SLURM_num_cpus_per_task: str = None
213
348
 
214
349
  def __post_init__(self):
@@ -291,20 +426,32 @@ class ElementResources(JSONLike):
291
426
 
292
427
  @staticmethod
293
428
  def get_default_os_name():
429
+ """
430
+ Get the default value for OS name.
431
+ """
294
432
  return os.name
295
433
 
296
434
  @classmethod
297
435
  def get_default_shell(cls):
436
+ """
437
+ Get the default value for name.
438
+ """
298
439
  return cls.app.config.default_shell
299
440
 
300
441
  @classmethod
301
442
  def get_default_scheduler(cls, os_name, shell_name):
443
+ """
444
+ Get the default value for scheduler.
445
+ """
302
446
  if os_name == "nt" and "wsl" in shell_name:
303
447
  # provide a "*_posix" default scheduler on windows if shell is WSL:
304
448
  return "direct_posix"
305
449
  return cls.app.config.default_scheduler
306
450
 
307
451
  def set_defaults(self):
452
+ """
453
+ Set defaults for unspecified values that need defaults.
454
+ """
308
455
  if self.os_name is None:
309
456
  self.os_name = self.get_default_os_name()
310
457
  if self.shell is None:
@@ -353,6 +500,33 @@ class ElementResources(JSONLike):
353
500
 
354
501
 
355
502
  class ElementIteration:
503
+ """
504
+ A particular iteration of an element.
505
+
506
+ Parameters
507
+ ----------
508
+ id_ : int
509
+ The ID of this iteration.
510
+ is_pending: bool
511
+ Whether this iteration is pending execution.
512
+ index: int
513
+ The index of this iteration in its parent element.
514
+ element: Element
515
+ The element this is an iteration of.
516
+ data_idx: dict
517
+ The overall element iteration data index, before resolution of EARs.
518
+ EARs_initialised: bool
519
+ Whether EARs have been set up for the iteration.
520
+ EAR_IDs: dict[int, int]
521
+ Mapping from iteration number to EAR ID, where known.
522
+ EARs: list[dict]
523
+ Data about EARs.
524
+ schema_parameters: list[str]
525
+ Parameters from the schema.
526
+ loop_idx: dict[str, int]
527
+ Indexing information from the loop.
528
+ """
529
+
356
530
  _app_attr = "app"
357
531
 
358
532
  def __init__(
@@ -406,46 +580,79 @@ class ElementIteration:
406
580
 
407
581
  @property
408
582
  def element(self):
583
+ """
584
+ The element this is an iteration of.
585
+ """
409
586
  return self._element
410
587
 
411
588
  @property
412
589
  def index(self):
590
+ """
591
+ The index of this iteration in its parent element.
592
+ """
413
593
  return self._index
414
594
 
415
595
  @property
416
596
  def id_(self) -> int:
597
+ """
598
+ The ID of this iteration.
599
+ """
417
600
  return self._id
418
601
 
419
602
  @property
420
603
  def is_pending(self) -> bool:
604
+ """
605
+ Whether this iteration is pending execution.
606
+ """
421
607
  return self._is_pending
422
608
 
423
609
  @property
424
610
  def task(self):
611
+ """
612
+ The task this is an iteration of an element for.
613
+ """
425
614
  return self.element.task
426
615
 
427
616
  @property
428
617
  def workflow(self):
618
+ """
619
+ The workflow this is a part of.
620
+ """
429
621
  return self.element.workflow
430
622
 
431
623
  @property
432
624
  def loop_idx(self) -> Dict[str, int]:
625
+ """
626
+ Indexing information from the loop.
627
+ """
433
628
  return self._loop_idx
434
629
 
435
630
  @property
436
631
  def schema_parameters(self) -> List[str]:
632
+ """
633
+ Parameters from the schema.
634
+ """
437
635
  return self._schema_parameters
438
636
 
439
637
  @property
440
638
  def EAR_IDs(self) -> Dict[int, int]:
639
+ """
640
+ Mapping from iteration number to EAR ID, where known.
641
+ """
441
642
  return self._EAR_IDs
442
643
 
443
644
  @property
444
645
  def EAR_IDs_flat(self):
646
+ """
647
+ The EAR IDs.
648
+ """
445
649
  return [j for i in self.EAR_IDs.values() for j in i]
446
650
 
447
651
  @property
448
652
  def actions(self) -> Dict[app.ElementAction]:
653
+ """
654
+ The actions of this iteration.
655
+ """
449
656
  if self._action_objs is None:
450
657
  self._action_objs = {
451
658
  act_idx: self.app.ElementAction(
@@ -459,30 +666,44 @@ class ElementIteration:
459
666
 
460
667
  @property
461
668
  def action_runs(self) -> List[app.ElementActionRun]:
462
- """Get a list of element action runs, where only the final run is taken for each
463
- element action."""
669
+ """
670
+ A list of element action runs, where only the final run is taken for each
671
+ element action.
672
+ """
464
673
  return [i.runs[-1] for i in self.actions.values()]
465
674
 
466
675
  @property
467
676
  def inputs(self) -> app.ElementInputs:
677
+ """
678
+ The inputs to this element.
679
+ """
468
680
  if not self._inputs:
469
681
  self._inputs = self.app.ElementInputs(element_iteration=self)
470
682
  return self._inputs
471
683
 
472
684
  @property
473
685
  def outputs(self) -> app.ElementOutputs:
686
+ """
687
+ The outputs from this element.
688
+ """
474
689
  if not self._outputs:
475
690
  self._outputs = self.app.ElementOutputs(element_iteration=self)
476
691
  return self._outputs
477
692
 
478
693
  @property
479
694
  def input_files(self) -> app.ElementInputFiles:
695
+ """
696
+ The input files to this element.
697
+ """
480
698
  if not self._input_files:
481
699
  self._input_files = self.app.ElementInputFiles(element_iteration=self)
482
700
  return self._input_files
483
701
 
484
702
  @property
485
703
  def output_files(self) -> app.ElementOutputFiles:
704
+ """
705
+ The output files from this element.
706
+ """
486
707
  if not self._output_files:
487
708
  self._output_files = self.app.ElementOutputFiles(element_iteration=self)
488
709
  return self._output_files
@@ -521,10 +742,16 @@ class ElementIteration:
521
742
  run_idx: int = -1,
522
743
  ) -> Dict[str, int]:
523
744
  """
745
+ Get the data index.
746
+
524
747
  Parameters
525
748
  ----------
526
- action_idx
749
+ path:
750
+ If specified, filters the data indices to the ones relevant to this path.
751
+ action_idx:
527
752
  The index of the action within the schema.
753
+ run_idx:
754
+ The index of the run within the action.
528
755
  """
529
756
 
530
757
  if not self.actions:
@@ -563,6 +790,8 @@ class ElementIteration:
563
790
  use_task_index: bool = False,
564
791
  ) -> Dict[str, Union[str, Dict[str, Any]]]:
565
792
  """
793
+ Get the origin of parameters.
794
+
566
795
  Parameters
567
796
  ----------
568
797
  use_task_index
@@ -938,10 +1167,39 @@ class ElementIteration:
938
1167
  def get_resources_obj(
939
1168
  self, action: app.Action, set_defaults: bool = False
940
1169
  ) -> app.ElementResources:
1170
+ """
1171
+ Get the resources for an action (see :py:meth:`get_resources`)
1172
+ as a searchable model.
1173
+ """
941
1174
  return self.app.ElementResources(**self.get_resources(action, set_defaults))
942
1175
 
943
1176
 
944
1177
  class Element:
1178
+ """
1179
+ A basic component of a workflow. Elements are enactments of tasks.
1180
+
1181
+ Parameters
1182
+ ----------
1183
+ id_ : int
1184
+ The ID of this element.
1185
+ is_pending: bool
1186
+ Whether this element is pending execution.
1187
+ task: ~hpcflow.app.WorkflowTask
1188
+ The task this is part of the enactment of.
1189
+ index: int
1190
+ The index of this element.
1191
+ es_idx: int
1192
+ The index within the task of the element set containing this element.
1193
+ seq_idx: dict[str, int]
1194
+ The sequence index IDs.
1195
+ src_idx: dict[str, int]
1196
+ The input source indices.
1197
+ iteration_IDs: list[int]
1198
+ The known IDs of iterations,
1199
+ iterations: list[dict]
1200
+ Data for creating iteration objects.
1201
+ """
1202
+
945
1203
  _app_attr = "app"
946
1204
 
947
1205
  # TODO: use slots
@@ -984,14 +1242,23 @@ class Element:
984
1242
 
985
1243
  @property
986
1244
  def id_(self) -> int:
1245
+ """
1246
+ The ID of this element.
1247
+ """
987
1248
  return self._id
988
1249
 
989
1250
  @property
990
1251
  def is_pending(self) -> bool:
1252
+ """
1253
+ Whether this element is pending execution.
1254
+ """
991
1255
  return self._is_pending
992
1256
 
993
1257
  @property
994
1258
  def task(self) -> app.WorkflowTask:
1259
+ """
1260
+ The task this is part of the enactment of.
1261
+ """
995
1262
  return self._task
996
1263
 
997
1264
  @property
@@ -1005,22 +1272,37 @@ class Element:
1005
1272
 
1006
1273
  @property
1007
1274
  def element_set_idx(self) -> int:
1275
+ """
1276
+ The index within the task of the element set containing this element.
1277
+ """
1008
1278
  return self._es_idx
1009
1279
 
1010
1280
  @property
1011
1281
  def element_set(self):
1282
+ """
1283
+ The element set containing this element.
1284
+ """
1012
1285
  return self.task.template.element_sets[self.element_set_idx]
1013
1286
 
1014
1287
  @property
1015
1288
  def sequence_idx(self) -> Dict[str, int]:
1289
+ """
1290
+ The sequence index IDs.
1291
+ """
1016
1292
  return self._seq_idx
1017
1293
 
1018
1294
  @property
1019
1295
  def input_source_idx(self) -> Dict[str, int]:
1296
+ """
1297
+ The input source indices.
1298
+ """
1020
1299
  return self._src_idx
1021
1300
 
1022
1301
  @property
1023
1302
  def input_sources(self) -> Dict[str, app.InputSource]:
1303
+ """
1304
+ The sources of the inputs to this element.
1305
+ """
1024
1306
  return {
1025
1307
  k: self.element_set.input_sources[k.split("inputs.")[1]][v]
1026
1308
  for k, v in self.input_source_idx.items()
@@ -1028,15 +1310,24 @@ class Element:
1028
1310
 
1029
1311
  @property
1030
1312
  def workflow(self) -> app.Workflow:
1313
+ """
1314
+ The workflow containing this element.
1315
+ """
1031
1316
  return self.task.workflow
1032
1317
 
1033
1318
  @property
1034
1319
  def iteration_IDs(self) -> List[int]:
1320
+ """
1321
+ The IDs of the iterations of this element.
1322
+ """
1035
1323
  return self._iteration_IDs
1036
1324
 
1037
1325
  @property
1038
1326
  @TimeIt.decorator
1039
- def iterations(self) -> Dict[app.ElementAction]:
1327
+ def iterations(self) -> List[app.ElementIteration]:
1328
+ """
1329
+ The iterations of this element.
1330
+ """
1040
1331
  # TODO: fix this
1041
1332
  if self._iteration_objs is None:
1042
1333
  self._iteration_objs = [
@@ -1051,43 +1342,72 @@ class Element:
1051
1342
 
1052
1343
  @property
1053
1344
  def dir_name(self):
1345
+ """
1346
+ The name of the directory for containing temporary files for this element.
1347
+ """
1054
1348
  return f"e_{self.index}"
1055
1349
 
1056
1350
  @property
1057
1351
  def latest_iteration(self):
1352
+ """
1353
+ The most recent iteration of this element.
1354
+ """
1058
1355
  return self.iterations[-1]
1059
1356
 
1060
1357
  @property
1061
1358
  def inputs(self) -> app.ElementInputs:
1359
+ """
1360
+ The inputs to this element (or its most recent iteration).
1361
+ """
1062
1362
  return self.latest_iteration.inputs
1063
1363
 
1064
1364
  @property
1065
1365
  def outputs(self) -> app.ElementOutputs:
1366
+ """
1367
+ The outputs from this element (or its most recent iteration).
1368
+ """
1066
1369
  return self.latest_iteration.outputs
1067
1370
 
1068
1371
  @property
1069
1372
  def input_files(self) -> app.ElementInputFiles:
1373
+ """
1374
+ The input files to this element (or its most recent iteration).
1375
+ """
1070
1376
  return self.latest_iteration.input_files
1071
1377
 
1072
1378
  @property
1073
1379
  def output_files(self) -> app.ElementOutputFiles:
1380
+ """
1381
+ The output files from this element (or its most recent iteration).
1382
+ """
1074
1383
  return self.latest_iteration.output_files
1075
1384
 
1076
1385
  @property
1077
1386
  def schema_parameters(self) -> List[str]:
1387
+ """
1388
+ The schema-defined parameters to this element (or its most recent iteration).
1389
+ """
1078
1390
  return self.latest_iteration.schema_parameters
1079
1391
 
1080
1392
  @property
1081
1393
  def actions(self) -> Dict[app.ElementAction]:
1394
+ """
1395
+ The actions of this element (or its most recent iteration).
1396
+ """
1082
1397
  return self.latest_iteration.actions
1083
1398
 
1084
1399
  @property
1085
1400
  def action_runs(self) -> List[app.ElementActionRun]:
1086
- """Get a list of element action runs from the latest iteration, where only the
1087
- final run is taken for each element action."""
1401
+ """
1402
+ A list of element action runs from the latest iteration, where only the
1403
+ final run is taken for each element action.
1404
+ """
1088
1405
  return self.latest_iteration.action_runs
1089
1406
 
1090
1407
  def init_loop_index(self, loop_name: str):
1408
+ """
1409
+ Initialise the loop index if necessary.
1410
+ """
1091
1411
  pass
1092
1412
 
1093
1413
  def to_element_set_data(self):
@@ -1117,6 +1437,9 @@ class Element:
1117
1437
  return inputs, resources
1118
1438
 
1119
1439
  def get_sequence_value(self, sequence_path: str) -> Any:
1440
+ """
1441
+ Get the value of a sequence that applies.
1442
+ """
1120
1443
  seq = self.element_set.get_sequence_from_path(sequence_path)
1121
1444
  if not seq:
1122
1445
  raise ValueError(
@@ -1286,19 +1609,44 @@ class Element:
1286
1609
 
1287
1610
  @dataclass
1288
1611
  class ElementParameter:
1612
+ """
1613
+ A parameter to an :py:class:`.Element`.
1614
+
1615
+ Parameters
1616
+ ----------
1617
+ task: ~hpcflow.app.WorkflowTask
1618
+ The task that this is part of.
1619
+ path: str
1620
+ The path to this parameter.
1621
+ parent: Element | ~hpcflow.app.ElementAction | ~hpcflow.app.ElementActionRun | ~hpcflow.app.Parameters
1622
+ The entity that owns this parameter.
1623
+ element: Element
1624
+ The element that this is a parameter of.
1625
+ """
1626
+
1289
1627
  _app_attr = "app"
1290
1628
 
1629
+ #: The task that this is part of.
1291
1630
  task: app.WorkflowTask
1631
+ #: The path to this parameter.
1292
1632
  path: str
1633
+ #: The entity that owns this parameter.
1293
1634
  parent: Union[Element, app.ElementAction, app.ElementActionRun, app.Parameters]
1635
+ #: The element that this is a parameter of.
1294
1636
  element: Element
1295
1637
 
1296
1638
  @property
1297
1639
  def data_idx(self):
1640
+ """
1641
+ The data indices associated with this parameter.
1642
+ """
1298
1643
  return self.parent.get_data_idx(path=self.path)
1299
1644
 
1300
1645
  @property
1301
1646
  def value(self) -> Any:
1647
+ """
1648
+ The value of this parameter.
1649
+ """
1302
1650
  return self.parent.get(path=self.path)
1303
1651
 
1304
1652
  def __repr__(self) -> str:
@@ -1312,27 +1660,49 @@ class ElementParameter:
1312
1660
 
1313
1661
  @property
1314
1662
  def data_idx_is_set(self):
1663
+ """
1664
+ The associated data indices for which this is set.
1665
+ """
1315
1666
  return {
1316
1667
  k: self.task.workflow.is_parameter_set(v) for k, v in self.data_idx.items()
1317
1668
  }
1318
1669
 
1319
1670
  @property
1320
1671
  def is_set(self):
1672
+ """
1673
+ Whether this parameter is set.
1674
+ """
1321
1675
  return all(self.data_idx_is_set.values())
1322
1676
 
1323
1677
  def get_size(self, **store_kwargs):
1678
+ """
1679
+ Get the size of the parameter.
1680
+ """
1324
1681
  raise NotImplementedError
1325
1682
 
1326
1683
 
1327
1684
  @dataclass
1328
1685
  class ElementFilter(JSONLike):
1686
+ """
1687
+ A filter for iterations.
1688
+
1689
+ Parameters
1690
+ ----------
1691
+ rules: list[~hpcflow.app.Rule]
1692
+ The filtering rules to use.
1693
+ """
1694
+
1329
1695
  _child_objects = (ChildObjectSpec(name="rules", is_multiple=True, class_name="Rule"),)
1330
1696
 
1697
+ #: The filtering rules to use.
1331
1698
  rules: List[app.Rule] = field(default_factory=list)
1332
1699
 
1333
1700
  def filter(
1334
1701
  self, element_iters: List[app.ElementIteration]
1335
1702
  ) -> List[app.ElementIteration]:
1703
+ """
1704
+ Apply the filter rules to select a subsequence of iterations.
1705
+ """
1336
1706
  out = []
1337
1707
  for i in element_iters:
1338
1708
  if all(rule_j.test(i) for rule_j in self.rules):
@@ -1342,8 +1712,24 @@ class ElementFilter(JSONLike):
1342
1712
 
1343
1713
  @dataclass
1344
1714
  class ElementGroup(JSONLike):
1715
+ """
1716
+ A grouping rule for element iterations.
1717
+
1718
+ Parameters
1719
+ ----------
1720
+ name:
1721
+ The name of the grouping rule.
1722
+ where:
1723
+ A filtering rule to select which iterations to use in the group.
1724
+ group_by_distinct:
1725
+ If specified, the name of the property to group iterations by.
1726
+ """
1727
+
1728
+ #: The name of the grouping rule.
1345
1729
  name: str
1730
+ #: A filtering rule to select which iterations to use in the group.
1346
1731
  where: Optional[ElementFilter] = None
1732
+ #: If specified, the name of the property to group iterations by.
1347
1733
  group_by_distinct: Optional[app.ParameterPath] = None
1348
1734
 
1349
1735
  def __post_init__(self):
@@ -1352,5 +1738,18 @@ class ElementGroup(JSONLike):
1352
1738
 
1353
1739
  @dataclass
1354
1740
  class ElementRepeats:
1741
+ """
1742
+ A repetition rule.
1743
+
1744
+ Parameters
1745
+ ----------
1746
+ number:
1747
+ The number of times to repeat.
1748
+ where:
1749
+ A filtering rule for what to repeat.
1750
+ """
1751
+
1752
+ #: The number of times to repeat.
1355
1753
  number: int
1754
+ #: A filtering rule for what to repeat.
1356
1755
  where: Optional[ElementFilter] = None