hpcflow-new2 0.2.0a190__py3-none-any.whl → 0.2.0a199__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 +150 -89
- 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 +78 -7
- hpcflow/sdk/core/workflow.py +1538 -336
- 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/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/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.0a199.dist-info}/METADATA +7 -4
- hpcflow_new2-0.2.0a199.dist-info/RECORD +221 -0
- hpcflow_new2-0.2.0a190.dist-info/RECORD +0 -165
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.dist-info}/LICENSE +0 -0
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.dist-info}/WHEEL +0 -0
- {hpcflow_new2-0.2.0a190.dist-info → hpcflow_new2-0.2.0a199.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
|
|
@@ -2651,7 +2676,8 @@ class BaseApp(metaclass=Singleton):
|
|
2651
2676
|
store_kwargs: dict[str, Any] | None = None,
|
2652
2677
|
variables: dict[str, str] | None = None,
|
2653
2678
|
status: bool = True,
|
2654
|
-
|
2679
|
+
add_submission: bool = False,
|
2680
|
+
) -> _Workflow | _Submission | None:
|
2655
2681
|
"""
|
2656
2682
|
Generate a new {app_name} workflow from a file or string containing a workflow
|
2657
2683
|
template parametrisation.
|
@@ -2690,11 +2716,15 @@ class BaseApp(metaclass=Singleton):
|
|
2690
2716
|
String variables to substitute in `template_file_or_str`.
|
2691
2717
|
status
|
2692
2718
|
If True, display a live status to track workflow creation progress.
|
2719
|
+
add_submission
|
2720
|
+
If True, add a submission to the workflow (but do not submit).
|
2693
2721
|
|
2694
2722
|
Returns
|
2695
2723
|
-------
|
2696
2724
|
Workflow
|
2697
|
-
The created workflow
|
2725
|
+
The created workflow, if `add_submission` is `False`.
|
2726
|
+
Submission
|
2727
|
+
The created submission object, if `add_submission` is `True`.
|
2698
2728
|
"""
|
2699
2729
|
self.API_logger.info("make_workflow called")
|
2700
2730
|
|
@@ -2703,44 +2733,31 @@ class BaseApp(metaclass=Singleton):
|
|
2703
2733
|
)
|
2704
2734
|
|
2705
2735
|
with status_context as status_:
|
2736
|
+
|
2737
|
+
common: MakeWorkflowCommonArgs = {
|
2738
|
+
"path": str(path) if path else None,
|
2739
|
+
"name": name,
|
2740
|
+
"overwrite": overwrite,
|
2741
|
+
"store": store,
|
2742
|
+
"ts_fmt": ts_fmt,
|
2743
|
+
"ts_name_fmt": ts_name_fmt,
|
2744
|
+
"store_kwargs": store_kwargs,
|
2745
|
+
"variables": variables,
|
2746
|
+
"status": status_,
|
2747
|
+
}
|
2706
2748
|
if not is_string:
|
2707
|
-
|
2749
|
+
wk = self.Workflow.from_file(
|
2708
2750
|
template_path=template_file_or_str,
|
2709
2751
|
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_,
|
2752
|
+
**common,
|
2719
2753
|
)
|
2720
2754
|
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_,
|
2755
|
+
wk = self.Workflow.from_JSON_string(
|
2756
|
+
JSON_str=str(template_file_or_str), **common
|
2732
2757
|
)
|
2733
2758
|
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,
|
2759
|
+
wk = self.Workflow.from_YAML_string(
|
2760
|
+
YAML_str=str(template_file_or_str), **common
|
2744
2761
|
)
|
2745
2762
|
elif not template_format:
|
2746
2763
|
raise ValueError(
|
@@ -2752,6 +2769,11 @@ class BaseApp(metaclass=Singleton):
|
|
2752
2769
|
f"Template format {template_format!r} not understood. Available template "
|
2753
2770
|
f"formats are {ALL_TEMPLATE_FORMATS!r}."
|
2754
2771
|
)
|
2772
|
+
if add_submission:
|
2773
|
+
with wk._store.cached_load(), wk.batch_update():
|
2774
|
+
return wk._add_submission(status=status_)
|
2775
|
+
|
2776
|
+
return wk
|
2755
2777
|
|
2756
2778
|
def _make_and_submit_workflow(
|
2757
2779
|
self,
|
@@ -2766,7 +2788,7 @@ class BaseApp(metaclass=Singleton):
|
|
2766
2788
|
ts_name_fmt: str | None = None,
|
2767
2789
|
store_kwargs: dict[str, Any] | None = None,
|
2768
2790
|
variables: dict[str, str] | None = None,
|
2769
|
-
JS_parallelism: bool | None = None,
|
2791
|
+
JS_parallelism: bool | Literal["direct", "scheduled"] | None = None,
|
2770
2792
|
wait: bool = False,
|
2771
2793
|
add_to_known: bool = True,
|
2772
2794
|
return_idx: bool = False,
|
@@ -2812,9 +2834,12 @@ class BaseApp(metaclass=Singleton):
|
|
2812
2834
|
variables
|
2813
2835
|
String variables to substitute in `template_file_or_str`.
|
2814
2836
|
JS_parallelism
|
2815
|
-
If True, allow multiple jobscripts to execute simultaneously.
|
2816
|
-
|
2817
|
-
|
2837
|
+
If True, allow multiple jobscripts to execute simultaneously. If
|
2838
|
+
'scheduled'/'direct', only allow simultaneous execution of scheduled/direct
|
2839
|
+
jobscripts. Raises if set to True, 'scheduled', or 'direct', but the store
|
2840
|
+
type does not support the `jobscript_parallelism` feature. If not set,
|
2841
|
+
jobscript parallelism will be used if the store type supports it, for
|
2842
|
+
scheduled jobscripts only.
|
2818
2843
|
wait
|
2819
2844
|
If True, this command will block until the workflow execution is complete.
|
2820
2845
|
add_to_known
|
@@ -2855,6 +2880,7 @@ class BaseApp(metaclass=Singleton):
|
|
2855
2880
|
variables=variables,
|
2856
2881
|
status=status,
|
2857
2882
|
)
|
2883
|
+
assert isinstance(wk, _Workflow)
|
2858
2884
|
submitted_js = wk.submit(
|
2859
2885
|
JS_parallelism=JS_parallelism,
|
2860
2886
|
wait=wait,
|
@@ -2882,7 +2908,8 @@ class BaseApp(metaclass=Singleton):
|
|
2882
2908
|
store_kwargs: dict[str, Any] | None = None,
|
2883
2909
|
variables: dict[str, str] | None = None,
|
2884
2910
|
status: bool = True,
|
2885
|
-
|
2911
|
+
add_submission: bool = False,
|
2912
|
+
) -> _Workflow | _Submission | None:
|
2886
2913
|
"""
|
2887
2914
|
Generate a new {app_name} workflow from a builtin demo workflow template.
|
2888
2915
|
|
@@ -2918,11 +2945,15 @@ class BaseApp(metaclass=Singleton):
|
|
2918
2945
|
String variables to substitute in the demo workflow template file.
|
2919
2946
|
status
|
2920
2947
|
If True, display a live status to track workflow creation progress.
|
2948
|
+
add_submission
|
2949
|
+
If True, add a submission to the workflow (but do not submit).
|
2921
2950
|
|
2922
2951
|
Returns
|
2923
2952
|
-------
|
2924
2953
|
Workflow
|
2925
|
-
The created workflow
|
2954
|
+
The created workflow, if `add_submission` is `False`.
|
2955
|
+
Submission
|
2956
|
+
The created submission object, if `add_submission` is `True`.
|
2926
2957
|
"""
|
2927
2958
|
self.API_logger.info("make_demo_workflow called")
|
2928
2959
|
|
@@ -2933,7 +2964,7 @@ class BaseApp(metaclass=Singleton):
|
|
2933
2964
|
with status_context as status_, self.get_demo_workflow_template_file(
|
2934
2965
|
workflow_name
|
2935
2966
|
) as template_path:
|
2936
|
-
|
2967
|
+
wk = self.Workflow.from_file(
|
2937
2968
|
template_path=template_path,
|
2938
2969
|
template_format=template_format,
|
2939
2970
|
path=str(path) if path else None,
|
@@ -2946,6 +2977,11 @@ class BaseApp(metaclass=Singleton):
|
|
2946
2977
|
variables=variables,
|
2947
2978
|
status=status_,
|
2948
2979
|
)
|
2980
|
+
if add_submission:
|
2981
|
+
with wk._store.cached_load():
|
2982
|
+
with wk.batch_update():
|
2983
|
+
return wk._add_submission(status=status_)
|
2984
|
+
return wk
|
2949
2985
|
|
2950
2986
|
def _make_and_submit_demo_workflow(
|
2951
2987
|
self,
|
@@ -2959,7 +2995,7 @@ class BaseApp(metaclass=Singleton):
|
|
2959
2995
|
ts_name_fmt: str | None = None,
|
2960
2996
|
store_kwargs: dict[str, Any] | None = None,
|
2961
2997
|
variables: dict[str, str] | None = None,
|
2962
|
-
JS_parallelism: bool | None = None,
|
2998
|
+
JS_parallelism: bool | Literal["direct", "scheduled"] | None = None,
|
2963
2999
|
wait: bool = False,
|
2964
3000
|
add_to_known: bool = True,
|
2965
3001
|
return_idx: bool = False,
|
@@ -3002,9 +3038,12 @@ class BaseApp(metaclass=Singleton):
|
|
3002
3038
|
variables
|
3003
3039
|
String variables to substitute in the demo workflow template file.
|
3004
3040
|
JS_parallelism
|
3005
|
-
If True, allow multiple jobscripts to execute simultaneously.
|
3006
|
-
|
3007
|
-
|
3041
|
+
If True, allow multiple jobscripts to execute simultaneously. If
|
3042
|
+
'scheduled'/'direct', only allow simultaneous execution of scheduled/direct
|
3043
|
+
jobscripts. Raises if set to True, 'scheduled', or 'direct', but the store
|
3044
|
+
type does not support the `jobscript_parallelism` feature. If not set,
|
3045
|
+
jobscript parallelism will be used if the store type supports it, for
|
3046
|
+
scheduled jobscripts only.
|
3008
3047
|
wait
|
3009
3048
|
If True, this command will block until the workflow execution is complete.
|
3010
3049
|
add_to_known
|
@@ -3042,6 +3081,7 @@ class BaseApp(metaclass=Singleton):
|
|
3042
3081
|
store_kwargs=store_kwargs,
|
3043
3082
|
variables=variables,
|
3044
3083
|
)
|
3084
|
+
assert isinstance(wk, _Workflow)
|
3045
3085
|
submitted_js = wk.submit(
|
3046
3086
|
JS_parallelism=JS_parallelism,
|
3047
3087
|
wait=wait,
|
@@ -3059,7 +3099,7 @@ class BaseApp(metaclass=Singleton):
|
|
3059
3099
|
def _submit_workflow(
|
3060
3100
|
self,
|
3061
3101
|
workflow_path: PathLike,
|
3062
|
-
JS_parallelism: bool | None = None,
|
3102
|
+
JS_parallelism: bool | Literal["direct", "scheduled"] | None = None,
|
3063
3103
|
wait: bool = False,
|
3064
3104
|
return_idx: bool = False,
|
3065
3105
|
tasks: list[int] | None = None,
|
@@ -3072,9 +3112,12 @@ class BaseApp(metaclass=Singleton):
|
|
3072
3112
|
workflow_path:
|
3073
3113
|
Path to an existing workflow.
|
3074
3114
|
JS_parallelism:
|
3075
|
-
If True, allow multiple jobscripts to execute simultaneously.
|
3076
|
-
|
3077
|
-
|
3115
|
+
If True, allow multiple jobscripts to execute simultaneously. If
|
3116
|
+
'scheduled'/'direct', only allow simultaneous execution of scheduled/direct
|
3117
|
+
jobscripts. Raises if set to True, 'scheduled', or 'direct', but the store
|
3118
|
+
type does not support the `jobscript_parallelism` feature. If not set,
|
3119
|
+
jobscript parallelism will be used if the store type supports it, for
|
3120
|
+
scheduled jobscripts only.
|
3078
3121
|
wait:
|
3079
3122
|
Whether to wait for the submission to complete.
|
3080
3123
|
return_idx:
|
@@ -3193,7 +3236,8 @@ class BaseApp(metaclass=Singleton):
|
|
3193
3236
|
|
3194
3237
|
# keys are (workflow path, submission index)
|
3195
3238
|
active_jobscripts: dict[
|
3196
|
-
tuple[str, int],
|
3239
|
+
tuple[str, int],
|
3240
|
+
Mapping[int, Mapping[int, Mapping[int, JobscriptElementState]]],
|
3197
3241
|
] = {}
|
3198
3242
|
loaded_workflows: dict[str, _Workflow] = {} # keys are workflow path
|
3199
3243
|
|
@@ -3295,7 +3339,9 @@ class BaseApp(metaclass=Singleton):
|
|
3295
3339
|
if file_dat_i["is_active"]:
|
3296
3340
|
# check it really is active:
|
3297
3341
|
run_key = (file_dat_i["path"], file_dat_i["sub_idx"])
|
3298
|
-
act_i_js: Mapping[
|
3342
|
+
act_i_js: Mapping[
|
3343
|
+
int, Mapping[int, Mapping[int, JobscriptElementState]]
|
3344
|
+
]
|
3299
3345
|
if run_key in active_jobscripts:
|
3300
3346
|
act_i_js = active_jobscripts[run_key]
|
3301
3347
|
else:
|
@@ -3521,25 +3567,27 @@ class BaseApp(metaclass=Singleton):
|
|
3521
3567
|
style_wk_name = "grey42 strike" if deleted else style
|
3522
3568
|
style_it = "italic grey42" if (no_access or not act_js) else "italic"
|
3523
3569
|
|
3524
|
-
|
3525
|
-
|
3526
|
-
|
3527
|
-
|
3528
|
-
|
3529
|
-
|
3530
|
-
|
3531
|
-
)
|
3532
|
-
|
3533
|
-
|
3534
|
-
|
3570
|
+
all_cells: dict[str, str | Text | Padding] = {}
|
3571
|
+
if "status" in columns:
|
3572
|
+
if act_js:
|
3573
|
+
act_js_states = set(
|
3574
|
+
state_i
|
3575
|
+
for js_dat in act_js.values()
|
3576
|
+
for block_dat in js_dat.values()
|
3577
|
+
for state_i in block_dat.values()
|
3578
|
+
)
|
3579
|
+
all_cells["status"] = "/".join(
|
3580
|
+
js_state.rich_repr
|
3581
|
+
for js_state in sorted(act_js_states, key=lambda x: x.value)
|
3582
|
+
)
|
3583
|
+
else:
|
3584
|
+
if deleted:
|
3585
|
+
txt = "deleted"
|
3586
|
+
elif unloadable:
|
3587
|
+
txt = "unloadable"
|
3535
3588
|
else:
|
3536
|
-
|
3537
|
-
|
3538
|
-
elif unloadable:
|
3539
|
-
txt = "unloadable"
|
3540
|
-
else:
|
3541
|
-
txt = "inactive"
|
3542
|
-
all_cells["status"] = Text(txt, style=style_it)
|
3589
|
+
txt = "inactive"
|
3590
|
+
all_cells["status"] = Text(txt, style=style_it)
|
3543
3591
|
|
3544
3592
|
if "id" in columns:
|
3545
3593
|
all_cells["id"] = Text(str(dat_i["local_id"]), style=style)
|
@@ -3591,7 +3639,9 @@ class BaseApp(metaclass=Singleton):
|
|
3591
3639
|
)
|
3592
3640
|
all_cells["actions_compact"] = " | ".join(
|
3593
3641
|
f"[{k.colour}]{k.symbol}[/{k.colour}]:{v}" # type: ignore
|
3594
|
-
for k, v in
|
3642
|
+
for k, v in dict(
|
3643
|
+
sorted(EAR_stat_count.items(), key=lambda x: x[0].value)
|
3644
|
+
).items()
|
3595
3645
|
)
|
3596
3646
|
else:
|
3597
3647
|
all_cells["actions_compact"] = ""
|
@@ -3711,18 +3761,29 @@ class BaseApp(metaclass=Singleton):
|
|
3711
3761
|
return path.resolve()
|
3712
3762
|
|
3713
3763
|
def _cancel(
|
3714
|
-
self,
|
3764
|
+
self,
|
3765
|
+
workflow_ref: int | str | Path,
|
3766
|
+
ref_is_path: str | None = None,
|
3767
|
+
status: bool = True,
|
3715
3768
|
) -> None:
|
3716
3769
|
"""
|
3717
3770
|
Cancel the execution of a workflow submission.
|
3718
3771
|
|
3719
3772
|
Parameters
|
3720
3773
|
----------
|
3721
|
-
|
3722
|
-
|
3774
|
+
workflow_ref: int | str | Path
|
3775
|
+
Which workflow to cancel, by ID or path.
|
3776
|
+
ref_is_path: str
|
3777
|
+
One of "``id``", "``path``" or "``assume-id``" (the default)
|
3778
|
+
status: bool
|
3779
|
+
Whether to show a live status during cancel.
|
3723
3780
|
"""
|
3724
3781
|
path = self._resolve_workflow_reference(str(workflow_ref), ref_is_path)
|
3725
|
-
self.Workflow(path).cancel()
|
3782
|
+
self.Workflow(path).cancel(status=status)
|
3783
|
+
|
3784
|
+
@staticmethod
|
3785
|
+
def redirect_std_to_file(*args, **kwargs):
|
3786
|
+
return redirect_std_to_file_hpcflow(*args, **kwargs)
|
3726
3787
|
|
3727
3788
|
def configure_env(
|
3728
3789
|
self,
|