hpcflow-new2 0.2.0a211__py3-none-any.whl → 0.2.0a213__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 (34) hide show
  1. hpcflow/_version.py +1 -1
  2. hpcflow/sdk/app.py +15 -24
  3. hpcflow/sdk/config/callbacks.py +5 -10
  4. hpcflow/sdk/config/config.py +11 -23
  5. hpcflow/sdk/core/actions.py +25 -40
  6. hpcflow/sdk/core/app_aware.py +1 -0
  7. hpcflow/sdk/core/cache.py +3 -3
  8. hpcflow/sdk/core/command_files.py +2 -4
  9. hpcflow/sdk/core/element.py +40 -72
  10. hpcflow/sdk/core/enums.py +1 -0
  11. hpcflow/sdk/core/json_like.py +18 -30
  12. hpcflow/sdk/core/object_list.py +14 -21
  13. hpcflow/sdk/core/parameters.py +24 -10
  14. hpcflow/sdk/core/task.py +18 -32
  15. hpcflow/sdk/core/task_schema.py +1 -1
  16. hpcflow/sdk/core/types.py +1 -2
  17. hpcflow/sdk/core/utils.py +10 -17
  18. hpcflow/sdk/core/validation.py +11 -22
  19. hpcflow/sdk/core/workflow.py +16 -24
  20. hpcflow/sdk/persistence/base.py +68 -116
  21. hpcflow/sdk/persistence/discovery.py +1 -0
  22. hpcflow/sdk/persistence/zarr.py +12 -12
  23. hpcflow/sdk/submission/enums.py +1 -0
  24. hpcflow/sdk/submission/jobscript.py +8 -10
  25. hpcflow/sdk/submission/schedulers/direct.py +2 -4
  26. hpcflow/sdk/submission/shells/__init__.py +1 -0
  27. hpcflow/sdk/submission/submission.py +11 -13
  28. hpcflow/sdk/utils/arrays.py +2 -4
  29. hpcflow/tests/unit/test_multi_path_sequences.py +23 -0
  30. {hpcflow_new2-0.2.0a211.dist-info → hpcflow_new2-0.2.0a213.dist-info}/METADATA +2 -2
  31. {hpcflow_new2-0.2.0a211.dist-info → hpcflow_new2-0.2.0a213.dist-info}/RECORD +34 -34
  32. {hpcflow_new2-0.2.0a211.dist-info → hpcflow_new2-0.2.0a213.dist-info}/LICENSE +0 -0
  33. {hpcflow_new2-0.2.0a211.dist-info → hpcflow_new2-0.2.0a213.dist-info}/WHEEL +0 -0
  34. {hpcflow_new2-0.2.0a211.dist-info → hpcflow_new2-0.2.0a213.dist-info}/entry_points.txt +0 -0
@@ -874,8 +874,7 @@ class ElementIteration(AppAware):
874
874
  typ: str | None = None,
875
875
  as_strings: Literal[True],
876
876
  use_task_index: bool = False,
877
- ) -> Mapping[str, str]:
878
- ...
877
+ ) -> Mapping[str, str]: ...
879
878
 
880
879
  @overload
881
880
  def get_parameter_sources(
@@ -887,8 +886,7 @@ class ElementIteration(AppAware):
887
886
  typ: str | None = None,
888
887
  as_strings: Literal[False] = False,
889
888
  use_task_index: bool = False,
890
- ) -> Mapping[str, ParamSource | list[ParamSource]]:
891
- ...
889
+ ) -> Mapping[str, ParamSource | list[ParamSource]]: ...
892
890
 
893
891
  @TimeIt.decorator
894
892
  def get_parameter_sources(
@@ -980,15 +978,13 @@ class ElementIteration(AppAware):
980
978
  def get_EAR_dependencies(
981
979
  self,
982
980
  as_objects: Literal[False] = False,
983
- ) -> set[int]:
984
- ...
981
+ ) -> set[int]: ...
985
982
 
