hpcflow-new2 0.2.0a189__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.0a189.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.0a189.dist-info/RECORD +0 -158
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a189.dist-info → hpcflow_new2-0.2.0a190.dist-info}/entry_points.txt +0 -0
@@ -2,16 +2,17 @@
|
|
2
2
|
Operating system information discovery helpers.
|
3
3
|
"""
|
4
4
|
|
5
|
-
import
|
5
|
+
from __future__ import annotations
|
6
|
+
from collections.abc import Mapping
|
6
7
|
import platform
|
7
8
|
import re
|
8
9
|
import subprocess
|
9
|
-
from typing import
|
10
|
+
from typing import Final
|
10
11
|
|
11
|
-
|
12
|
+
_DEFAULT_LINUX_RELEASE_FILE: Final = "/etc/os-release"
|
12
13
|
|
13
14
|
|
14
|
-
def get_OS_info() ->
|
15
|
+
def get_OS_info() -> Mapping[str, str]:
|
15
16
|
"""
|
16
17
|
Get basic operating system version info.
|
17
18
|
"""
|
@@ -23,7 +24,7 @@ def get_OS_info() -> Dict:
|
|
23
24
|
}
|
24
25
|
|
25
26
|
|
26
|
-
def get_OS_info_windows() ->
|
27
|
+
def get_OS_info_windows() -> Mapping[str, str]:
|
27
28
|
"""
|
28
29
|
Get operating system version info: Windows version.
|
29
30
|
"""
|
@@ -31,10 +32,10 @@ def get_OS_info_windows() -> Dict:
|
|
31
32
|
|
32
33
|
|
33
34
|
def get_OS_info_POSIX(
|
34
|
-
WSL_executable:
|
35
|
-
use_py:
|
36
|
-
linux_release_file:
|
37
|
-
) ->
|
35
|
+
WSL_executable: list[str] | None = None,
|
36
|
+
use_py: bool = True,
|
37
|
+
linux_release_file: str | None = None,
|
38
|
+
) -> Mapping[str, str]:
|
38
39
|
"""
|
39
40
|
Get operating system version info: POSIX version.
|
40
41
|
|
@@ -48,11 +49,11 @@ def get_OS_info_POSIX(
|
|
48
49
|
when getting OS info in WSL on Windows, since we need to call the WSL executable.
|
49
50
|
linux_release_file:
|
50
51
|
If on Linux, record the name and version fields from this file.
|
51
|
-
|
52
52
|
"""
|
53
53
|
|
54
|
-
def try_subprocess_call(
|
54
|
+
def try_subprocess_call(*args: str) -> str:
|
55
55
|
exc = None
|
56
|
+
command = [*WSL_exe, *args]
|
56
57
|
try:
|
57
58
|
proc = subprocess.run(
|
58
59
|
args=command,
|
@@ -63,23 +64,21 @@ def get_OS_info_POSIX(
|
|
63
64
|
except Exception as err:
|
64
65
|
exc = err
|
65
66
|
|
66
|
-
if proc.returncode
|
67
|
+
if proc.returncode or exc:
|
67
68
|
raise RuntimeError(
|
68
69
|
f"Failed to get POSIX OS info. Command was: {command!r}. Subprocess "
|
69
70
|
f"exception was: {exc!r}. Stderr was: {proc.stderr!r}."
|
70
71
|
)
|
71
|
-
|
72
|
-
return proc.stdout
|
72
|
+
return proc.stdout
|
73
73
|
|
74
|
-
|
75
|
-
out = {}
|
74
|
+
WSL_exe = WSL_executable or []
|
75
|
+
out: dict[str, str] = {}
|
76
76
|
if use_py:
|
77
77
|
out.update(**get_OS_info())
|
78
|
-
|
79
78
|
else:
|
80
|
-
OS_name = try_subprocess_call(
|
81
|
-
OS_release = try_subprocess_call(
|
82
|
-
OS_version = try_subprocess_call(
|
79
|
+
OS_name = try_subprocess_call("uname", "-s").strip()
|
80
|
+
OS_release = try_subprocess_call("uname", "-r").strip()
|
81
|
+
OS_version = try_subprocess_call("uname", "-v").strip()
|
83
82
|
|
84
83
|
out["OS_name"] = OS_name
|
85
84
|
out["OS_release"] = OS_release
|
@@ -87,28 +86,30 @@ def get_OS_info_POSIX(
|
|
87
86
|
|
88
87
|
if out["OS_name"] == "Linux":
|
89
88
|
# get linux distribution name and version:
|
90
|
-
linux_release_file = linux_release_file or
|
91
|
-
release_out = try_subprocess_call(
|
89
|
+
linux_release_file = linux_release_file or _DEFAULT_LINUX_RELEASE_FILE
|
90
|
+
release_out = try_subprocess_call("cat", linux_release_file)
|
92
91
|
|
93
|
-
name_match =
|
94
|
-
if name_match:
|
95
|
-
lin_name = name_match.group(1)
|
96
|
-
else:
|
92
|
+
name_match = _NAME_RE.search(release_out)
|
93
|
+
if not name_match:
|
97
94
|
raise RuntimeError(
|
98
95
|
f"Failed to get Linux distribution name from file `{linux_release_file}`."
|
99
96
|
)
|
97
|
+
lin_name: str = name_match[1]
|
100
98
|
|
101
|
-
version_match =
|
102
|
-
if version_match:
|
103
|
-
lin_version = version_match.group(1)
|
104
|
-
else:
|
99
|
+
version_match = _VERSION_RE.search(release_out)
|
100
|
+
if not version_match:
|
105
101
|
raise RuntimeError(
|
106
102
|
f"Failed to get Linux distribution version from file "
|
107
103
|
f"`{linux_release_file}`."
|
108
104
|
)
|
105
|
+
lin_version: str = version_match[1]
|
109
106
|
|
110
107
|
out["linux_release_file"] = linux_release_file
|
111
108
|
out["linux_distribution_name"] = lin_name
|
112
109
|
out["linux_distribution_version"] = lin_version
|
113
110
|
|
114
111
|
return out
|
112
|
+
|
113
|
+
|
114
|
+
_NAME_RE: Final = re.compile(r"^NAME=\"(.*)\"", flags=re.MULTILINE)
|
115
|
+
_VERSION_RE: Final = re.compile(r"^VERSION=\"(.*)\"", flags=re.MULTILINE)
|
@@ -2,32 +2,40 @@
|
|
2
2
|
Shell models based on Microsoft PowerShell.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from __future__ import annotations
|
5
6
|
import subprocess
|
6
7
|
from textwrap import dedent, indent
|
7
|
-
from typing import
|
8
|
+
from typing import TYPE_CHECKING
|
9
|
+
from typing_extensions import override
|
10
|
+
from hpcflow.sdk.typing import hydrate
|
8
11
|
from hpcflow.sdk.core import ABORT_EXIT_CODE
|
9
|
-
from hpcflow.sdk.submission.shells import Shell
|
12
|
+
from hpcflow.sdk.submission.shells.base import Shell
|
10
13
|
from hpcflow.sdk.submission.shells.os_version import get_OS_info_windows
|
11
14
|
|
15
|
+
if TYPE_CHECKING:
|
16
|
+
from typing import ClassVar
|
17
|
+
from .base import VersionInfo
|
12
18
|
|
19
|
+
|
20
|
+
@hydrate
|
13
21
|
class WindowsPowerShell(Shell):
|
14
22
|
"""Class to represent using PowerShell on Windows to generate and submit a jobscript."""
|
15
23
|
|
16
24
|
# TODO: add snippets that can be used in demo task schemas?
|
17
25
|
|
18
26
|
#: Default for executable name.
|
19
|
-
DEFAULT_EXE = "powershell.exe"
|
27
|
+
DEFAULT_EXE: ClassVar[str] = "powershell.exe"
|
20
28
|
|
21
29
|
#: File extension for jobscripts.
|
22
|
-
JS_EXT = ".ps1"
|
30
|
+
JS_EXT: ClassVar[str] = ".ps1"
|
23
31
|
#: Basic indent.
|
24
|
-
JS_INDENT = " "
|
32
|
+
JS_INDENT: ClassVar[str] = " "
|
25
33
|
#: Indent for environment setup.
|
26
|
-
JS_ENV_SETUP_INDENT = 2 * JS_INDENT
|
34
|
+
JS_ENV_SETUP_INDENT: ClassVar[str] = 2 * JS_INDENT
|
27
35
|
#: Template for the jobscript shebang line.
|
28
|
-
JS_SHEBANG = ""
|
36
|
+
JS_SHEBANG: ClassVar[str] = ""
|
29
37
|
#: Template for the common part of the jobscript header.
|
30
|
-
JS_HEADER = dedent(
|
38
|
+
JS_HEADER: ClassVar[str] = dedent(
|
31
39
|
"""\
|
32
40
|
function {workflow_app_alias} {{
|
33
41
|
& {{
|
@@ -71,7 +79,7 @@ class WindowsPowerShell(Shell):
|
|
71
79
|
"""
|
72
80
|
)
|
73
81
|
#: Template for the jobscript header when directly executed.
|
74
|
-
JS_DIRECT_HEADER = dedent(
|
82
|
+
JS_DIRECT_HEADER: ClassVar[str] = dedent(
|
75
83
|
"""\
|
76
84
|
{shebang}
|
77
85
|
|
@@ -80,7 +88,7 @@ class WindowsPowerShell(Shell):
|
|
80
88
|
"""
|
81
89
|
)
|
82
90
|
#: Template for the jobscript body.
|
83
|
-
JS_MAIN = dedent(
|
91
|
+
JS_MAIN: ClassVar[str] = dedent(
|
84
92
|
"""\
|
85
93
|
$elem_EAR_IDs = get_nth_line $EAR_ID_FILE $JS_elem_idx
|
86
94
|
$elem_run_dirs = get_nth_line $ELEM_RUN_DIR_FILE $JS_elem_idx
|
@@ -101,7 +109,6 @@ class WindowsPowerShell(Shell):
|
|
101
109
|
$exc_sk = $LASTEXITCODE
|
102
110
|
|
103
111
|
if ($exc_sk -eq 0) {{
|
104
|
-
|
105
112
|
if ($skip -eq "1") {{
|
106
113
|
continue
|
107
114
|
}}
|
@@ -120,7 +127,7 @@ class WindowsPowerShell(Shell):
|
|
120
127
|
$exit_code = If ($exc_wc -ne 0) {{$exc_wc}} Else {{$exc_se}}
|
121
128
|
}}
|
122
129
|
}}
|
123
|
-
else {{
|
130
|
+
else {{
|
124
131
|
$exit_code = $exc_sk
|
125
132
|
}}
|
126
133
|
$global:LASTEXITCODE = $null
|
@@ -130,7 +137,7 @@ class WindowsPowerShell(Shell):
|
|
130
137
|
"""
|
131
138
|
)
|
132
139
|
#: Template for the element processing loop in a jobscript.
|
133
|
-
JS_ELEMENT_LOOP = dedent(
|
140
|
+
JS_ELEMENT_LOOP: ClassVar[str] = dedent(
|
134
141
|
"""\
|
135
142
|
for ($JS_elem_idx = 0; $JS_elem_idx -lt {num_elements}; $JS_elem_idx += 1) {{
|
136
143
|
{main}
|
@@ -139,14 +146,12 @@ class WindowsPowerShell(Shell):
|
|
139
146
|
"""
|
140
147
|
)
|
141
148
|
|
142
|
-
def
|
143
|
-
super().__init__(*args, **kwargs)
|
144
|
-
|
145
|
-
def get_direct_submit_command(self, js_path) -> List[str]:
|
149
|
+
def get_direct_submit_command(self, js_path: str) -> list[str]:
|
146
150
|
"""Get the command for submitting a non-scheduled jobscript."""
|
147
|
-
return self.executable
|
151
|
+
return [*self.executable, "-File", js_path]
|
148
152
|
|
149
|
-
|
153
|
+
@override
|
154
|
+
def get_version_info(self, exclude_os: bool = False) -> VersionInfo:
|
150
155
|
"""Get powershell version information.
|
151
156
|
|
152
157
|
Parameters
|
@@ -166,30 +171,29 @@ class WindowsPowerShell(Shell):
|
|
166
171
|
else:
|
167
172
|
raise RuntimeError("Failed to parse PowerShell version information.")
|
168
173
|
|
169
|
-
|
174
|
+
osinfo = {} if exclude_os else get_OS_info_windows()
|
175
|
+
return {
|
170
176
|
"shell_name": "powershell",
|
171
177
|
"shell_executable": self.executable,
|
172
178
|
"shell_version": PS_version,
|
179
|
+
**osinfo,
|
173
180
|
}
|
174
181
|
|
175
|
-
if not exclude_os:
|
176
|
-
out.update(**get_OS_info_windows())
|
177
|
-
|
178
|
-
return out
|
179
|
-
|
180
182
|
@staticmethod
|
181
|
-
def process_app_invoc_executable(app_invoc_exe):
|
183
|
+
def process_app_invoc_executable(app_invoc_exe: str) -> str:
|
182
184
|
if " " in app_invoc_exe:
|
183
185
|
# use call operator and single-quote the executable path:
|
184
186
|
app_invoc_exe = f"& '{app_invoc_exe}'"
|
185
187
|
return app_invoc_exe
|
186
188
|
|
187
|
-
|
189
|
+
@override
|
190
|
+
def format_stream_assignment(self, shell_var_name: str, command: str) -> str:
|
188
191
|
"""
|
189
192
|
Produce code to assign the output of the command to a shell variable.
|
190
193
|
"""
|
191
194
|
return f"${shell_var_name} = {command}"
|
192
195
|
|
196
|
+
@override
|
193
197
|
def format_save_parameter(
|
194
198
|
self,
|
195
199
|
workflow_app_alias: str,
|
@@ -198,7 +202,7 @@ class WindowsPowerShell(Shell):
|
|
198
202
|
EAR_ID: int,
|
199
203
|
cmd_idx: int,
|
200
204
|
stderr: bool,
|
201
|
-
):
|
205
|
+
) -> str:
|
202
206
|
"""
|
203
207
|
Produce code to save a parameter's value into the workflow persistent store.
|
204
208
|
"""
|
@@ -213,7 +217,10 @@ class WindowsPowerShell(Shell):
|
|
213
217
|
f"\n"
|
214
218
|
)
|
215
219
|
|
216
|
-
|
220
|
+
@override
|
221
|
+
def format_loop_check(
|
222
|
+
self, workflow_app_alias: str, loop_name: str, run_ID: int
|
223
|
+
) -> str:
|
217
224
|
"""
|
218
225
|
Produce code to check the looping status of part of a workflow.
|
219
226
|
"""
|
@@ -225,6 +232,7 @@ class WindowsPowerShell(Shell):
|
|
225
232
|
f"\n"
|
226
233
|
)
|
227
234
|
|
235
|
+
@override
|
228
236
|
def wrap_in_subshell(self, commands: str, abortable: bool) -> str:
|
229
237
|
"""Format commands to run within a child scope.
|
230
238
|
|