hpcflow-new2 0.2.0a188__py3-none-any.whl → 0.2.0a190__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/__pyinstaller/hook-hpcflow.py +8 -6
- hpcflow/_version.py +1 -1
- hpcflow/app.py +1 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj.py +1 -1
- hpcflow/data/scripts/main_script_test_hdf5_out_obj.py +1 -1
- hpcflow/sdk/__init__.py +21 -15
- hpcflow/sdk/app.py +2133 -770
- hpcflow/sdk/cli.py +281 -250
- hpcflow/sdk/cli_common.py +6 -2
- hpcflow/sdk/config/__init__.py +1 -1
- hpcflow/sdk/config/callbacks.py +77 -42
- hpcflow/sdk/config/cli.py +126 -103
- hpcflow/sdk/config/config.py +578 -311
- hpcflow/sdk/config/config_file.py +131 -95
- hpcflow/sdk/config/errors.py +112 -85
- hpcflow/sdk/config/types.py +145 -0
- hpcflow/sdk/core/actions.py +1054 -994
- hpcflow/sdk/core/app_aware.py +24 -0
- hpcflow/sdk/core/cache.py +81 -63
- hpcflow/sdk/core/command_files.py +275 -185
- hpcflow/sdk/core/commands.py +111 -107
- hpcflow/sdk/core/element.py +724 -503
- hpcflow/sdk/core/enums.py +192 -0
- hpcflow/sdk/core/environment.py +74 -93
- hpcflow/sdk/core/errors.py +398 -51
- hpcflow/sdk/core/json_like.py +540 -272
- hpcflow/sdk/core/loop.py +380 -334
- hpcflow/sdk/core/loop_cache.py +160 -43
- hpcflow/sdk/core/object_list.py +370 -207
- hpcflow/sdk/core/parameters.py +728 -600
- hpcflow/sdk/core/rule.py +59 -41
- hpcflow/sdk/core/run_dir_files.py +33 -22
- hpcflow/sdk/core/task.py +1546 -1325
- hpcflow/sdk/core/task_schema.py +240 -196
- hpcflow/sdk/core/test_utils.py +126 -88
- hpcflow/sdk/core/types.py +387 -0
- hpcflow/sdk/core/utils.py +410 -305
- hpcflow/sdk/core/validation.py +82 -9
- hpcflow/sdk/core/workflow.py +1192 -1028
- hpcflow/sdk/core/zarr_io.py +98 -137
- hpcflow/sdk/demo/cli.py +46 -33
- hpcflow/sdk/helper/cli.py +18 -16
- hpcflow/sdk/helper/helper.py +75 -63
- hpcflow/sdk/helper/watcher.py +61 -28
- hpcflow/sdk/log.py +83 -59
- hpcflow/sdk/persistence/__init__.py +8 -31
- hpcflow/sdk/persistence/base.py +988 -586
- hpcflow/sdk/persistence/defaults.py +6 -0
- hpcflow/sdk/persistence/discovery.py +38 -0
- hpcflow/sdk/persistence/json.py +408 -153
- hpcflow/sdk/persistence/pending.py +158 -123
- hpcflow/sdk/persistence/store_resource.py +37 -22
- hpcflow/sdk/persistence/types.py +307 -0
- hpcflow/sdk/persistence/utils.py +14 -11
- hpcflow/sdk/persistence/zarr.py +477 -420
- hpcflow/sdk/runtime.py +44 -41
- hpcflow/sdk/submission/{jobscript_info.py → enums.py} +39 -12
- hpcflow/sdk/submission/jobscript.py +444 -404
- hpcflow/sdk/submission/schedulers/__init__.py +133 -40
- hpcflow/sdk/submission/schedulers/direct.py +97 -71
- hpcflow/sdk/submission/schedulers/sge.py +132 -126
- hpcflow/sdk/submission/schedulers/slurm.py +263 -268
- hpcflow/sdk/submission/schedulers/utils.py +7 -2
- hpcflow/sdk/submission/shells/__init__.py +14 -15
- hpcflow/sdk/submission/shells/base.py +102 -29
- hpcflow/sdk/submission/shells/bash.py +72 -55
- hpcflow/sdk/submission/shells/os_version.py +31 -30
- hpcflow/sdk/submission/shells/powershell.py +37 -29
- hpcflow/sdk/submission/submission.py +203 -257
- hpcflow/sdk/submission/types.py +143 -0
- hpcflow/sdk/typing.py +163 -12
- hpcflow/tests/conftest.py +8 -6
- hpcflow/tests/schedulers/slurm/test_slurm_submission.py +5 -2
- hpcflow/tests/scripts/test_main_scripts.py +60 -30
- hpcflow/tests/shells/wsl/test_wsl_submission.py +6 -4
- hpcflow/tests/unit/test_action.py +86 -75
- hpcflow/tests/unit/test_action_rule.py +9 -4
- hpcflow/tests/unit/test_app.py +13 -6
- hpcflow/tests/unit/test_cli.py +1 -1
- hpcflow/tests/unit/test_command.py +71 -54
- hpcflow/tests/unit/test_config.py +20 -15
- hpcflow/tests/unit/test_config_file.py +21 -18
- hpcflow/tests/unit/test_element.py +58 -62
- hpcflow/tests/unit/test_element_iteration.py +3 -1
- hpcflow/tests/unit/test_element_set.py +29 -19
- hpcflow/tests/unit/test_group.py +4 -2
- hpcflow/tests/unit/test_input_source.py +116 -93
- hpcflow/tests/unit/test_input_value.py +29 -24
- hpcflow/tests/unit/test_json_like.py +44 -35
- hpcflow/tests/unit/test_loop.py +65 -58
- hpcflow/tests/unit/test_object_list.py +17 -12
- hpcflow/tests/unit/test_parameter.py +16 -7
- hpcflow/tests/unit/test_persistence.py +48 -35
- hpcflow/tests/unit/test_resources.py +20 -18
- hpcflow/tests/unit/test_run.py +8 -3
- hpcflow/tests/unit/test_runtime.py +2 -1
- hpcflow/tests/unit/test_schema_input.py +23 -15
- hpcflow/tests/unit/test_shell.py +3 -2
- hpcflow/tests/unit/test_slurm.py +8 -7
- hpcflow/tests/unit/test_submission.py +39 -19
- hpcflow/tests/unit/test_task.py +352 -247
- hpcflow/tests/unit/test_task_schema.py +33 -20
- hpcflow/tests/unit/test_utils.py +9 -11
- hpcflow/tests/unit/test_value_sequence.py +15 -12
- hpcflow/tests/unit/test_workflow.py +114 -83
- hpcflow/tests/unit/test_workflow_template.py +0 -1
- hpcflow/tests/workflows/test_jobscript.py +2 -1
- hpcflow/tests/workflows/test_workflows.py +18 -13
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/METADATA +2 -1
- hpcflow_new2-0.2.0a190.dist-info/RECORD +165 -0
- hpcflow/sdk/core/parallel.py +0 -21
- hpcflow_new2-0.2.0a188.dist-info/RECORD +0 -158
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a188.dist-info → hpcflow_new2-0.2.0a190.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
"""
|
2
|
+
Utility base class for making classes aware of the overall application context.
|
3
|
+
"""
|
4
|
+
from __future__ import annotations
|
5
|
+
from typing import TYPE_CHECKING
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
from typing import ClassVar
|
9
|
+
from ..app import BaseApp
|
10
|
+
|
11
|
+
|
12
|
+
class AppAware:
|
13
|
+
"""
|
14
|
+
A base class that marks its subclasses as aware of the application.
|
15
|
+
|
16
|
+
Attributes
|
17
|
+
----------
|
18
|
+
_app: BaseApp
|
19
|
+
A class attribute that holds the application instance.
|
20
|
+
"""
|
21
|
+
|
22
|
+
__slots__: ClassVar[tuple[str, ...]] = ()
|
23
|
+
_app: ClassVar[BaseApp]
|
24
|
+
_app_attr: ClassVar[str] = "_app"
|
hpcflow/sdk/core/cache.py
CHANGED
@@ -2,42 +2,53 @@
|
|
2
2
|
Dependency resolution cache.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from __future__ import annotations
|
5
6
|
from collections import defaultdict
|
6
7
|
from dataclasses import dataclass
|
7
|
-
from
|
8
|
+
from itertools import chain
|
9
|
+
from typing import TYPE_CHECKING
|
8
10
|
|
9
11
|
from hpcflow.sdk.log import TimeIt
|
10
12
|
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from collections.abc import Sequence
|
15
|
+
from typing_extensions import Self
|
16
|
+
from .element import Element, ElementIteration
|
17
|
+
from .workflow import Workflow
|
18
|
+
from ..persistence.base import StoreEAR, StoreElement, StoreElementIter
|
19
|
+
|
11
20
|
|
12
21
|
@dataclass
|
13
22
|
class DependencyCache:
|
14
|
-
"""
|
23
|
+
"""
|
24
|
+
Class to bulk-retrieve dependencies between elements, iterations, and runs.
|
25
|
+
"""
|
15
26
|
|
16
27
|
#: What EARs (by ID) a given EAR depends on.
|
17
|
-
run_dependencies:
|
28
|
+
run_dependencies: dict[int, set[int]]
|
18
29
|
#: What EARs (by ID) are depending on a given EAR.
|
19
|
-
run_dependents:
|
30
|
+
run_dependents: dict[int, set[int]]
|
20
31
|
#: What EARs (by ID) a given iteration depends on.
|
21
|
-
iter_run_dependencies:
|
32
|
+
iter_run_dependencies: dict[int, set[int]]
|
22
33
|
#: What iterations (by ID) a given iteration depends on.
|
23
|
-
iter_iter_dependencies:
|
34
|
+
iter_iter_dependencies: dict[int, set[int]]
|
24
35
|
#: What iterations (by ID) a given element depends on.
|
25
|
-
elem_iter_dependencies:
|
36
|
+
elem_iter_dependencies: dict[int, set[int]]
|
26
37
|
#: What elements (by ID) a given element depends on.
|
27
|
-
elem_elem_dependencies:
|
38
|
+
elem_elem_dependencies: dict[int, set[int]]
|
28
39
|
#: What elements (by ID) are depending on a given element.
|
29
|
-
elem_elem_dependents:
|
40
|
+
elem_elem_dependents: dict[int, set[int]]
|
30
41
|
#: Transitive closure of :py:attr:`elem_elem_dependents`.
|
31
|
-
elem_elem_dependents_rec:
|
42
|
+
elem_elem_dependents_rec: dict[int, set[int]]
|
32
43
|
|
33
44
|
#: The elements of the workflow that this cache was built from.
|
34
|
-
elements:
|
45
|
+
elements: list[Element]
|
35
46
|
#: The iterations of the workflow that this cache was built from.
|
36
|
-
iterations:
|
47
|
+
iterations: list[ElementIteration]
|
37
48
|
|
38
49
|
@classmethod
|
39
50
|
@TimeIt.decorator
|
40
|
-
def build(cls, workflow):
|
51
|
+
def build(cls, workflow: Workflow) -> Self:
|
41
52
|
"""
|
42
53
|
Build a cache instance.
|
43
54
|
|
@@ -50,54 +61,59 @@ class DependencyCache:
|
|
50
61
|
num_elems = workflow.num_elements
|
51
62
|
num_runs = workflow.num_EARs
|
52
63
|
|
53
|
-
all_store_runs = workflow._store.get_EARs(
|
54
|
-
all_store_iters
|
55
|
-
|
64
|
+
all_store_runs: Sequence[StoreEAR] = workflow._store.get_EARs(range(num_runs))
|
65
|
+
all_store_iters: Sequence[
|
66
|
+
StoreElementIter
|
67
|
+
] = workflow._store.get_element_iterations(range(num_iters))
|
68
|
+
all_store_elements: Sequence[StoreElement] = workflow._store.get_elements(
|
69
|
+
range(num_elems)
|
70
|
+
)
|
56
71
|
all_param_sources = workflow.get_all_parameter_sources()
|
57
|
-
all_data_idx =
|
72
|
+
all_data_idx = (
|
58
73
|
{
|
59
74
|
k: v if isinstance(v, list) else [v]
|
60
|
-
for k, v in
|
61
|
-
if
|
75
|
+
for k, v in store_ear.data_idx.items()
|
76
|
+
if not k.startswith("repeats.")
|
62
77
|
}
|
63
|
-
for
|
64
|
-
|
78
|
+
for store_ear in all_store_runs
|
79
|
+
)
|
65
80
|
|
66
81
|
# run dependencies and dependents
|
67
|
-
run_dependencies = {}
|
68
|
-
run_dependents = defaultdict(set)
|
69
|
-
for idx,
|
70
|
-
run_i_sources = set(
|
71
|
-
|
72
|
-
for
|
73
|
-
|
74
|
-
|
75
|
-
|
82
|
+
run_dependencies: dict[int, set[int]] = {}
|
83
|
+
run_dependents: defaultdict[int, set[int]] = defaultdict(set)
|
84
|
+
for idx, dict_i in enumerate(all_data_idx):
|
85
|
+
run_i_sources = set(
|
86
|
+
run_k
|
87
|
+
for idx in chain.from_iterable(dict_i.values())
|
88
|
+
if (run_k := all_param_sources[idx].get("EAR_ID")) is not None
|
89
|
+
and run_k != idx
|
90
|
+
)
|
76
91
|
run_dependencies[idx] = run_i_sources
|
77
92
|
for m in run_i_sources:
|
78
93
|
run_dependents[m].add(idx)
|
79
94
|
|
80
|
-
# add missing:
|
81
|
-
for
|
82
|
-
run_dependents[
|
83
|
-
|
84
|
-
run_dependents = dict(run_dependents)
|
95
|
+
# add missing and downgrade to dict:
|
96
|
+
for run_idx in range(num_runs):
|
97
|
+
run_dependents[run_idx]
|
98
|
+
run_dependents.default_factory = None
|
85
99
|
|
86
100
|
# iteration dependencies
|
87
101
|
all_iter_run_IDs = {
|
88
|
-
|
102
|
+
iter_.id_: tuple(chain.from_iterable((iter_.EAR_IDs or {}).values()))
|
103
|
+
for iter_ in all_store_iters
|
89
104
|
}
|
90
105
|
# for each iteration, which runs does it depend on?
|
91
106
|
iter_run_dependencies = {
|
92
|
-
k: set(j for
|
107
|
+
k: set(j for idx in v for j in run_dependencies[idx])
|
93
108
|
for k, v in all_iter_run_IDs.items()
|
94
109
|
}
|
95
110
|
|
96
111
|
# for each run, which iteration does it belong to?
|
97
|
-
all_run_iter_IDs = {
|
98
|
-
|
99
|
-
for
|
100
|
-
|
112
|
+
all_run_iter_IDs = {
|
113
|
+
run_ID: iter_ID
|
114
|
+
for iter_ID, run_IDs in all_iter_run_IDs.items()
|
115
|
+
for run_ID in run_IDs
|
116
|
+
}
|
101
117
|
|
102
118
|
# for each iteration, which iterations does it depend on?
|
103
119
|
iter_iter_dependencies = {
|
@@ -105,47 +121,49 @@ class DependencyCache:
|
|
105
121
|
for k, v in iter_run_dependencies.items()
|
106
122
|
}
|
107
123
|
|
108
|
-
all_elem_iter_IDs = {
|
124
|
+
all_elem_iter_IDs = {el.id_: el.iteration_IDs for el in all_store_elements}
|
109
125
|
|
110
126
|
elem_iter_dependencies = {
|
111
|
-
|
112
|
-
for
|
127
|
+
elem_ID: set(j for i in iter_IDs for j in iter_iter_dependencies[i])
|
128
|
+
for elem_ID, iter_IDs in all_elem_iter_IDs.items()
|
113
129
|
}
|
114
130
|
|
115
131
|
# for each iteration, which element does it belong to?
|
116
|
-
all_iter_elem_IDs = {
|
117
|
-
|
118
|
-
for
|
119
|
-
|
132
|
+
all_iter_elem_IDs = {
|
133
|
+
iter_ID: elem_ID
|
134
|
+
for elem_ID, iter_IDs in all_elem_iter_IDs.items()
|
135
|
+
for iter_ID in iter_IDs
|
136
|
+
}
|
120
137
|
|
121
138
|
# element dependencies
|
122
139
|
elem_elem_dependencies = {
|
123
|
-
k: set(all_iter_elem_IDs[i] for i in
|
124
|
-
for k,
|
140
|
+
k: set(all_iter_elem_IDs[i] for i in dep_set)
|
141
|
+
for k, dep_set in elem_iter_dependencies.items()
|
125
142
|
}
|
126
143
|
|
127
144
|
# for each element, which elements depend on it (directly)?
|
128
|
-
elem_elem_dependents = defaultdict(set)
|
129
|
-
for k,
|
130
|
-
for i in
|
145
|
+
elem_elem_dependents: defaultdict[int, set[int]] = defaultdict(set)
|
146
|
+
for k, dep_set in elem_elem_dependencies.items():
|
147
|
+
for i in dep_set:
|
131
148
|
elem_elem_dependents[i].add(k)
|
132
149
|
|
133
150
|
# for each element, which elements depend on it (recursively)?
|
134
|
-
elem_elem_dependents_rec = defaultdict(set)
|
135
|
-
for k in
|
151
|
+
elem_elem_dependents_rec: defaultdict[int, set[int]] = defaultdict(set)
|
152
|
+
for k in tuple(elem_elem_dependents):
|
153
|
+
# NB: code below modifies elem_elem_dependents during this loop;
|
154
|
+
# copy above is mandatory!
|
136
155
|
for i in elem_elem_dependents[k]:
|
137
156
|
elem_elem_dependents_rec[k].add(i)
|
138
157
|
elem_elem_dependents_rec[k].update(
|
139
|
-
|
158
|
+
m for m in elem_elem_dependents[i] if m != k
|
140
159
|
)
|
141
160
|
|
142
|
-
# add missing keys:
|
143
|
-
for
|
144
|
-
elem_elem_dependents[
|
145
|
-
elem_elem_dependents_rec[
|
146
|
-
|
147
|
-
|
148
|
-
elem_elem_dependents_rec = dict(elem_elem_dependents_rec)
|
161
|
+
# add missing keys and downgrade to dict:
|
162
|
+
for elem_idx in range(num_elems):
|
163
|
+
elem_elem_dependents[elem_idx]
|
164
|
+
elem_elem_dependents_rec[elem_idx]
|
165
|
+
elem_elem_dependents.default_factory = None
|
166
|
+
elem_elem_dependents_rec.default_factory = None
|
149
167
|
|
150
168
|
elements = workflow.get_all_elements()
|
151
169
|
iterations = workflow.get_all_element_iterations()
|