986
983
  @overload
987
984
  def get_EAR_dependencies(
988
985
  self,
989
986
  as_objects: Literal[True],
990
- ) -> list[ElementActionRun]:
991
- ...
987
+ ) -> list[ElementActionRun]: ...
992
988
 
993
989
  @TimeIt.decorator
994
990
  def get_EAR_dependencies(
@@ -1023,14 +1019,12 @@ class ElementIteration(AppAware):
1023
1019
  @overload
1024
1020
  def get_element_iteration_dependencies(
1025
1021
  self, as_objects: Literal[True]
1026
- ) -> list[ElementIteration]:
1027
- ...
1022
+ ) -> list[ElementIteration]: ...
1028
1023
 
1029
1024
  @overload
1030
1025
  def get_element_iteration_dependencies(
1031
1026
  self, as_objects: Literal[False] = False
1032
- ) -> set[int]:
1033
- ...
1027
+ ) -> set[int]: ...
1034
1028
 
1035
1029
  @TimeIt.decorator
1036
1030
  def get_element_iteration_dependencies(
@@ -1048,15 +1042,13 @@ class ElementIteration(AppAware):
1048
1042
  def get_element_dependencies(
1049
1043
  self,
1050
1044
  as_objects: Literal[False] = False,
1051
- ) -> set[int]:
1052
- ...
1045
+ ) -> set[int]: ...
1053
1046
 
1054
1047
  @overload
1055
1048
  def get_element_dependencies(
1056
1049
  self,
1057
1050
  as_objects: Literal[True],
1058
- ) -> list[Element]:
1059
- ...
1051
+ ) -> list[Element]: ...
1060
1052
 
1061
1053
  @TimeIt.decorator
1062
1054
  def get_element_dependencies(
@@ -1085,12 +1077,10 @@ class ElementIteration(AppAware):
1085
1077
  return out
1086
1078
 
1087
1079
  @overload
1088
- def get_task_dependencies(self, as_objects: Literal[False] = False) -> set[int]:
1089
- ...
1080
+ def get_task_dependencies(self, as_objects: Literal[False] = False) -> set[int]: ...
1090
1081
 
1091
1082
  @overload
1092
- def get_task_dependencies(self, as_objects: Literal[True]) -> list[WorkflowTask]:
1093
- ...
1083
+ def get_task_dependencies(self, as_objects: Literal[True]) -> list[WorkflowTask]: ...
1094
1084
 
1095
1085
  def get_task_dependencies(
1096
1086
  self, as_objects: bool = False
@@ -1128,12 +1118,10 @@ class ElementIteration(AppAware):
1128
1118
  yield from elem.iterations
1129
1119
 
1130
1120
  @overload
1131
- def get_dependent_EARs(self, as_objects: Literal[False] = False) -> set[int]:
1132
- ...
1121
+ def get_dependent_EARs(self, as_objects: Literal[False] = False) -> set[int]: ...
1133
1122
 
1134
1123
  @overload
1135
- def get_dependent_EARs(self, as_objects: Literal[True]) -> list[ElementActionRun]:
1136
- ...
1124
+ def get_dependent_EARs(self, as_objects: Literal[True]) -> list[ElementActionRun]: ...
1137
1125
 
1138
1126
  @TimeIt.decorator
1139
1127
  def get_dependent_EARs(
@@ -1157,14 +1145,12 @@ class ElementIteration(AppAware):
1157
1145
  @overload
1158
1146
  def get_dependent_element_iterations(
1159
1147
  self, as_objects: Literal[True]
1160
- ) -> list[ElementIteration]:
1161
- ...
1148
+ ) -> list[ElementIteration]: ...
1162
1149
 
1163
1150
  @overload
1164
1151
  def get_dependent_element_iterations(
1165
1152
  self, as_objects: Literal[False] = False
1166
- ) -> set[int]:
1167
- ...
1153
+ ) -> set[int]: ...
1168
1154
 
1169
1155
  @TimeIt.decorator
1170
1156
  def get_dependent_element_iterations(
@@ -1187,15 +1173,13 @@ class ElementIteration(AppAware):
1187
1173
  def get_dependent_elements(
1188
1174
  self,
1189
1175
  as_objects: Literal[True],
1190
- ) -> list[Element]:
1191
- ...
1176
+ ) -> list[Element]: ...
1192
1177
 
1193
1178
  @overload
1194
1179
  def get_dependent_elements(
1195
1180
  self,
1196
1181
  as_objects: Literal[False] = False,
1197
- ) -> set[int]:
1198
- ...
1182
+ ) -> set[int]: ...
1199
1183
 
