hpcflow-new2 0.2.0a190__py3-none-any.whl → 0.2.0a200__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 +1 -0
- hpcflow/_version.py +1 -1
- hpcflow/data/scripts/bad_script.py +2 -0
- hpcflow/data/scripts/do_nothing.py +2 -0
- hpcflow/data/scripts/env_specifier_test/input_file_generator_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/main_script_test_pass_env_spec.py +8 -0
- hpcflow/data/scripts/env_specifier_test/output_file_parser_pass_env_spec.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/input_file_generator_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v1/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/env_specifier_test/v1/output_file_parser_basic.py +4 -0
- hpcflow/data/scripts/env_specifier_test/v2/main_script_test_direct_in_direct_out.py +7 -0
- hpcflow/data/scripts/input_file_generator_basic.py +3 -0
- hpcflow/data/scripts/input_file_generator_basic_FAIL.py +3 -0
- hpcflow/data/scripts/input_file_generator_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/main_script_test_direct_in.py +3 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_2_fail_allowed_group.py +7 -0
- hpcflow/data/scripts/main_script_test_direct_in_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_direct_in_group_one_fail_direct_out_3.py +6 -0
- hpcflow/data/scripts/main_script_test_hdf5_in_obj_2.py +12 -0
- hpcflow/data/scripts/main_script_test_json_out_FAIL.py +3 -0
- hpcflow/data/scripts/main_script_test_shell_env_vars.py +12 -0
- hpcflow/data/scripts/main_script_test_std_out_std_err.py +6 -0
- hpcflow/data/scripts/output_file_parser_basic.py +3 -0
- hpcflow/data/scripts/output_file_parser_basic_FAIL.py +7 -0
- hpcflow/data/scripts/output_file_parser_test_stdout_stderr.py +8 -0
- hpcflow/data/scripts/script_exit_test.py +5 -0
- hpcflow/data/template_components/environments.yaml +1 -1
- hpcflow/sdk/__init__.py +5 -0
- hpcflow/sdk/app.py +166 -92
- hpcflow/sdk/cli.py +263 -84
- hpcflow/sdk/cli_common.py +99 -5
- hpcflow/sdk/config/callbacks.py +38 -1
- hpcflow/sdk/config/config.py +102 -13
- hpcflow/sdk/config/errors.py +19 -5
- hpcflow/sdk/config/types.py +3 -0
- hpcflow/sdk/core/__init__.py +25 -1
- hpcflow/sdk/core/actions.py +914 -262
- hpcflow/sdk/core/cache.py +76 -34
- hpcflow/sdk/core/command_files.py +14 -128
- hpcflow/sdk/core/commands.py +35 -6
- hpcflow/sdk/core/element.py +122 -50
- hpcflow/sdk/core/errors.py +58 -2
- hpcflow/sdk/core/execute.py +207 -0
- hpcflow/sdk/core/loop.py +408 -50
- hpcflow/sdk/core/loop_cache.py +4 -4
- hpcflow/sdk/core/parameters.py +382 -37
- hpcflow/sdk/core/run_dir_files.py +13 -40
- hpcflow/sdk/core/skip_reason.py +7 -0
- hpcflow/sdk/core/task.py +119 -30
- hpcflow/sdk/core/task_schema.py +68 -0
- hpcflow/sdk/core/test_utils.py +66 -27
- hpcflow/sdk/core/types.py +54 -1
- hpcflow/sdk/core/utils.py +136 -19
- hpcflow/sdk/core/workflow.py +1587 -356
- hpcflow/sdk/data/workflow_spec_schema.yaml +2 -0
- hpcflow/sdk/demo/cli.py +7 -0
- hpcflow/sdk/helper/cli.py +1 -0
- hpcflow/sdk/log.py +42 -15
- hpcflow/sdk/persistence/base.py +405 -53
- hpcflow/sdk/persistence/json.py +177 -52
- hpcflow/sdk/persistence/pending.py +237 -69
- hpcflow/sdk/persistence/store_resource.py +3 -2
- hpcflow/sdk/persistence/types.py +15 -4
- hpcflow/sdk/persistence/zarr.py +928 -81
- hpcflow/sdk/submission/jobscript.py +1408 -489
- hpcflow/sdk/submission/schedulers/__init__.py +40 -5
- hpcflow/sdk/submission/schedulers/direct.py +33 -19
- hpcflow/sdk/submission/schedulers/sge.py +51 -16
- hpcflow/sdk/submission/schedulers/slurm.py +44 -16
- hpcflow/sdk/submission/schedulers/utils.py +7 -2
- hpcflow/sdk/submission/shells/base.py +68 -20
- hpcflow/sdk/submission/shells/bash.py +222 -129
- hpcflow/sdk/submission/shells/powershell.py +200 -150
- hpcflow/sdk/submission/submission.py +852 -119
- hpcflow/sdk/submission/types.py +18 -21
- hpcflow/sdk/typing.py +24 -5
- hpcflow/sdk/utils/arrays.py +71 -0
- hpcflow/sdk/utils/deferred_file.py +55 -0
- hpcflow/sdk/utils/hashing.py +16 -0
- hpcflow/sdk/utils/patches.py +12 -0
- hpcflow/sdk/utils/strings.py +33 -0
- hpcflow/tests/api/test_api.py +32 -0
- hpcflow/tests/conftest.py +19 -0
- hpcflow/tests/data/benchmark_script_runner.yaml +26 -0
- hpcflow/tests/data/multi_path_sequences.yaml +29 -0
- hpcflow/tests/data/workflow_test_run_abort.yaml +34 -35
- hpcflow/tests/schedulers/sge/test_sge_submission.py +36 -0
- hpcflow/tests/scripts/test_input_file_generators.py +282 -0
- hpcflow/tests/scripts/test_main_scripts.py +821 -70
- hpcflow/tests/scripts/test_non_snippet_script.py +46 -0
- hpcflow/tests/scripts/test_ouput_file_parsers.py +353 -0
- hpcflow/tests/shells/wsl/test_wsl_submission.py +6 -0
- hpcflow/tests/unit/test_action.py +176 -0
- hpcflow/tests/unit/test_app.py +20 -0
- hpcflow/tests/unit/test_cache.py +46 -0
- hpcflow/tests/unit/test_cli.py +133 -0
- hpcflow/tests/unit/test_config.py +122 -1
- hpcflow/tests/unit/test_element_iteration.py +47 -0
- hpcflow/tests/unit/test_jobscript_unit.py +757 -0
- hpcflow/tests/unit/test_loop.py +1332 -27
- hpcflow/tests/unit/test_meta_task.py +325 -0
- hpcflow/tests/unit/test_multi_path_sequences.py +229 -0
- hpcflow/tests/unit/test_parameter.py +13 -0
- hpcflow/tests/unit/test_persistence.py +190 -8
- hpcflow/tests/unit/test_run.py +109 -3
- hpcflow/tests/unit/test_run_directories.py +29 -0
- hpcflow/tests/unit/test_shell.py +20 -0
- hpcflow/tests/unit/test_submission.py +5 -76
- hpcflow/tests/unit/test_workflow_template.py +31 -0
- hpcflow/tests/unit/utils/test_arrays.py +40 -0
- hpcflow/tests/unit/utils/test_deferred_file_writer.py +34 -0
- hpcflow/tests/unit/utils/test_hashing.py +65 -0
- hpcflow/tests/unit/utils/test_patches.py +5 -0
- hpcflow/tests/unit/utils/test_redirect_std.py +50 -0
- hpcflow/tests/workflows/__init__.py +0 -0
- hpcflow/tests/workflows/test_directory_structure.py +31 -0
- hpcflow/tests/workflows/test_jobscript.py +332 -0
- hpcflow/tests/workflows/test_run_status.py +198 -0
- hpcflow/tests/workflows/test_skip_downstream.py +696 -0
- hpcflow/tests/workflows/test_submission.py +140 -0
- hpcflow/tests/workflows/test_workflows.py +142 -2
- hpcflow/tests/workflows/test_zip.py +18 -0
- hpcflow/viz_demo.ipynb +6587 -3
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/METADATA +7 -4
- hpcflow_new2-0.2.0a200.dist-info/RECORD +222 -0
- hpcflow_new2-0.2.0a190.dist-info/RECORD +0 -165
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a200.dist-info}/entry_points.txt +0 -0
hpcflow/sdk/app.py
CHANGED
@@ -15,7 +15,7 @@ from contextlib import contextmanager
|
|
15
15
|
from pathlib import Path
|
16
16
|
import sys
|
17
17
|
from tempfile import TemporaryDirectory
|
18
|
-
from typing import Any, TypeVar, Generic, cast, TYPE_CHECKING
|
18
|
+
from typing import Any, TypeVar, Generic, cast, TYPE_CHECKING, Literal
|
19
19
|
import warnings
|
20
20
|
import zipfile
|
21
21
|
from platformdirs import user_cache_path, user_data_dir
|
@@ -39,6 +39,7 @@ from hpcflow.sdk.core.utils import (
|
|
39
39
|
read_JSON_file,
|
40
40
|
write_YAML_file,
|
41
41
|
write_JSON_file,
|
42
|
+
redirect_std_to_file as redirect_std_to_file_hpcflow,
|
42
43
|
parse_timestamp,
|
43
44
|
get_file_context,
|
44
45
|
open_text_resource,
|
@@ -46,6 +47,7 @@ from hpcflow.sdk.core.utils import (
|
|
46
47
|
from hpcflow.sdk import sdk_classes, sdk_funcs, get_SDK_logger
|
47
48
|
from hpcflow.sdk.config import Config, ConfigFile
|
48
49
|
from hpcflow.sdk.core import ALL_TEMPLATE_FORMATS
|
50
|
+
from .core.workflow import Workflow as _Workflow
|
49
51
|
from hpcflow.sdk.log import AppLog, TimeIt
|
50
52
|
from hpcflow.sdk.persistence.defaults import DEFAULT_STORE_FORMAT
|
51
53
|
from hpcflow.sdk.persistence.base import TEMPLATE_COMP_TYPES
|
@@ -71,6 +73,7 @@ if TYPE_CHECKING:
|
|
71
73
|
KnownSubmissionItem,
|
72
74
|
PathLike,
|
73
75
|
TemplateComponents,
|
76
|
+
MakeWorkflowCommonArgs,
|
74
77
|
)
|
75
78
|
from .config.config import ConfigOptions
|
76
79
|
from .core.actions import (
|
@@ -132,6 +135,7 @@ if TYPE_CHECKING:
|
|
132
135
|
ResourceSpec,
|
133
136
|
SchemaOutput,
|
134
137
|
ValueSequence,
|
138
|
+
MultiPathSequence,
|
135
139
|
SchemaInput,
|
136
140
|
)
|
137
141
|
from .core.rule import Rule
|
@@ -146,12 +150,9 @@ if TYPE_CHECKING:
|
|
146
150
|
ElementSet,
|
147
151
|
)
|
148
152
|
from .core.task_schema import TaskSchema, TaskObjective
|
149
|
-
from .core.workflow import
|
150
|
-
Workflow as _Workflow,
|
151
|
-
WorkflowTemplate as _WorkflowTemplate,
|
152
|
-
)
|
153
|
+
from .core.workflow import WorkflowTemplate as _WorkflowTemplate
|
153
154
|
from .submission.jobscript import Jobscript
|
154
|
-
from .submission.submission import Submission
|
155
|
+
from .submission.submission import Submission as _Submission # TODO: why?
|
155
156
|
from .submission.schedulers import Scheduler, QueuedScheduler
|
156
157
|
from .submission.schedulers.direct import DirectPosix, DirectWindows
|
157
158
|
from .submission.schedulers.sge import SGEPosix
|
@@ -176,7 +177,8 @@ if TYPE_CHECKING:
|
|
176
177
|
store_kwargs: dict[str, Any] | None = None,
|
177
178
|
variables: dict[str, str] | None = None,
|
178
179
|
status: bool = True,
|
179
|
-
|
180
|
+
add_submission: bool = False,
|
181
|
+
) -> _Workflow | _Submission | None:
|
180
182
|
...
|
181
183
|
|
182
184
|
class _MakeDemoWorkflow(Protocol):
|
@@ -195,7 +197,8 @@ if TYPE_CHECKING:
|
|
195
197
|
store_kwargs: dict[str, Any] | None = None,
|
196
198
|
variables: dict[str, str] | None = None,
|
197
199
|
status: bool = True,
|
198
|
-
|
200
|
+
add_submission: bool = False,
|
201
|
+
) -> _Workflow | _Submission | None:
|
199
202
|
...
|
200
203
|
|
201
204
|
class _MakeAndSubmitWorkflow(Protocol):
|
@@ -296,6 +299,7 @@ if TYPE_CHECKING:
|
|
296
299
|
self,
|
297
300
|
workflow_ref: int | str | Path,
|
298
301
|
ref_is_path: str | None = None,
|
302
|
+
status: bool = False,
|
299
303
|
) -> None:
|
300
304
|
...
|
301
305
|
|
@@ -766,6 +770,15 @@ class BaseApp(metaclass=Singleton):
|
|
766
770
|
"""
|
767
771
|
return self._get_app_core_class("ValueSequence")
|
768
772
|
|
773
|
+
@property
|
774
|
+
def MultiPathSequence(self) -> type[MultiPathSequence]:
|
775
|
+
"""
|
776
|
+
The :class:`MultiPathSequence` class.
|
777
|
+
|
778
|
+
:meta private:
|
779
|
+
"""
|
780
|
+
return self._get_app_core_class("MultiPathSequence")
|
781
|
+
|
769
782
|
@property
|
770
783
|
def SchemaInput(self) -> type[SchemaInput]:
|
771
784
|
"""
|
@@ -1172,7 +1185,7 @@ class BaseApp(metaclass=Singleton):
|
|
1172
1185
|
return self._get_app_core_class("Jobscript")
|
1173
1186
|
|
1174
1187
|
@property
|
1175
|
-
def Submission(self) -> type[
|
1188
|
+
def Submission(self) -> type[_Submission]:
|
1176
1189
|
"""
|
1177
1190
|
The :class:`Submission` class.
|
1178
1191
|
|
@@ -1265,11 +1278,15 @@ class BaseApp(metaclass=Singleton):
|
|
1265
1278
|
String variables to substitute in `template_file_or_str`.
|
1266
1279
|
status: bool
|
1267
1280
|
If True, display a live status to track workflow creation progress.
|
1281
|
+
add_submission
|
1282
|
+
If True, add a submission to the workflow (but do not submit).
|
1268
1283
|
|
1269
1284
|
Returns
|
1270
1285
|
-------
|
1271
1286
|
Workflow
|
1272
|
-
The created workflow
|
1287
|
+
The created workflow, if `add_submission` is `False`.
|
1288
|
+
Submission
|
1289
|
+
The created submission object, if `add_submission` is `True`.
|
1273
1290
|
"""
|
1274
1291
|
return self.__get_app_func("make_workflow")
|
1275
1292
|
|
@@ -1310,11 +1327,15 @@ class BaseApp(metaclass=Singleton):
|
|
1310
1327
|
String variables to substitute in the demo workflow template file.
|
1311
1328
|
status: bool
|
1312
1329
|
If True, display a live status to track workflow creation progress.
|
1330
|
+
add_submission
|
1331
|
+
If True, add a submission to the workflow (but do not submit).
|
1313
1332
|
|
1314
1333
|
Returns
|
1315
1334
|
-------
|
1316
1335
|
Workflow
|
1317
|
-
The created workflow
|
1336
|
+
The created workflow, if `add_submission` is `False`.
|
1337
|
+
Submission
|
1338
|
+
The created submission object, if `add_submission` is `True`.
|
1318
1339
|
"""
|
1319
1340
|
return self.__get_app_func("make_demo_workflow")
|
1320
1341
|
|
@@ -1580,6 +1601,8 @@ class BaseApp(metaclass=Singleton):
|
|
1580
1601
|
Which workflow to cancel, by ID or path.
|
1581
1602
|
ref_is_path: str
|
1582
1603
|
One of "``id``", "``path``" or "``assume-id``" (the default)
|
1604
|
+
status: bool
|
1605
|
+
Whether to show a live status during cancel.
|
1583
1606
|
"""
|
1584
1607
|
return self.__get_app_func("cancel")
|
1585
1608
|
|
@@ -2133,10 +2156,12 @@ class BaseApp(metaclass=Singleton):
|
|
2133
2156
|
**overrides,
|
2134
2157
|
)
|
2135
2158
|
self.log.update_console_level(self.config.get("log_console_level"))
|
2136
|
-
self.
|
2137
|
-
|
2138
|
-
|
2139
|
-
|
2159
|
+
log_file_path = self.config.get("log_file_path")
|
2160
|
+
if log_file_path:
|
2161
|
+
self.log.add_file_logger(
|
2162
|
+
path=log_file_path,
|
2163
|
+
level=self.config.get("log_file_level"),
|
2164
|
+
)
|
2140
2165
|
self.logger.info(f"Configuration loaded from: {self.config.config_file_path}")
|
2141
2166
|
self._ensure_user_data_hostname_dir()
|
2142
2167
|
|
@@ -2212,7 +2237,7 @@ class BaseApp(metaclass=Singleton):
|
|
2212
2237
|
"""
|
2213
2238
|
if warn and not self.is_config_loaded:
|
2214
2239
|
warnings.warn("Configuration is not loaded; loading.")
|
2215
|
-
self.log.
|
2240
|
+
self.log.remove_file_handler()
|
2216
2241
|
self._config_files = {}
|
2217
2242
|
self._load_config(config_dir, config_key, **overrides)
|
2218
2243
|
|
@@ -2345,10 +2370,23 @@ class BaseApp(metaclass=Singleton):
|
|
2345
2370
|
else:
|
2346
2371
|
print(contents)
|
2347
2372
|
|
2348
|
-
def load_demo_workflow(
|
2349
|
-
|
2373
|
+
def load_demo_workflow(
|
2374
|
+
self, name: str, variables: dict[str, str] | Literal[False] | None = None
|
2375
|
+
) -> _WorkflowTemplate:
|
2376
|
+
"""Load a WorkflowTemplate object from a builtin demo template file.
|
2377
|
+
|
2378
|
+
Parameters
|
2379
|
+
----------
|
2380
|
+
name:
|
2381
|
+
Name of the demo workflow to load.
|
2382
|
+
variables:
|
2383
|
+
String variables to substitute in the demo workflow. Substitutions will be
|
2384
|
+
attempted if the file looks to contain variable references (like
|
2385
|
+
"<<var:name>>"). If set to `False`, no substitutions will occur, which may
|
2386
|
+
result in an invalid workflow template!
|
2387
|
+
"""
|
2350
2388
|
with self.get_demo_workflow_template_file(name) as path:
|
2351
|
-
return self.WorkflowTemplate.from_file(path)
|
2389
|
+
return self.WorkflowTemplate.from_file(path, variables=variables)
|
2352
2390
|
|
2353
2391
|
def template_components_from_json_like(
|
2354
2392
|
self, json_like: dict[str, dict]
|
@@ -2651,7 +2689,8 @@ class BaseApp(metaclass=Singleton):
|
|
2651
2689
|
store_kwargs: dict[str, Any] | None = None,
|
2652
2690
|
variables: dict[str, str] | None = None,
|
2653
2691
|
status: bool = True,
|
2654
|
-
|
2692
|
+
add_submission: bool = False,
|
2693
|
+
) -> _Workflow | _Submission | None:
|
2655
2694
|
"""
|
2656
2695
|
Generate a new {app_name} workflow from a file or string containing a workflow
|
2657
2696
|
template parametrisation.
|
@@ -2690,11 +2729,15 @@ class BaseApp(metaclass=Singleton):
|
|
2690
2729
|
String variables to substitute in `template_file_or_str`.
|
2691
2730
|
status
|
2692
2731
|
If True, display a live status to track workflow creation progress.
|
2732
|
+
add_submission
|
2733
|
+
If True, add a submission to the workflow (but do not submit).
|
2693
2734
|
|
2694
2735
|
Returns
|
2695
2736
|
-------
|
2696
2737
|
Workflow
|
2697
|
-
The created workflow
|
2738
|
+
The created workflow, if `add_submission` is `False`.
|
2739
|
+
Submission
|
2740
|
+
The created submission object, if `add_submission` is `True`.
|
2698
2741
|
"""
|
2699
2742
|
self.API_logger.info("make_workflow called")
|
2700
2743
|
|
@@ -2703,44 +2746,31 @@ class BaseApp(metaclass=Singleton):
|
|
2703
2746
|
)
|
2704
2747
|
|
2705
2748
|
with status_context as status_:
|
2749
|
+
|
2750
|
+
common: MakeWorkflowCommonArgs = {
|
2751
|
+
"path": str(path) if path else None,
|
2752
|
+
"name": name,
|
2753
|
+
"overwrite": overwrite,
|
2754
|
+
"store": store,
|
2755
|
+
"ts_fmt": ts_fmt,
|
2756
|
+
"ts_name_fmt": ts_name_fmt,
|
2757
|
+
"store_kwargs": store_kwargs,
|
2758
|
+
"variables": variables,
|
2759
|
+
"status": status_,
|
2760
|
+
}
|
2706
2761
|
if not is_string:
|
2707
|
-
|
2762
|
+
wk = self.Workflow.from_file(
|
2708
2763
|
template_path=template_file_or_str,
|
2709
2764
|
template_format=template_format,
|
2710
|
-
|
2711
|
-
name=name,
|
2712
|
-
overwrite=overwrite,
|
2713
|
-
store=store,
|
2714
|
-
ts_fmt=ts_fmt,
|
2715
|
-
ts_name_fmt=ts_name_fmt,
|
2716
|
-
store_kwargs=store_kwargs,
|
2717
|
-
variables=variables,
|
2718
|
-
status=status_,
|
2765
|
+
**common,
|
2719
2766
|
)
|
2720
2767
|
elif template_format == "json":
|
2721
|
-
|
2722
|
-
JSON_str=str(template_file_or_str),
|
2723
|
-
path=str(path) if path else None,
|
2724
|
-
name=name,
|
2725
|
-
overwrite=overwrite,
|
2726
|
-
store=store,
|
2727
|
-
ts_fmt=ts_fmt,
|
2728
|
-
ts_name_fmt=ts_name_fmt,
|
2729
|
-
store_kwargs=store_kwargs,
|
2730
|
-
variables=variables,
|
2731
|
-
status=status_,
|
2768
|
+
wk = self.Workflow.from_JSON_string(
|
2769
|
+
JSON_str=str(template_file_or_str), **common
|
2732
2770
|
)
|
2733
2771
|
elif template_format == "yaml":
|
2734
|
-
|
2735
|
-
YAML_str=str(template_file_or_str),
|
2736
|
-
path=str(path) if path else None,
|
2737
|
-
name=name,
|
2738
|
-
overwrite=overwrite,
|
2739
|
-
store=store,
|
2740
|
-
ts_fmt=ts_fmt,
|
2741
|
-
ts_name_fmt=ts_name_fmt,
|
2742
|
-
store_kwargs=store_kwargs,
|
2743
|
-
variables=variables,
|
2772
|
+
wk = self.Workflow.from_YAML_string(
|
2773
|
+
YAML_str=str(template_file_or_str), **common
|
2744
2774
|
)
|
2745
2775
|
elif not template_format:
|
2746
2776
|
raise ValueError(
|
@@ -2752,6 +2782,11 @@ class BaseApp(metaclass=Singleton):
|
|
2752
2782
|
f"Template format {template_format!r} not understood. Available template "
|
2753
2783
|
f"formats are {ALL_TEMPLATE_FORMATS!r}."
|
2754
2784
|
)
|
2785
|
+
if add_submission:
|
2786
|
+
with wk._store.cached_load(), wk.batch_update():
|
2787
|
+
return wk._add_submission(status=status_)
|
2788
|
+
|
2789
|
+
return wk
|
2755
2790
|
|
2756
2791
|
def _make_and_submit_workflow(
|
2757
2792
|
self,
|
@@ -2766,7 +2801,7 @@ class BaseApp(metaclass=Singleton):
|
|
2766
2801
|
ts_name_fmt: str | None = None,
|
2767
2802
|
store_kwargs: dict[str, Any] | None = None,
|
2768
2803
|
variables: dict[str, str] | None = None,
|
2769
|
-
JS_parallelism: bool | None = None,
|
2804
|
+
JS_parallelism: bool | Literal["direct", "scheduled"] | None = None,
|
2770
2805
|
wait: bool = False,
|
2771
2806
|
add_to_known: bool = True,
|
2772
2807
|
return_idx: bool = False,
|
@@ -2812,9 +2847,12 @@ class BaseApp(metaclass=Singleton):
|
|
2812
2847
|
variables
|
2813
2848
|
String variables to substitute in `template_file_or_str`.
|
2814
2849
|
JS_parallelism
|
2815
|
-
If True, allow multiple jobscripts to execute simultaneously.
|
2816
|
-
|
2817
|
-
|
2850
|
+
If True, allow multiple jobscripts to execute simultaneously. If
|
2851
|
+
'scheduled'/'direct', only allow simultaneous execution of scheduled/direct
|
2852
|
+
jobscripts. Raises if set to True, 'scheduled', or 'direct', but the store
|
2853
|
+
type does not support the `jobscript_parallelism` feature. If not set,
|
2854
|
+
jobscript parallelism will be used if the store type supports it, for
|
2855
|
+
scheduled jobscripts only.
|
2818
2856
|
wait
|
2819
2857
|
If True, this command will block until the workflow execution is complete.
|
2820
2858
|
add_to_known
|
@@ -2855,6 +2893,7 @@ class BaseApp(metaclass=Singleton):
|
|
2855
2893
|
variables=variables,
|
2856
2894
|
status=status,
|
2857
2895
|
)
|
2896
|
+
assert isinstance(wk, _Workflow)
|
2858
2897
|
submitted_js = wk.submit(
|
2859
2898
|
JS_parallelism=JS_parallelism,
|
2860
2899
|
wait=wait,
|
@@ -2882,7 +2921,8 @@ class BaseApp(metaclass=Singleton):
|
|
2882
2921
|
store_kwargs: dict[str, Any] | None = None,
|
2883
2922
|
variables: dict[str, str] | None = None,
|
2884
2923
|
status: bool = True,
|
2885
|
-
|
2924
|
+
add_submission: bool = False,
|
2925
|
+
) -> _Workflow | _Submission | None:
|
2886
2926
|
"""
|
2887
2927
|
Generate a new {app_name} workflow from a builtin demo workflow template.
|
2888
2928
|
|
@@ -2918,11 +2958,15 @@ class BaseApp(metaclass=Singleton):
|
|
2918
2958
|
String variables to substitute in the demo workflow template file.
|
2919
2959
|
status
|
2920
2960
|
If True, display a live status to track workflow creation progress.
|
2961
|
+
add_submission
|
2962
|
+
If True, add a submission to the workflow (but do not submit).
|
2921
2963
|
|
2922
2964
|
Returns
|
2923
2965
|
-------
|
2924
2966
|
Workflow
|
2925
|
-
The created workflow
|
2967
|
+
The created workflow, if `add_submission` is `False`.
|
2968
|
+
Submission
|
2969
|
+
The created submission object, if `add_submission` is `True`.
|
2926
2970
|
"""
|
2927
2971
|
self.API_logger.info("make_demo_workflow called")
|
2928
2972
|
|
@@ -2933,7 +2977,7 @@ class BaseApp(metaclass=Singleton):
|
|
2933
2977
|
with status_context as status_, self.get_demo_workflow_template_file(
|
2934
2978
|
workflow_name
|
2935
2979
|
) as template_path:
|
2936
|
-
|
2980
|
+
wk = self.Workflow.from_file(
|
2937
2981
|
template_path=template_path,
|
2938
2982
|
template_format=template_format,
|
2939
2983
|
path=str(path) if path else None,
|
@@ -2946,6 +2990,11 @@ class BaseApp(metaclass=Singleton):
|
|
2946
2990
|
variables=variables,
|
2947
2991
|
status=status_,
|
2948
2992
|
)
|
2993
|
+
if add_submission:
|
2994
|
+
with wk._store.cached_load():
|
2995
|
+
with wk.batch_update():
|
2996
|
+
return wk._add_submission(status=status_)
|
2997
|
+
return wk
|
2949
2998
|
|
2950
2999
|
def _make_and_submit_demo_workflow(
|
2951
3000
|
self,
|
@@ -2959,7 +3008,7 @@ class BaseApp(metaclass=Singleton):
|
|
2959
3008
|
ts_name_fmt: str | None = None,
|
2960
3009
|
store_kwargs: dict[str, Any] | None = None,
|
2961
3010
|
variables: dict[str, str] | None = None,
|
2962
|
-
JS_parallelism: bool | None = None,
|
3011
|
+
JS_parallelism: bool | Literal["direct", "scheduled"] | None = None,
|
2963
3012
|
wait: bool = False,
|
2964
3013
|
add_to_known: bool = True,
|
2965
3014
|
return_idx: bool = False,
|
@@ -3002,9 +3051,12 @@ class BaseApp(metaclass=Singleton):
|
|
3002
3051
|
variables
|
3003
3052
|
String variables to substitute in the demo workflow template file.
|
3004
3053
|
JS_parallelism
|
3005
|
-
If True, allow multiple jobscripts to execute simultaneously.
|
3006
|
-
|
3007
|
-
|
3054
|
+
If True, allow multiple jobscripts to execute simultaneously. If
|
3055
|
+
'scheduled'/'direct', only allow simultaneous execution of scheduled/direct
|
3056
|
+
jobscripts. Raises if set to True, 'scheduled', or 'direct', but the store
|
3057
|
+
type does not support the `jobscript_parallelism` feature. If not set,
|
3058
|
+
jobscript parallelism will be used if the store type supports it, for
|
3059
|
+
scheduled jobscripts only.
|
3008
3060
|
wait
|
3009
3061
|
If True, this command will block until the workflow execution is complete.
|
3010
3062
|
add_to_known
|
@@ -3042,6 +3094,7 @@ class BaseApp(metaclass=Singleton):
|
|
3042
3094
|
store_kwargs=store_kwargs,
|
3043
3095
|
variables=variables,
|
3044
3096
|
)
|
3097
|
+
assert isinstance(wk, _Workflow)
|
3045
3098
|
submitted_js = wk.submit(
|
3046
3099
|
JS_parallelism=JS_parallelism,
|
3047
3100
|
wait=wait,
|
@@ -3059,7 +3112,7 @@ class BaseApp(metaclass=Singleton):
|
|
3059
3112
|
def _submit_workflow(
|
3060
3113
|
self,
|
3061
3114
|
workflow_path: PathLike,
|
3062
|
-
JS_parallelism: bool | None = None,
|
3115
|
+
JS_parallelism: bool | Literal["direct", "scheduled"] | None = None,
|
3063
3116
|
wait: bool = False,
|
3064
3117
|
return_idx: bool = False,
|
3065
3118
|
tasks: list[int] | None = None,
|
@@ -3072,9 +3125,12 @@ class BaseApp(metaclass=Singleton):
|
|
3072
3125
|
workflow_path:
|
3073
3126
|
Path to an existing workflow.
|
3074
3127
|
JS_parallelism:
|
3075
|
-
If True, allow multiple jobscripts to execute simultaneously.
|
3076
|
-
|
3077
|
-
|
3128
|
+
If True, allow multiple jobscripts to execute simultaneously. If
|
3129
|
+
'scheduled'/'direct', only allow simultaneous execution of scheduled/direct
|
3130
|
+
jobscripts. Raises if set to True, 'scheduled', or 'direct', but the store
|
3131
|
+
type does not support the `jobscript_parallelism` feature. If not set,
|
3132
|
+
jobscript parallelism will be used if the store type supports it, for
|
3133
|
+
scheduled jobscripts only.
|
3078
3134
|
wait:
|
3079
3135
|
Whether to wait for the submission to complete.
|
3080
3136
|
return_idx:
|
@@ -3193,7 +3249,8 @@ class BaseApp(metaclass=Singleton):
|
|
3193
3249
|
|
3194
3250
|
# keys are (workflow path, submission index)
|
3195
3251
|
active_jobscripts: dict[
|
3196
|
-
tuple[str, int],
|
3252
|
+
tuple[str, int],
|
3253
|
+
Mapping[int, Mapping[int, Mapping[int, JobscriptElementState]]],
|
3197
3254
|
] = {}
|
3198
3255
|
loaded_workflows: dict[str, _Workflow] = {} # keys are workflow path
|
3199
3256
|
|
@@ -3295,7 +3352,9 @@ class BaseApp(metaclass=Singleton):
|
|
3295
3352
|
if file_dat_i["is_active"]:
|
3296
3353
|
# check it really is active:
|
3297
3354
|
run_key = (file_dat_i["path"], file_dat_i["sub_idx"])
|
3298
|
-
act_i_js: Mapping[
|
3355
|
+
act_i_js: Mapping[
|
3356
|
+
int, Mapping[int, Mapping[int, JobscriptElementState]]
|
3357
|
+
]
|
3299
3358
|
if run_key in active_jobscripts:
|
3300
3359
|
act_i_js = active_jobscripts[run_key]
|
3301
3360
|
else:
|
@@ -3521,25 +3580,27 @@ class BaseApp(metaclass=Singleton):
|
|
3521
3580
|
style_wk_name = "grey42 strike" if deleted else style
|
3522
3581
|
style_it = "italic grey42" if (no_access or not act_js) else "italic"
|
3523
3582
|
|
3524
|
-
|
3525
|
-
|
3526
|
-
|
3527
|
-
|
3528
|
-
|
3529
|
-
|
3530
|
-
|
3531
|
-
)
|
3532
|
-
|
3533
|
-
|
3534
|
-
|
3583
|
+
all_cells: dict[str, str | Text | Padding] = {}
|
3584
|
+
if "status" in columns:
|
3585
|
+
if act_js:
|
3586
|
+
act_js_states = set(
|
3587
|
+
state_i
|
3588
|
+
for js_dat in act_js.values()
|
3589
|
+
for block_dat in js_dat.values()
|
3590
|
+
for state_i in block_dat.values()
|
3591
|
+
)
|
3592
|
+
all_cells["status"] = "/".join(
|
3593
|
+
js_state.rich_repr
|
3594
|
+
for js_state in sorted(act_js_states, key=lambda x: x.value)
|
3595
|
+
)
|
3596
|
+
else:
|
3597
|
+
if deleted:
|
3598
|
+
txt = "deleted"
|
3599
|
+
elif unloadable:
|
3600
|
+
txt = "unloadable"
|
3535
3601
|
else:
|
3536
|
-
|
3537
|
-
|
3538
|
-
elif unloadable:
|
3539
|
-
txt = "unloadable"
|
3540
|
-
else:
|
3541
|
-
txt = "inactive"
|
3542
|
-
all_cells["status"] = Text(txt, style=style_it)
|
3602
|
+
txt = "inactive"
|
3603
|
+
all_cells["status"] = Text(txt, style=style_it)
|
3543
3604
|
|
3544
3605
|
if "id" in columns:
|
3545
3606
|
all_cells["id"] = Text(str(dat_i["local_id"]), style=style)
|
@@ -3591,7 +3652,9 @@ class BaseApp(metaclass=Singleton):
|
|
3591
3652
|
)
|
3592
3653
|
all_cells["actions_compact"] = " | ".join(
|
3593
3654
|
f"[{k.colour}]{k.symbol}[/{k.colour}]:{v}" # type: ignore
|
3594
|
-
for k, v in
|
3655
|
+
for k, v in dict(
|
3656
|
+
sorted(EAR_stat_count.items(), key=lambda x: x[0].value)
|
3657
|
+
).items()
|
3595
3658
|
)
|
3596
3659
|
else:
|
3597
3660
|
all_cells["actions_compact"] = ""
|
@@ -3711,18 +3774,29 @@ class BaseApp(metaclass=Singleton):
|
|
3711
3774
|
return path.resolve()
|
3712
3775
|
|
3713
3776
|
def _cancel(
|
3714
|
-
self,
|
3777
|
+
self,
|
3778
|
+
workflow_ref: int | str | Path,
|
3779
|
+
ref_is_path: str | None = None,
|
3780
|
+
status: bool = True,
|
3715
3781
|
) -> None:
|
3716
3782
|
"""
|
3717
3783
|
Cancel the execution of a workflow submission.
|
3718
3784
|
|
3719
3785
|
Parameters
|
3720
3786
|
----------
|
3721
|
-
|
3722
|
-
|
3787
|
+
workflow_ref: int | str | Path
|
3788
|
+
Which workflow to cancel, by ID or path.
|
3789
|
+
ref_is_path: str
|
3790
|
+
One of "``id``", "``path``" or "``assume-id``" (the default)
|
3791
|
+
status: bool
|
3792
|
+
Whether to show a live status during cancel.
|
3723
3793
|
"""
|
3724
3794
|
path = self._resolve_workflow_reference(str(workflow_ref), ref_is_path)
|
3725
|
-
self.Workflow(path).cancel()
|
3795
|
+
self.Workflow(path).cancel(status=status)
|
3796
|
+
|
3797
|
+
@staticmethod
|
3798
|
+
def redirect_std_to_file(*args, **kwargs):
|
3799
|
+
return redirect_std_to_file_hpcflow(*args, **kwargs)
|
3726
3800
|
|
3727
3801
|
def configure_env(
|
3728
3802
|
self,
|