hpcflow-new2 0.2.0a163__py3-none-any.whl → 0.2.0a166__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/_version.py +1 -1
- hpcflow/sdk/core/actions.py +24 -7
- hpcflow/sdk/core/commands.py +14 -2
- hpcflow/sdk/core/errors.py +16 -0
- hpcflow/sdk/core/parameters.py +26 -2
- hpcflow/sdk/core/task.py +209 -59
- hpcflow/sdk/core/task_schema.py +1 -1
- hpcflow/sdk/persistence/base.py +6 -0
- hpcflow/sdk/persistence/zarr.py +2 -0
- hpcflow/tests/unit/test_action.py +170 -0
- hpcflow/tests/unit/test_element_set.py +10 -0
- hpcflow/tests/unit/test_input_source.py +601 -1
- hpcflow/tests/unit/test_persistence.py +4 -1
- hpcflow/tests/unit/test_task.py +1 -1
- {hpcflow_new2-0.2.0a163.dist-info → hpcflow_new2-0.2.0a166.dist-info}/METADATA +1 -1
- {hpcflow_new2-0.2.0a163.dist-info → hpcflow_new2-0.2.0a166.dist-info}/RECORD +18 -18
- {hpcflow_new2-0.2.0a163.dist-info → hpcflow_new2-0.2.0a166.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a163.dist-info → hpcflow_new2-0.2.0a166.dist-info}/entry_points.txt +0 -0
hpcflow/_version.py
CHANGED
@@ -1 +1 @@
|
|
1
|
-
__version__ = "0.2.
|
1
|
+
__version__ = "0.2.0a166"
|
hpcflow/sdk/core/actions.py
CHANGED
@@ -141,6 +141,7 @@ class ElementActionRun:
|
|
141
141
|
element_action,
|
142
142
|
index: int,
|
143
143
|
data_idx: Dict,
|
144
|
+
commands_idx: List[int],
|
144
145
|
start_time: Union[datetime, None],
|
145
146
|
end_time: Union[datetime, None],
|
146
147
|
snapshot_start: Union[Dict, None],
|
@@ -157,6 +158,7 @@ class ElementActionRun:
|
|
157
158
|
self._element_action = element_action
|
158
159
|
self._index = index # local index of this run with the action
|
159
160
|
self._data_idx = data_idx
|
161
|
+
self._commands_idx = commands_idx
|
160
162
|
self._start_time = start_time
|
161
163
|
self._end_time = end_time
|
162
164
|
self._submission_idx = submission_idx
|
@@ -222,6 +224,10 @@ class ElementActionRun:
|
|
222
224
|
def data_idx(self):
|
223
225
|
return self._data_idx
|
224
226
|
|
227
|
+
@property
|
228
|
+
def commands_idx(self):
|
229
|
+
return self._commands_idx
|
230
|
+
|
225
231
|
@property
|
226
232
|
def metadata(self):
|
227
233
|
return self._metadata
|
@@ -715,11 +721,13 @@ class ElementActionRun:
|
|
715
721
|
|
716
722
|
shell_vars = {} # keys are cmd_idx, each value is a list of tuples
|
717
723
|
for cmd_idx, command in enumerate(self.action.commands):
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
|
724
|
+
if cmd_idx in self.commands_idx:
|
725
|
+
# only execute commands that have no rules, or all valid rules:
|
726
|
+
cmd_str, shell_vars_i = command.get_command_line(
|
727
|
+
EAR=self, shell=jobscript.shell, env=env
|
728
|
+
)
|
729
|
+
shell_vars[cmd_idx] = shell_vars_i
|
730
|
+
command_lns.append(cmd_str)
|
723
731
|
|
724
732
|
commands = "\n".join(command_lns) + "\n"
|
725
733
|
|
@@ -1025,6 +1033,7 @@ class ActionRule(JSONLike):
|
|
1025
1033
|
|
1026
1034
|
self.rule = rule
|
1027
1035
|
self.action = None # assigned by parent action
|
1036
|
+
self.command = None # assigned by parent command
|
1028
1037
|
|
1029
1038
|
def __eq__(self, other):
|
1030
1039
|
if type(other) is not self.__class__:
|
@@ -1958,9 +1967,17 @@ class Action(JSONLike):
|
|
1958
1967
|
return True
|
1959
1968
|
|
1960
1969
|
@TimeIt.decorator
|
1961
|
-
def test_rules(self, element_iter) -> List[
|
1970
|
+
def test_rules(self, element_iter) -> Tuple[bool, List[int]]:
|
1962
1971
|
"""Test all rules against the specified element iteration."""
|
1963
|
-
|
1972
|
+
rules_valid = [rule.test(element_iteration=element_iter) for rule in self.rules]
|
1973
|
+
action_valid = all(rules_valid)
|
1974
|
+
commands_idx = []
|
1975
|
+
if action_valid:
|
1976
|
+
for cmd_idx, cmd in enumerate(self.commands):
|
1977
|
+
if any(not i.test(element_iteration=element_iter) for i in cmd.rules):
|
1978
|
+
continue
|
1979
|
+
commands_idx.append(cmd_idx)
|
1980
|
+
return action_valid, commands_idx
|
1964
1981
|
|
1965
1982
|
def get_required_executables(self) -> Tuple[str]:
|
1966
1983
|
"""Return executable labels required by this action."""
|
hpcflow/sdk/core/commands.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from dataclasses import dataclass
|
1
|
+
from dataclasses import dataclass, field
|
2
2
|
from functools import partial
|
3
3
|
from pathlib import Path
|
4
4
|
import re
|
@@ -6,15 +6,24 @@ from typing import Dict, Iterable, List, Optional, Tuple, Union
|
|
6
6
|
|
7
7
|
import numpy as np
|
8
8
|
|
9
|
+
from hpcflow.sdk import app
|
9
10
|
from hpcflow.sdk.core.element import ElementResources
|
10
11
|
from hpcflow.sdk.core.errors import NoCLIFormatMethodError
|
11
|
-
from hpcflow.sdk.core.json_like import JSONLike
|
12
|
+
from hpcflow.sdk.core.json_like import ChildObjectSpec, JSONLike
|
12
13
|
from hpcflow.sdk.core.parameters import ParameterValue
|
13
14
|
|
14
15
|
|
15
16
|
@dataclass
|
16
17
|
class Command(JSONLike):
|
17
18
|
_app_attr = "app"
|
19
|
+
_child_objects = (
|
20
|
+
ChildObjectSpec(
|
21
|
+
name="rules",
|
22
|
+
class_name="ActionRule",
|
23
|
+
is_multiple=True,
|
24
|
+
parent_ref="command",
|
25
|
+
),
|
26
|
+
)
|
18
27
|
|
19
28
|
command: Optional[str] = None
|
20
29
|
executable: Optional[str] = None
|
@@ -23,6 +32,7 @@ class Command(JSONLike):
|
|
23
32
|
stdout: Optional[str] = None
|
24
33
|
stderr: Optional[str] = None
|
25
34
|
stdin: Optional[str] = None
|
35
|
+
rules: Optional[List[app.ActionRule]] = field(default_factory=lambda: [])
|
26
36
|
|
27
37
|
def __repr__(self) -> str:
|
28
38
|
out = []
|
@@ -40,6 +50,8 @@ class Command(JSONLike):
|
|
40
50
|
out.append(f"stderr={self.stderr!r}")
|
41
51
|
if self.stdin:
|
42
52
|
out.append(f"stdin={self.stdin!r}")
|
53
|
+
if self.rules:
|
54
|
+
out.append(f"rules={self.rules!r}")
|
43
55
|
|
44
56
|
return f"{self.__class__.__name__}({', '.join(out)})"
|
45
57
|
|
hpcflow/sdk/core/errors.py
CHANGED
@@ -55,6 +55,18 @@ class ExtraInputs(Exception):
|
|
55
55
|
super().__init__(message)
|
56
56
|
|
57
57
|
|
58
|
+
class UnavailableInputSource(ValueError):
|
59
|
+
pass
|
60
|
+
|
61
|
+
|
62
|
+
class InapplicableInputSourceElementIters(ValueError):
|
63
|
+
pass
|
64
|
+
|
65
|
+
|
66
|
+
class NoCoincidentInputSources(ValueError):
|
67
|
+
pass
|
68
|
+
|
69
|
+
|
58
70
|
class TaskTemplateInvalidNesting(ValueError):
|
59
71
|
pass
|
60
72
|
|
@@ -131,6 +143,10 @@ class MalformedParameterPathError(ValueError):
|
|
131
143
|
pass
|
132
144
|
|
133
145
|
|
146
|
+
class MalformedNestingOrderPath(ValueError):
|
147
|
+
pass
|
148
|
+
|
149
|
+
|
134
150
|
class UnknownResourceSpecItemError(ValueError):
|
135
151
|
pass
|
136
152
|
|
hpcflow/sdk/core/parameters.py
CHANGED
@@ -869,6 +869,11 @@ class ValueSequence(JSONLike):
|
|
869
869
|
vals = (vals.T).tolist()
|
870
870
|
return vals
|
871
871
|
|
872
|
+
@classmethod
|
873
|
+
def _values_from_random_uniform(cls, num, low=0.0, high=1.0, seed=None):
|
874
|
+
rng = np.random.default_rng(seed)
|
875
|
+
return rng.uniform(low=low, high=high, size=num).tolist()
|
876
|
+
|
872
877
|
@classmethod
|
873
878
|
def from_linear_space(
|
874
879
|
cls,
|
@@ -1027,6 +1032,25 @@ class ValueSequence(JSONLike):
|
|
1027
1032
|
obj._values_method_args = args
|
1028
1033
|
return obj
|
1029
1034
|
|
1035
|
+
@classmethod
|
1036
|
+
def from_random_uniform(
|
1037
|
+
cls,
|
1038
|
+
path,
|
1039
|
+
num,
|
1040
|
+
low=0.0,
|
1041
|
+
high=1.0,
|
1042
|
+
seed=None,
|
1043
|
+
nesting_order=0,
|
1044
|
+
label=None,
|
1045
|
+
**kwargs,
|
1046
|
+
):
|
1047
|
+
args = {"low": low, "high": high, "num": num, "seed": seed, **kwargs}
|
1048
|
+
values = cls._values_from_random_uniform(**args)
|
1049
|
+
obj = cls(values=values, path=path, nesting_order=nesting_order, label=label)
|
1050
|
+
obj._values_method = "from_random_uniform"
|
1051
|
+
obj._values_method_args = args
|
1052
|
+
return obj
|
1053
|
+
|
1030
1054
|
|
1031
1055
|
@dataclass
|
1032
1056
|
class AbstractInputValue(JSONLike):
|
@@ -1793,7 +1817,7 @@ class InputSource(JSONLike):
|
|
1793
1817
|
f"task_source_type={self.task_source_type.name.lower()!r}",
|
1794
1818
|
)
|
1795
1819
|
|
1796
|
-
if self.element_iters:
|
1820
|
+
if self.element_iters is not None:
|
1797
1821
|
args_lst.append(f"element_iters={self.element_iters}")
|
1798
1822
|
|
1799
1823
|
if self.where is not None:
|
@@ -1831,7 +1855,7 @@ class InputSource(JSONLike):
|
|
1831
1855
|
out = [self.source_type.name.lower()]
|
1832
1856
|
if self.source_type is InputSourceType.TASK:
|
1833
1857
|
out += [str(self.task_ref), self.task_source_type.name.lower()]
|
1834
|
-
if self.element_iters:
|
1858
|
+
if self.element_iters is not None:
|
1835
1859
|
out += ["[" + ",".join(f"{i}" for i in self.element_iters) + "]"]
|
1836
1860
|
elif self.source_type is InputSourceType.IMPORT:
|
1837
1861
|
out += [str(self.import_ref)]
|