1200
1184
  @TimeIt.decorator
1201
1185
  def get_dependent_elements(
@@ -1220,15 +1204,13 @@ class ElementIteration(AppAware):
1220
1204
  def get_dependent_tasks(
1221
1205
  self,
1222
1206
  as_objects: Literal[True],
1223
- ) -> list[WorkflowTask]:
1224
- ...
1207
+ ) -> list[WorkflowTask]: ...
1225
1208
 
1226
1209
  @overload
1227
1210
  def get_dependent_tasks(
1228
1211
  self,
1229
1212
  as_objects: Literal[False] = False,
1230
- ) -> set[int]:
1231
- ...
1213
+ ) -> set[int]: ...
1232
1214
 
1233
1215
  def get_dependent_tasks(
1234
1216
  self,
@@ -1644,8 +1626,7 @@ class Element(AppAware):
1644
1626
  typ: str | None = None,
1645
1627
  as_strings: Literal[False] = False,
1646
1628
  use_task_index: bool = False,
1647
- ) -> Mapping[str, ParamSource | list[ParamSource]]:
1648
- ...
1629
+ ) -> Mapping[str, ParamSource | list[ParamSource]]: ...
1649
1630
 
1650
1631
  @overload
1651
1632
  def get_parameter_sources(
@@ -1657,8 +1638,7 @@ class Element(AppAware):
1657
1638
  typ: str | None = None,
1658
1639
  as_strings: Literal[True],
1659
1640
  use_task_index: bool = False,
1660
- ) -> Mapping[str, str]:
1661
- ...
1641
+ ) -> Mapping[str, str]: ...
1662
1642
 
1663
1643
  def get_parameter_sources(
1664
1644
  self,
@@ -1716,12 +1696,12 @@ class Element(AppAware):
1716
1696
  )
1717
1697
 
1718
1698
  @overload
1719
- def get_EAR_dependencies(self, as_objects: Literal[True]) -> list[ElementActionRun]:
1720
- ...
1699
+ def get_EAR_dependencies(
1700
+ self, as_objects: Literal[True]
1701
+ ) -> list[ElementActionRun]: ...
1721
1702
 
1722
1703
  @overload
1723
- def get_EAR_dependencies(self, as_objects: Literal[False] = False) -> set[int]:
1724
- ...
1704
+ def get_EAR_dependencies(self, as_objects: Literal[False] = False) -> set[int]: ...
1725
1705
 
1726
1706
  @TimeIt.decorator
1727
1707
  def get_EAR_dependencies(
@@ -1735,14 +1715,12 @@ class Element(AppAware):
1735
1715
  @overload
1736
1716
  def get_element_iteration_dependencies(
1737
1717
  self, as_objects: Literal[True]
1738
- ) -> list[ElementIteration]:
1739
- ...
1718
+ ) -> list[ElementIteration]: ...
1740
1719
 
1741
1720
  @overload
1742
1721
  def get_element_iteration_dependencies(
1743
1722
  self, as_objects: Literal[False] = False
1744
- ) -> set[int]:
1745
- ...
1723
+ ) -> set[int]: ...
1746
1724
 
