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 CHANGED
@@ -1 +1 @@
1
- __version__ = "0.2.0a163"
1
+ __version__ = "0.2.0a166"
@@ -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
- cmd_str, shell_vars_i = command.get_command_line(
719
- EAR=self, shell=jobscript.shell, env=env
720
- )
721
- shell_vars[cmd_idx] = shell_vars_i
722
- command_lns.append(cmd_str)
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[bool]:
1970
+ def test_rules(self, element_iter) -> Tuple[bool, List[int]]:
1962
1971
  """Test all rules against the specified element iteration."""
1963
- return [i.test(element_iteration=element_iter) for i in self.rules]
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."""
@@ -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
 
@@ -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
 
@@ -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)]