1747
1725
  def get_element_iteration_dependencies(
1748
1726
  self, as_objects: bool = False
@@ -1756,12 +1734,12 @@ class Element(AppAware):
1756
1734
  return self.latest_iteration.get_element_iteration_dependencies()
1757
1735
 
1758
1736
  @overload
1759
- def get_element_dependencies(self, as_objects: Literal[True]) -> list[Element]:
1760
- ...
1737
+ def get_element_dependencies(self, as_objects: Literal[True]) -> list[Element]: ...
1761
1738
 
1762
1739
  @overload
1763
- def get_element_dependencies(self, as_objects: Literal[False] = False) -> set[int]:
1764
- ...
1740
+ def get_element_dependencies(
1741
+ self, as_objects: Literal[False] = False
1742
+ ) -> set[int]: ...
1765
1743
 
1766
1744
  def get_element_dependencies(
1767
1745
  self, as_objects: bool = False
@@ -1777,12 +1755,10 @@ class Element(AppAware):
1777
1755
  return self.latest_iteration.get_input_dependencies()
1778
1756
 
1779
1757
  @overload
1780
- def get_task_dependencies(self, as_objects: Literal[True]) -> list[WorkflowTask]:
1781
- ...
1758
+ def get_task_dependencies(self, as_objects: Literal[True]) -> list[WorkflowTask]: ...
1782
1759
 
1783
1760
  @overload
1784
- def get_task_dependencies(self, as_objects: Literal[False] = False) -> set[int]:
1785
- ...
1761
+ def get_task_dependencies(self, as_objects: Literal[False] = False) -> set[int]: ...
1786
1762
 
1787
1763
  def get_task_dependencies(
1788
1764
  self, as_objects: bool = False
@@ -1797,12 +1773,10 @@ class Element(AppAware):
1797
1773
  return self.latest_iteration.get_task_dependencies()
1798
1774
 
1799
1775
  @overload
1800
- def get_dependent_EARs(self, as_objects: Literal[True]) -> list[ElementActionRun]:
1801
- ...
1776
+ def get_dependent_EARs(self, as_objects: Literal[True]) -> list[ElementActionRun]: ...
1802
1777
 
1803
1778
  @overload
1804
- def get_dependent_EARs(self, as_objects: Literal[False] = False) -> set[int]:
1805
- ...
1779
+ def get_dependent_EARs(self, as_objects: Literal[False] = False) -> set[int]: ...
1806
1780
 
1807
1781
  def get_dependent_EARs(
1808
1782
  self, as_objects: bool = False
@@ -1815,14 +1789,12 @@ class Element(AppAware):
1815
1789
  @overload
1816
1790
  def get_dependent_element_iterations(
1817
1791
  self, as_objects: Literal[True]
1818
- ) -> list[ElementIteration]:
1819
- ...
1792
+ ) -> list[ElementIteration]: ...
1820
1793
 
1821
1794
  @overload
1822
1795
  def get_dependent_element_iterations(
1823
1796
  self, as_objects: Literal[False] = False
1824
- ) -> set[int]:
1825
- ...
1797
+ ) -> set[int]: ...
1826
1798
 
1827
1799
  def get_dependent_element_iterations(
1828
1800
  self, as_objects: bool = False
@@ -1834,12 +1806,10 @@ class Element(AppAware):
1834
1806
  return self.latest_iteration.get_dependent_element_iterations()
1835
1807
 
1836
1808
  @overload
1837
- def get_dependent_elements(self, as_objects: Literal[True]) -> list[Element]:
1838
- ...
1809
+ def get_dependent_elements(self, as_objects: Literal[True]) -> list[Element]: ...
1839
1810
 
1840
1811
  @overload
1841
- def get_dependent_elements(self, as_objects: Literal[False] = False) -> set[int]:
1842
- ...
1812
+ def get_dependent_elements(self, as_objects: Literal[False] = False) -> set[int]: ...
1843
1813
 
1844
1814
  def get_dependent_elements(
1845
1815
  self, as_objects: bool = False
@@ -1850,12 +1820,10 @@ class Element(AppAware):
1850
1820
  return self.latest_iteration.get_dependent_elements()
1851
1821
 
1852
1822
  @overload
1853
- def get_dependent_tasks(self, as_objects: Literal[True]) -> list[WorkflowTask]:
1854
- ...
1823
+ def get_dependent_tasks(self, as_objects: Literal[True]) -> list[WorkflowTask]: ...
1855
1824
 
1856
1825
  @overload
1857
- def get_dependent_tasks(self, as_objects: Literal[False] = False) -> set[int]:
1858
- ...
1826
+ def get_dependent_tasks(self, as_objects: Literal[False] = False) -> set[int]: ...
1859
1827
 
1860
1828
  def get_dependent_tasks(
1861
1829
  self, as_objects: bool = False
hpcflow/sdk/core/enums.py CHANGED
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Core enumeration types.
3
3
  """
4
+
4
5
  from __future__ import annotations
5
6
  from collections.abc import Sequence
6
7
  from dataclasses import dataclass
@@ -2,6 +2,7 @@
2
2
  Serialization and deserialization mechanism intended to map between a complex
3
3
  graph of objects and either JSON or YAML.
4
4
  """
5
+
5
6
  from __future__ import annotations
6
7
 
7
8
  from collections import defaultdict
@@ -70,8 +71,7 @@ def to_json_like(
70
71
  shared_data: _JSONDeserState = None,
71
72
  parent_refs: dict | None = None,
72
73
  path: list | None = None,
73
- ) -> tuple[int, _JSONDeserState]:
74
- ...
74
+ ) -> tuple[int, _JSONDeserState]: ...
75
75
 
76
76
 
77
77
  @overload
@@ -80,8 +80,7 @@ def to_json_like(
80
80
  shared_data: _JSONDeserState = None,
81
81
  parent_refs: dict | None = None,
82
82
  path: list | None = None,
83
- ) -> tuple[float, _JSONDeserState]:
84
- ...
83
+ ) -> tuple[float, _JSONDeserState]: ...
85
84
 
86
85
 
87
86
  @overload
@@ -90,8 +89,7 @@ def to_json_like(
90
89
  shared_data: _JSONDeserState = None,
91
90
  parent_refs: dict | None = None,
92
91
  path: list | None = None,
93
- ) -> tuple[str, _JSONDeserState]:
94
- ...
92
+ ) -> tuple[str, _JSONDeserState]: ...
95
93
 
96
94
 
97
95
  @overload
@@ -100,8 +98,7 @@ def to_json_like(
100
98
  shared_data: _JSONDeserState = None,
101
99
  parent_refs: dict | None = None,
102
100
  path: list | None = None,
103
- ) -> tuple[None, _JSONDeserState]:
104
- ...
101
+ ) -> tuple[None, _JSONDeserState]: ...
105
102
 
106
103
 
107
104
  @overload
@@ -110,8 +107,7 @@ def to_json_like(
110
107
  shared_data: _JSONDeserState = None,
111
108
  parent_refs: dict | None = None,
112
109
  path: list | None = None,
113
- ) -> tuple[str, _JSONDeserState]:
114
- ...
110
+ ) -> tuple[str, _JSONDeserState]: ...
115
111
 
116
112
 
117
113
  @overload
@@ -120,8 +116,7 @@ def to_json_like(
120
116
  shared_data: _JSONDeserState = None,
121
117
  parent_refs: dict | None = None,
122
118
  path: list | None = None,
123
- ) -> tuple[Sequence[JSONed], _JSONDeserState]:
124
- ...
119
+ ) -> tuple[Sequence[JSONed], _JSONDeserState]: ...
125
120
 
126
121
 
127
122
  @overload
@@ -130,8 +125,7 @@ def to_json_like(
130
125
  shared_data: _JSONDeserState = None,
131
126
  parent_refs: dict | None = None,
132
127
  path: list | None = None,
133
- ) -> tuple[Sequence[JSONed], _JSONDeserState]:
134
- ...
128
+ ) -> tuple[Sequence[JSONed], _JSONDeserState]: ...
135
129
 
136
130
 
137
131
  @overload
@@ -140,8 +134,7 @@ def to_json_like(
140
134
  shared_data: _JSONDeserState = None,
141
135
  parent_refs: dict | None = None,
142
136
  path: list | None = None,
143
- ) -> tuple[Sequence[JSONed], _JSONDeserState]:
144
- ...
137
+ ) -> tuple[Sequence[JSONed], _JSONDeserState]: ...
145
138
 
146
139
 
147
140
  @overload
@@ -150,8 +143,7 @@ def to_json_like(
150
143
  shared_data: _JSONDeserState = None,
151
144
  parent_refs: dict | None = None,
152
145
  path: list | None = None,
153
- ) -> tuple[Mapping[str, JSONed], _JSONDeserState]:
154
- ...
146
+ ) -> tuple[Mapping[str, JSONed], _JSONDeserState]: ...
155
147
 
156
148
 
157
149
  @overload
@@ -160,8 +152,7 @@ def to_json_like(
160
152
  shared_data: _JSONDeserState = None,
161
153
  parent_refs: dict | None = None,
162
154
  path: list | None = None,
163
- ) -> tuple[Mapping[str, JSONed], _JSONDeserState]:
164
- ...
155
+ ) -> tuple[Mapping[str, JSONed], _JSONDeserState]: ...
165
156
 
166
157
 
167
158
  def to_json_like(
@@ -350,13 +341,13 @@ class BaseJSONLike:
350
341
  @classmethod
351
342
  def _set_class_namespace(
352
343
  cls, value: SimpleNamespace, is_dict: Literal[False] = False
353
- ) -> None:
354
- ...
344
+ ) -> None: ...
355
345
 
356
346
  @overload
357
347
  @classmethod
358
- def _set_class_namespace(cls, value: dict[str, Any], is_dict: Literal[True]) -> None:
359
- ...
348
+ def _set_class_namespace(
349
+ cls, value: dict[str, Any], is_dict: Literal[True]
350
+ ) -> None: ...
360
351
 
361
352
  @classmethod
362
353
  def _set_class_namespace(
@@ -393,8 +384,7 @@ class BaseJSONLike:
393
384
  cls,
394
385
  json_like: str,
395
386
  shared_data: Mapping[str, ObjectList[JSONable]] | None = None,
396
- ) -> Self | None:
397
- ...
387
+ ) -> Self | None: ...
398
388
 
399
389
  @overload
400
390
  @classmethod
@@ -402,8 +392,7 @@ class BaseJSONLike:
402
392
  cls,
403
393
  json_like: Sequence[Mapping[str, JSONed]] | Mapping[str, JSONed],
404
394
  shared_data: Mapping[str, ObjectList[JSONable]] | None = None,
405
- ) -> Self:
406
- ...
395
+ ) -> Self: ...
407
396
 
408
397
  @overload
409
398
  @classmethod
@@ -411,8 +400,7 @@ class BaseJSONLike:
411
400
  cls,
412
401
  json_like: None,
413
402
  shared_data: Mapping[str, ObjectList[JSONable]] | None = None,
414
- ) -> None:
415
- ...
403
+ ) -> None: ...
416
404
 
417
405
  @classmethod
418
406
  def from_json_like(
@@ -92,12 +92,10 @@ class ObjectList(JSONLike, Generic[T]):
92
92
  return self._objects.__iter__()
93
93
 
94
94
  @overload
95
- def __getitem__(self, key: int) -> T:
96
- ...
95
+ def __getitem__(self, key: int) -> T: ...
97
96
 
98
97
  @overload
99
- def __getitem__(self, key: slice) -> list[T]:
100
- ...
98
+ def __getitem__(self, key: slice) -> list[T]: ...
101
99
 
102
100
  def __getitem__(self, key: int | slice) -> T | list[T]:
103
101
  """Provide list-like index access."""
@@ -177,14 +175,12 @@ class ObjectList(JSONLike, Generic[T]):
177
175
  @overload
178
176
  def add_object(
179
177
  self, obj: T, index: int = -1, *, skip_duplicates: Literal[False] = False
180
- ) -> int:
181
- ...
178
+ ) -> int: ...
182
179
 
183
180
  @overload
184
181
  def add_object(
185
182
  self, obj: T, index: int = -1, *, skip_duplicates: Literal[True]
186
- ) -> int | None:
187
- ...
183
+ ) -> int | None: ...
188
184
 
189
185
  def add_object(
190
186
  self, obj: T, index: int = -1, *, skip_duplicates: bool = False
@@ -360,14 +356,12 @@ class DotAccessObjectList(ObjectList[T], Generic[T]):
360
356
  @overload
361
357
  def add_object(
362
358
  self, obj: T, index: int = -1, *, skip_duplicates: Literal[False] = False
363
- ) -> int:
364
- ...
359
+ ) -> int: ...
365
360
 
366
361
  @overload
367
362
  def add_object(
368
363
  self, obj: T, index: int = -1, *, skip_duplicates: Literal[True]
369
- ) -> int | None:
370
- ...
364
+ ) -> int | None: ...
371
365
 
372
366
  def add_object(
373
367
  self, obj: T, index: int = -1, *, skip_duplicates: bool = False
@@ -424,8 +418,7 @@ class AppDataList(DotAccessObjectList[T], Generic[T]):
424
418
  json_like: str,
425
419
  shared_data: Mapping[str, ObjectList[JSONable]] | None = None,
426
420
  is_hashed: bool = False,
427
- ) -> Self | None:
428
- ...
421
+ ) -> Self | None: ...
429
422
 
430
423
  @overload
431
424
  @classmethod
@@ -434,8 +427,7 @@ class AppDataList(DotAccessObjectList[T], Generic[T]):
434
427
  json_like: Mapping[str, JSONed] | Sequence[Mapping[str, JSONed]],
435
428
  shared_data: Mapping[str, ObjectList[JSONable]] | None = None,
436
429
  is_hashed: bool = False,
437
- ) -> Self:
438
- ...
430
+ ) -> Self: ...
439
431
 
440
432
  @overload
441
433
  @classmethod
@@ -444,8 +436,7 @@ class AppDataList(DotAccessObjectList[T], Generic[T]):
444
436
  json_like: None,
445
437
  shared_data: Mapping[str, ObjectList[JSONable]] | None = None,
446
438
  is_hashed: bool = False,
447
- ) -> None:
448
- ...
439
+ ) -> None: ...
449
440
 
450
441
  @classmethod
451
442
  def from_json_like(
@@ -861,9 +852,11 @@ class ResourceList(ObjectList["ResourceSpec"]):
861
852
  return cls([resources])
862
853
  else:
863
854
  return cls(
864
- cls._app.ResourceSpec.from_json_like(cast("dict", res_i))
865
- if isinstance(res_i, dict)
866
- else cls.__ensure_non_persistent(res_i)
855
+ (
856
+ cls._app.ResourceSpec.from_json_like(cast("dict", res_i))
857
+ if isinstance(res_i, dict)
858
+ else cls.__ensure_non_persistent(res_i)
859
+ )
867
860
  for res_i in resources
868
861
  )
869
862
 
@@ -14,7 +14,7 @@ from typing import TypeVar, cast, TYPE_CHECKING
14
14
  from typing_extensions import override, TypeIs
15
15
 
16
16
  import numpy as np
17
- from scipy.stats.qmc import LatinHypercube
17
+ from scipy.stats.qmc import LatinHypercube, scale
18
18
  from valida import Schema as ValidaSchema # type: ignore
19
19
 
20
20
  from hpcflow.sdk.typing import hydrate
@@ -542,11 +542,11 @@ class SchemaInput(SchemaParameter):
542
542
  "value": v["default_value"],
543
543
  "label": k,
544
544
  }
545
- json_like["labels"][k][
546
- "default_value"
547
- ] = cls._app.InputValue.from_json_like(
548
- json_like=inp_val_kwargs,
549
- shared_data=shared_data,
545
+ json_like["labels"][k]["default_value"] = (
546
+ cls._app.InputValue.from_json_like(
547
+ json_like=inp_val_kwargs,
548
+ shared_data=shared_data,
549
+ )
550
550
  )
551
551
 
552
552
  return super().from_json_like(json_like, shared_data)
@@ -811,9 +811,9 @@ class ValueSequence(_BaseSequence):
811
811
  self._values = None
812
812
 
813
813
  self._values_group_idx: list[int] | None = None
814
- self._values_are_objs: list[
815
- bool
816
- ] | None = None # assigned initially on `make_persistent`
814
+ self._values_are_objs: list[bool] | None = (
815
+ None # assigned initially on `make_persistent`
816
+ )
817
817
 
818
818
  self._workflow: Workflow | None = None # assigned in `make_persistent`
819
819
  self._element_set: ElementSet | None = None # assigned by parent `ElementSet`
@@ -1584,6 +1584,7 @@ class MultiPathSequence(_BaseSequence):
1584
1584
  paths: Sequence[str],
1585
1585
  num_samples: int,
1586
1586
  *,
1587
+ bounds: dict[str, Sequence[float]] | None = None,
1587
1588
  scramble: bool = True,
1588
1589
  strength: int = 1,
1589
1590
  optimization: Literal["random-cd", "lloyd"] | None = None,
@@ -1598,13 +1599,24 @@ class MultiPathSequence(_BaseSequence):
1598
1599
  optimization=optimization,
1599
1600
  rng=rng,
1600
1601
  )
1602
+
1603
+ bounds = bounds or {}
1604
+
1605
+ parameter_ranges = np.array([bounds.get(path, [0, 1]) for path in paths]).T
1606
+
1607
+ lower_bound = parameter_ranges[0]
1608
+ upper_bound = parameter_ranges[1]
1609
+
1601
1610
  try:
1602
1611
  sampler = LatinHypercube(**kwargs)
1603
1612
  except TypeError:
1604
1613
  # `rng` was previously (<1.15.0) `seed`:
1605
1614
  kwargs["seed"] = kwargs.pop("rng")
1606
1615
  sampler = LatinHypercube(**kwargs)
1607
- return sampler.random(n=num_samples).T
1616
+
1617
+ samples = scale(sampler.random(n=num_samples), lower_bound, upper_bound).T
1618
+
1619
+ return samples
1608
1620
 
1609
1621
  @classmethod
1610
1622
  def from_latin_hypercube(
@@ -1612,6 +1624,7 @@ class MultiPathSequence(_BaseSequence):
1612
1624
  paths: Sequence[str],
1613
1625
  num_samples: int,
1614
1626
  *,
1627
+ bounds: dict[str, Sequence[float]] | None = None,
1615
1628
  scramble: bool = True,
1616
1629
  strength: int = 1,
1617
1630
  optimization: Literal["random-cd", "lloyd"] | None = None,
@@ -1629,6 +1642,7 @@ class MultiPathSequence(_BaseSequence):
1629
1642
  "strength": strength,
1630
1643
  "optimization": optimization,
1631
1644
  "rng": rng,
1645
+ "bounds": bounds,
1632
1646
  }
1633
1647
  values = cls._values_from_latin_hypercube(**kwargs)
1634
1648
  assert values is not None