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
hpcflow/sdk/cli.py
CHANGED
@@ -2,12 +2,13 @@
|
|
2
2
|
Command line interface implementation.
|
3
3
|
"""
|
4
4
|
|
5
|
+
from __future__ import annotations
|
5
6
|
import json
|
6
7
|
import os
|
7
|
-
from typing import Dict, List
|
8
8
|
import click
|
9
9
|
from colorama import init as colorama_init
|
10
|
-
from termcolor import colored
|
10
|
+
from termcolor import colored # type: ignore
|
11
|
+
from typing import TYPE_CHECKING
|
11
12
|
from rich.pretty import pprint
|
12
13
|
|
13
14
|
from hpcflow import __version__, _app_name
|
@@ -46,7 +47,16 @@ from hpcflow.sdk.cli_common import (
|
|
46
47
|
)
|
47
48
|
from hpcflow.sdk.helper.cli import get_helper_CLI
|
48
49
|
from hpcflow.sdk.log import TimeIt
|
50
|
+
from hpcflow.sdk.core.workflow import Workflow
|
49
51
|
from hpcflow.sdk.submission.shells import ALL_SHELLS
|
52
|
+
from hpcflow.sdk.submission.jobscript import Jobscript
|
53
|
+
from hpcflow.sdk.submission.submission import Submission
|
54
|
+
from hpcflow.sdk.submission.schedulers.sge import SGEPosix
|
55
|
+
|
56
|
+
if TYPE_CHECKING:
|
57
|
+
from pathlib import Path
|
58
|
+
from typing import Literal
|
59
|
+
from .app import BaseApp
|
50
60
|
|
51
61
|
#: Standard option
|
52
62
|
string_option = click.option(
|
@@ -59,16 +69,22 @@ string_option = click.option(
|
|
59
69
|
workflow_ref_type_opt = click.option(
|
60
70
|
"--ref-type",
|
61
71
|
"-r",
|
62
|
-
type=click.Choice(
|
72
|
+
type=click.Choice(("assume-id", "id", "path")),
|
63
73
|
default="assume-id",
|
64
74
|
help="How to interpret a reference, as an ID, a path, or to guess.",
|
65
75
|
)
|
66
76
|
|
77
|
+
#: Get the current workflow from the context.
|
78
|
+
_pass_workflow = click.make_pass_decorator(Workflow)
|
79
|
+
#: Get the current submission from the context.
|
80
|
+
_pass_submission = click.make_pass_decorator(Submission)
|
81
|
+
#: Get the current jobscript from the context.
|
82
|
+
_pass_js = click.make_pass_decorator(Jobscript)
|
67
83
|
|
68
84
|
_add_doc_from_help(string_option, workflow_ref_type_opt)
|
69
85
|
|
70
86
|
|
71
|
-
def parse_jobscript_wait_spec(jobscripts: str) ->
|
87
|
+
def parse_jobscript_wait_spec(jobscripts: str) -> dict[int, list[int]]:
|
72
88
|
"""
|
73
89
|
Parse a jobscript wait specification.
|
74
90
|
"""
|
@@ -79,7 +95,15 @@ def parse_jobscript_wait_spec(jobscripts: str) -> Dict[int, List[int]]:
|
|
79
95
|
return sub_js_idx_dct
|
80
96
|
|
81
97
|
|
82
|
-
def
|
98
|
+
def _set_help_name(cmd: click.Group | click.Command, app: BaseApp):
|
99
|
+
"""
|
100
|
+
Update the help string of the command to contain the name of the application.
|
101
|
+
"""
|
102
|
+
if cmd.help:
|
103
|
+
cmd.help = cmd.help.format(app_name=app.name)
|
104
|
+
|
105
|
+
|
106
|
+
def _make_API_CLI(app: BaseApp):
|
83
107
|
"""Generate the CLI for the main functionality."""
|
84
108
|
|
85
109
|
@click.command(name="make")
|
@@ -95,17 +119,17 @@ def _make_API_CLI(app):
|
|
95
119
|
@variables_option
|
96
120
|
@make_status_opt
|
97
121
|
def make_workflow(
|
98
|
-
template_file_or_str,
|
99
|
-
string,
|
100
|
-
format,
|
101
|
-
path,
|
102
|
-
name,
|
103
|
-
overwrite,
|
104
|
-
store,
|
105
|
-
ts_fmt=None,
|
106
|
-
ts_name_fmt=None,
|
107
|
-
variables=None,
|
108
|
-
status=True,
|
122
|
+
template_file_or_str: str,
|
123
|
+
string: bool,
|
124
|
+
format: Literal["json", "yaml"] | None,
|
125
|
+
path: Path | None,
|
126
|
+
name: str | None,
|
127
|
+
overwrite: bool,
|
128
|
+
store: str,
|
129
|
+
ts_fmt: str | None = None,
|
130
|
+
ts_name_fmt: str | None = None,
|
131
|
+
variables: list[tuple[str, str]] | None = None,
|
132
|
+
status: bool = True,
|
109
133
|
):
|
110
134
|
"""Generate a new {app_name} workflow.
|
111
135
|
|
@@ -123,7 +147,7 @@ def _make_API_CLI(app):
|
|
123
147
|
store=store,
|
124
148
|
ts_fmt=ts_fmt,
|
125
149
|
ts_name_fmt=ts_name_fmt,
|
126
|
-
variables=dict(variables),
|
150
|
+
variables=dict(variables) if variables is not None else None,
|
127
151
|
status=status,
|
128
152
|
)
|
129
153
|
click.echo(wk.path)
|
@@ -147,23 +171,23 @@ def _make_API_CLI(app):
|
|
147
171
|
@cancel_opt
|
148
172
|
@submit_status_opt
|
149
173
|
def make_and_submit_workflow(
|
150
|
-
template_file_or_str,
|
151
|
-
string,
|
152
|
-
format,
|
153
|
-
path,
|
154
|
-
name,
|
155
|
-
overwrite,
|
156
|
-
store,
|
157
|
-
ts_fmt=None,
|
158
|
-
ts_name_fmt=None,
|
159
|
-
variables=None,
|
160
|
-
js_parallelism=None,
|
161
|
-
wait=False,
|
162
|
-
add_to_known=True,
|
163
|
-
print_idx=False,
|
164
|
-
tasks=None,
|
165
|
-
cancel=False,
|
166
|
-
status=True,
|
174
|
+
template_file_or_str: str,
|
175
|
+
string: bool,
|
176
|
+
format: Literal["json", "yaml"] | None,
|
177
|
+
path: Path | None,
|
178
|
+
name: str | None,
|
179
|
+
overwrite: bool,
|
180
|
+
store: str,
|
181
|
+
ts_fmt: str | None = None,
|
182
|
+
ts_name_fmt: str | None = None,
|
183
|
+
variables: list[tuple[str, str]] | None = None,
|
184
|
+
js_parallelism: bool | None = None,
|
185
|
+
wait: bool = False,
|
186
|
+
add_to_known: bool = True,
|
187
|
+
print_idx: bool = False,
|
188
|
+
tasks: list[int] | None = None,
|
189
|
+
cancel: bool = False,
|
190
|
+
status: bool = True,
|
167
191
|
):
|
168
192
|
"""Generate and submit a new {app_name} workflow.
|
169
193
|
|
@@ -182,7 +206,7 @@ def _make_API_CLI(app):
|
|
182
206
|
store=store,
|
183
207
|
ts_fmt=ts_fmt,
|
184
208
|
ts_name_fmt=ts_name_fmt,
|
185
|
-
variables=dict(variables),
|
209
|
+
variables=dict(variables) if variables is not None else None,
|
186
210
|
JS_parallelism=js_parallelism,
|
187
211
|
wait=wait,
|
188
212
|
add_to_known=add_to_known,
|
@@ -192,12 +216,13 @@ def _make_API_CLI(app):
|
|
192
216
|
status=status,
|
193
217
|
)
|
194
218
|
if print_idx:
|
219
|
+
assert isinstance(out, tuple)
|
195
220
|
click.echo(out[1])
|
196
221
|
|
197
222
|
@click.command(context_settings={"ignore_unknown_options": True})
|
198
223
|
@click.argument("py_test_args", nargs=-1, type=click.UNPROCESSED)
|
199
224
|
@click.pass_context
|
200
|
-
def test(ctx, py_test_args):
|
225
|
+
def test(ctx: click.Context, py_test_args: list[str]):
|
201
226
|
"""Run {app_name} test suite.
|
202
227
|
|
203
228
|
PY_TEST_ARGS are arguments passed on to Pytest.
|
@@ -208,7 +233,7 @@ def _make_API_CLI(app):
|
|
208
233
|
@click.command(context_settings={"ignore_unknown_options": True})
|
209
234
|
@click.argument("py_test_args", nargs=-1, type=click.UNPROCESSED)
|
210
235
|
@click.pass_context
|
211
|
-
def test_hpcflow(ctx, py_test_args):
|
236
|
+
def test_hpcflow(ctx: click.Context, py_test_args: list[str]):
|
212
237
|
"""Run hpcFlow test suite.
|
213
238
|
|
214
239
|
PY_TEST_ARGS are arguments passed on to Pytest.
|
@@ -222,8 +247,7 @@ def _make_API_CLI(app):
|
|
222
247
|
test,
|
223
248
|
]
|
224
249
|
for cmd in commands:
|
225
|
-
|
226
|
-
cmd.help = cmd.help.format(app_name=app.name)
|
250
|
+
_set_help_name(cmd, app)
|
227
251
|
|
228
252
|
if app.name != "hpcFlow":
|
229
253
|
# `test_hpcflow` is the same as `test` for the hpcflow app no need to add both:
|
@@ -232,118 +256,116 @@ def _make_API_CLI(app):
|
|
232
256
|
return commands
|
233
257
|
|
234
258
|
|
235
|
-
def _make_workflow_submission_jobscript_CLI(app):
|
259
|
+
def _make_workflow_submission_jobscript_CLI(app: BaseApp):
|
236
260
|
"""Generate the CLI for interacting with existing workflow submission
|
237
261
|
jobscripts."""
|
238
262
|
|
239
263
|
@click.group(name="js")
|
264
|
+
@_pass_submission
|
240
265
|
@click.pass_context
|
241
266
|
@click.argument("js_idx", type=click.INT)
|
242
|
-
def jobscript(ctx, js_idx):
|
267
|
+
def jobscript(ctx: click.Context, sb: Submission, js_idx: int):
|
243
268
|
"""Interact with existing {app_name} workflow submission jobscripts.
|
244
269
|
|
245
270
|
JS_IDX is the jobscript index within the submission object.
|
246
271
|
|
247
272
|
"""
|
248
|
-
ctx.obj
|
273
|
+
ctx.obj = sb.jobscripts[js_idx]
|
249
274
|
|
250
275
|
@jobscript.command(name="res")
|
251
|
-
@
|
252
|
-
def resources(
|
276
|
+
@_pass_js
|
277
|
+
def resources(job: Jobscript):
|
253
278
|
"""Get resources associated with this jobscript."""
|
254
|
-
click.echo(
|
279
|
+
click.echo(job.resources.__dict__)
|
255
280
|
|
256
281
|
@jobscript.command(name="deps")
|
257
|
-
@
|
258
|
-
def dependencies(
|
282
|
+
@_pass_js
|
283
|
+
def dependencies(job: Jobscript):
|
259
284
|
"""Get jobscript dependencies."""
|
260
|
-
click.echo(
|
285
|
+
click.echo(job.dependencies)
|
261
286
|
|
262
287
|
@jobscript.command()
|
263
|
-
@
|
264
|
-
def path(
|
288
|
+
@_pass_js
|
289
|
+
def path(job: Jobscript):
|
265
290
|
"""Get the file path to the jobscript."""
|
266
|
-
click.echo(
|
291
|
+
click.echo(job.jobscript_path)
|
267
292
|
|
268
293
|
@jobscript.command()
|
269
|
-
@
|
270
|
-
def show(
|
294
|
+
@_pass_js
|
295
|
+
def show(job: Jobscript):
|
271
296
|
"""Show the jobscript file."""
|
272
|
-
with
|
297
|
+
with job.jobscript_path.open("rt") as fp:
|
273
298
|
click.echo(fp.read())
|
274
299
|
|
275
|
-
jobscript
|
276
|
-
|
300
|
+
_set_help_name(jobscript, app)
|
277
301
|
return jobscript
|
278
302
|
|
279
303
|
|
280
|
-
def _make_workflow_submission_CLI(app):
|
304
|
+
def _make_workflow_submission_CLI(app: BaseApp):
|
281
305
|
"""Generate the CLI for interacting with existing workflow submissions."""
|
282
306
|
|
283
307
|
@click.group(name="sub")
|
308
|
+
@_pass_workflow
|
284
309
|
@click.pass_context
|
285
310
|
@click.argument("sub_idx", type=click.INT)
|
286
|
-
def submission(ctx, sub_idx):
|
311
|
+
def submission(ctx: click.Context, wf: Workflow, sub_idx: int):
|
287
312
|
"""Interact with existing {app_name} workflow submissions.
|
288
313
|
|
289
314
|
SUB_IDX is the submission index.
|
290
315
|
|
291
316
|
"""
|
292
|
-
ctx.obj
|
317
|
+
ctx.obj = wf.submissions[sub_idx]
|
293
318
|
|
294
319
|
@submission.command("status")
|
295
|
-
@
|
296
|
-
def status(
|
320
|
+
@_pass_submission
|
321
|
+
def status(sb: Submission):
|
297
322
|
"""Get the submission status."""
|
298
|
-
click.echo(
|
323
|
+
click.echo(sb.status.name.lower())
|
299
324
|
|
300
325
|
@submission.command("submitted-js")
|
301
|
-
@
|
302
|
-
def submitted_JS(
|
326
|
+
@_pass_submission
|
327
|
+
def submitted_JS(sb: Submission):
|
303
328
|
"""Get a list of jobscript indices that have been submitted."""
|
304
|
-
click.echo(
|
329
|
+
click.echo(sb.submitted_jobscripts)
|
305
330
|
|
306
331
|
@submission.command("outstanding-js")
|
307
|
-
@
|
308
|
-
def outstanding_JS(
|
332
|
+
@_pass_submission
|
333
|
+
def outstanding_JS(sb: Submission):
|
309
334
|
"""Get a list of jobscript indices that have not yet been submitted."""
|
310
|
-
click.echo(
|
335
|
+
click.echo(sb.outstanding_jobscripts)
|
311
336
|
|
312
337
|
@submission.command("needs-submit")
|
313
|
-
@
|
314
|
-
def needs_submit(
|
338
|
+
@_pass_submission
|
339
|
+
def needs_submit(sb: Submission):
|
315
340
|
"""Check if this submission needs submitting."""
|
316
|
-
click.echo(
|
341
|
+
click.echo(sb.needs_submit)
|
317
342
|
|
318
343
|
@submission.command("get-active-jobscripts")
|
319
|
-
@
|
320
|
-
def get_active_jobscripts(
|
344
|
+
@_pass_submission
|
345
|
+
def get_active_jobscripts(sb: Submission):
|
321
346
|
"""Show active jobscripts and their jobscript-element states."""
|
322
|
-
pprint(
|
347
|
+
pprint(sb.get_active_jobscripts(as_json=True))
|
323
348
|
|
324
|
-
submission
|
349
|
+
_set_help_name(submission, app)
|
325
350
|
submission.add_command(_make_workflow_submission_jobscript_CLI(app))
|
326
|
-
|
327
351
|
return submission
|
328
352
|
|
329
353
|
|
330
|
-
def _make_workflow_CLI(app):
|
354
|
+
def _make_workflow_CLI(app: BaseApp):
|
331
355
|
"""Generate the CLI for interacting with existing workflows."""
|
332
356
|
|
333
357
|
@click.group()
|
334
358
|
@click.argument("workflow_ref")
|
335
359
|
@workflow_ref_type_opt
|
336
360
|
@click.pass_context
|
337
|
-
def workflow(ctx, workflow_ref, ref_type):
|
361
|
+
def workflow(ctx: click.Context, workflow_ref: str, ref_type: str | None):
|
338
362
|
"""Interact with existing {app_name} workflows.
|
339
363
|
|
340
364
|
WORKFLOW_REF is the path to, or local ID of, an existing workflow.
|
341
365
|
|
342
366
|
"""
|
343
367
|
workflow_path = app._resolve_workflow_reference(workflow_ref, ref_type)
|
344
|
-
|
345
|
-
ctx.ensure_object(dict)
|
346
|
-
ctx.obj["workflow"] = wk
|
368
|
+
ctx.obj = app.Workflow(workflow_path)
|
347
369
|
|
348
370
|
@workflow.command(name="submit")
|
349
371
|
@js_parallelism_option
|
@@ -353,23 +375,23 @@ def _make_workflow_CLI(app):
|
|
353
375
|
@tasks_opt
|
354
376
|
@cancel_opt
|
355
377
|
@submit_status_opt
|
356
|
-
@
|
378
|
+
@_pass_workflow
|
357
379
|
def submit_workflow(
|
358
|
-
|
359
|
-
js_parallelism=None,
|
360
|
-
wait=False,
|
361
|
-
add_to_known=True,
|
362
|
-
print_idx=False,
|
363
|
-
tasks=None,
|
364
|
-
cancel=False,
|
365
|
-
status=True,
|
380
|
+
wf: Workflow,
|
381
|
+
js_parallelism: bool | None = None,
|
382
|
+
wait: bool = False,
|
383
|
+
add_to_known: bool = True,
|
384
|
+
print_idx: bool = False,
|
385
|
+
tasks: list[int] | None = None,
|
386
|
+
cancel: bool = False,
|
387
|
+
status: bool = True,
|
366
388
|
):
|
367
389
|
"""Submit the workflow."""
|
368
|
-
out =
|
390
|
+
out = wf.submit(
|
369
391
|
JS_parallelism=js_parallelism,
|
370
392
|
wait=wait,
|
371
393
|
add_to_known=add_to_known,
|
372
|
-
return_idx=
|
394
|
+
return_idx=True,
|
373
395
|
tasks=tasks,
|
374
396
|
cancel=cancel,
|
375
397
|
status=status,
|
@@ -389,19 +411,19 @@ def _make_workflow_CLI(app):
|
|
389
411
|
"separate patterns like these."
|
390
412
|
),
|
391
413
|
)
|
392
|
-
@
|
393
|
-
def wait(
|
414
|
+
@_pass_workflow
|
415
|
+
def wait(wf: Workflow, jobscripts: str | None):
|
394
416
|
js_spec = parse_jobscript_wait_spec(jobscripts) if jobscripts else None
|
395
|
-
|
417
|
+
wf.wait(sub_js=js_spec)
|
396
418
|
|
397
419
|
@workflow.command(name="abort-run")
|
398
420
|
@click.option("--submission", type=click.INT, default=-1)
|
399
421
|
@click.option("--task", type=click.INT)
|
400
422
|
@click.option("--element", type=click.INT)
|
401
|
-
@
|
402
|
-
def abort_run(
|
423
|
+
@_pass_workflow
|
424
|
+
def abort_run(wf: Workflow, submission: int, task: int, element: int):
|
403
425
|
"""Abort the specified run."""
|
404
|
-
|
426
|
+
wf.abort_run(
|
405
427
|
submission_idx=submission,
|
406
428
|
task_idx=task,
|
407
429
|
element_idx=element,
|
@@ -409,36 +431,36 @@ def _make_workflow_CLI(app):
|
|
409
431
|
|
410
432
|
@workflow.command(name="get-param")
|
411
433
|
@click.argument("index", type=click.INT)
|
412
|
-
@
|
413
|
-
def get_parameter(
|
434
|
+
@_pass_workflow
|
435
|
+
def get_parameter(wf: Workflow, index: int):
|
414
436
|
"""Get a parameter value by data index."""
|
415
|
-
click.echo(
|
437
|
+
click.echo(wf.get_parameter_data(index))
|
416
438
|
|
417
439
|
@workflow.command(name="get-param-source")
|
418
440
|
@click.argument("index", type=click.INT)
|
419
|
-
@
|
420
|
-
def get_parameter_source(
|
441
|
+
@_pass_workflow
|
442
|
+
def get_parameter_source(wf: Workflow, index: int):
|
421
443
|
"""Get a parameter source by data index."""
|
422
|
-
click.echo(
|
444
|
+
click.echo(wf.get_parameter_source(index))
|
423
445
|
|
424
446
|
@workflow.command(name="get-all-params")
|
425
|
-
@
|
426
|
-
def get_all_parameters(
|
447
|
+
@_pass_workflow
|
448
|
+
def get_all_parameters(wf: Workflow):
|
427
449
|
"""Get all parameter values."""
|
428
|
-
click.echo(
|
450
|
+
click.echo(wf.get_all_parameter_data())
|
429
451
|
|
430
452
|
@workflow.command(name="is-param-set")
|
431
453
|
@click.argument("index", type=click.INT)
|
432
|
-
@
|
433
|
-
def is_parameter_set(
|
454
|
+
@_pass_workflow
|
455
|
+
def is_parameter_set(wf: Workflow, index: int):
|
434
456
|
"""Check if a parameter specified by data index is set."""
|
435
|
-
click.echo(
|
457
|
+
click.echo(wf.is_parameter_set(index))
|
436
458
|
|
437
459
|
@workflow.command(name="show-all-status")
|
438
|
-
@
|
439
|
-
def show_all_EAR_statuses(
|
460
|
+
@_pass_workflow
|
461
|
+
def show_all_EAR_statuses(wf: Workflow):
|
440
462
|
"""Show the submission status of all workflow EARs."""
|
441
|
-
|
463
|
+
wf.show_all_EAR_statuses()
|
442
464
|
|
443
465
|
@workflow.command(name="zip")
|
444
466
|
@zip_path_opt
|
@@ -446,19 +468,19 @@ def _make_workflow_CLI(app):
|
|
446
468
|
@zip_log_opt
|
447
469
|
@zip_include_execute_opt
|
448
470
|
@zip_include_rechunk_backups_opt
|
449
|
-
@
|
471
|
+
@_pass_workflow
|
450
472
|
def zip_workflow(
|
451
|
-
|
452
|
-
path,
|
453
|
-
overwrite,
|
454
|
-
log,
|
455
|
-
include_execute,
|
456
|
-
include_rechunk_backups,
|
473
|
+
wf: Workflow,
|
474
|
+
path: str,
|
475
|
+
overwrite: bool,
|
476
|
+
log: str | None,
|
477
|
+
include_execute: bool,
|
478
|
+
include_rechunk_backups: bool,
|
457
479
|
):
|
458
480
|
"""Generate a copy of the workflow in the zip file format in the current working
|
459
481
|
directory."""
|
460
482
|
click.echo(
|
461
|
-
|
483
|
+
wf.zip(
|
462
484
|
path=path,
|
463
485
|
overwrite=overwrite,
|
464
486
|
log=log,
|
@@ -470,54 +492,48 @@ def _make_workflow_CLI(app):
|
|
470
492
|
@workflow.command(name="unzip")
|
471
493
|
@unzip_path_opt
|
472
494
|
@unzip_log_opt
|
473
|
-
@
|
474
|
-
def unzip_workflow(
|
495
|
+
@_pass_workflow
|
496
|
+
def unzip_workflow(wf: Workflow, path: str, log: str | None):
|
475
497
|
"""Generate a copy of the zipped workflow in the submittable Zarr format in the
|
476
498
|
current working directory."""
|
477
|
-
click.echo(
|
499
|
+
click.echo(wf.unzip(path=path, log=log))
|
478
500
|
|
479
501
|
@workflow.command(name="rechunk")
|
480
502
|
@rechunk_backup_opt
|
481
503
|
@rechunk_chunk_size_opt
|
482
504
|
@rechunk_status_opt
|
483
|
-
@
|
484
|
-
def rechunk(
|
505
|
+
@_pass_workflow
|
506
|
+
def rechunk(wf: Workflow, backup: bool, chunk_size: int, status: bool):
|
485
507
|
"""Rechunk metadata/runs and parameters/base arrays."""
|
486
|
-
|
508
|
+
wf.rechunk(backup=backup, chunk_size=chunk_size, status=status)
|
487
509
|
|
488
510
|
@workflow.command(name="rechunk-runs")
|
489
511
|
@rechunk_backup_opt
|
490
512
|
@rechunk_chunk_size_opt
|
491
513
|
@rechunk_status_opt
|
492
|
-
@
|
493
|
-
def rechunk_runs(
|
514
|
+
@_pass_workflow
|
515
|
+
def rechunk_runs(wf: Workflow, backup: bool, chunk_size: int, status: bool):
|
494
516
|
"""Rechunk the metadata/runs array."""
|
495
|
-
|
496
|
-
backup=backup, chunk_size=chunk_size, status=status
|
497
|
-
)
|
517
|
+
wf.rechunk_runs(backup=backup, chunk_size=chunk_size, status=status)
|
498
518
|
|
499
519
|
@workflow.command(name="rechunk-parameter-base")
|
500
520
|
@rechunk_backup_opt
|
501
521
|
@rechunk_chunk_size_opt
|
502
522
|
@rechunk_status_opt
|
503
|
-
@
|
504
|
-
def rechunk_parameter_base(
|
523
|
+
@_pass_workflow
|
524
|
+
def rechunk_parameter_base(wf: Workflow, backup: bool, chunk_size: int, status: bool):
|
505
525
|
"""Rechunk the parameters/base array."""
|
506
|
-
|
507
|
-
backup=backup, chunk_size=chunk_size, status=status
|
508
|
-
)
|
509
|
-
|
510
|
-
workflow.help = workflow.help.format(app_name=app.name)
|
526
|
+
wf.rechunk_parameter_base(backup=backup, chunk_size=chunk_size, status=status)
|
511
527
|
|
528
|
+
_set_help_name(workflow, app)
|
512
529
|
workflow.add_command(_make_workflow_submission_CLI(app))
|
513
|
-
|
514
530
|
return workflow
|
515
531
|
|
516
532
|
|
517
|
-
def _make_submission_CLI(app):
|
533
|
+
def _make_submission_CLI(app: BaseApp):
|
518
534
|
"""Generate the CLI for submission related queries."""
|
519
535
|
|
520
|
-
def OS_info_callback(ctx, param, value):
|
536
|
+
def OS_info_callback(ctx: click.Context, param, value: bool):
|
521
537
|
if not value or ctx.resilient_parsing:
|
522
538
|
return
|
523
539
|
pprint(app.get_OS_info())
|
@@ -532,16 +548,15 @@ def _make_submission_CLI(app):
|
|
532
548
|
expose_value=False,
|
533
549
|
callback=OS_info_callback,
|
534
550
|
)
|
535
|
-
|
536
|
-
def submission(ctx):
|
551
|
+
def submission():
|
537
552
|
"""Submission-related queries."""
|
538
|
-
|
553
|
+
pass
|
539
554
|
|
540
555
|
@submission.command("shell-info")
|
541
|
-
@click.argument("shell_name", type=click.Choice(ALL_SHELLS))
|
556
|
+
@click.argument("shell_name", type=click.Choice(list(ALL_SHELLS)))
|
542
557
|
@click.option("--exclude-os", is_flag=True, default=False)
|
543
558
|
@click.pass_context
|
544
|
-
def shell_info(ctx, shell_name, exclude_os):
|
559
|
+
def shell_info(ctx: click.Context, shell_name: str, exclude_os: bool):
|
545
560
|
"""Show information about the specified shell, such as the version."""
|
546
561
|
pprint(app.get_shell_info(shell_name, exclude_os))
|
547
562
|
ctx.exit()
|
@@ -549,13 +564,14 @@ def _make_submission_CLI(app):
|
|
549
564
|
@submission.group("scheduler")
|
550
565
|
@click.argument("scheduler_name")
|
551
566
|
@click.pass_context
|
552
|
-
def scheduler(ctx, scheduler_name):
|
553
|
-
ctx.obj
|
567
|
+
def scheduler(ctx: click.Context, scheduler_name: str):
|
568
|
+
ctx.obj = app.get_scheduler(scheduler_name, os.name)
|
569
|
+
|
570
|
+
pass_scheduler = click.make_pass_decorator(SGEPosix)
|
554
571
|
|
555
572
|
@scheduler.command()
|
556
|
-
@
|
557
|
-
def get_login_nodes(
|
558
|
-
scheduler = ctx.obj["scheduler_obj"]
|
573
|
+
@pass_scheduler
|
574
|
+
def get_login_nodes(scheduler: SGEPosix):
|
559
575
|
pprint(scheduler.get_login_nodes())
|
560
576
|
|
561
577
|
@submission.command()
|
@@ -566,8 +582,7 @@ def _make_submission_CLI(app):
|
|
566
582
|
default=False,
|
567
583
|
help="Do not format and only show JSON-compatible information.",
|
568
584
|
)
|
569
|
-
|
570
|
-
def get_known(ctx, as_json=False):
|
585
|
+
def get_known(as_json: bool = False):
|
571
586
|
"""Print known-submissions information as a formatted Python object."""
|
572
587
|
out = app.get_known_submissions(as_json=as_json)
|
573
588
|
if as_json:
|
@@ -578,11 +593,11 @@ def _make_submission_CLI(app):
|
|
578
593
|
return submission
|
579
594
|
|
580
595
|
|
581
|
-
def _make_internal_CLI(app):
|
596
|
+
def _make_internal_CLI(app: BaseApp):
|
582
597
|
"""Generate the CLI for internal use."""
|
583
598
|
|
584
599
|
@click.group()
|
585
|
-
def internal(help=True): # TEMP
|
600
|
+
def internal(help: bool = True): # TEMP
|
586
601
|
"""Internal CLI to be invoked by scripts generated by the app."""
|
587
602
|
pass
|
588
603
|
|
@@ -594,36 +609,36 @@ def _make_internal_CLI(app):
|
|
594
609
|
@internal.group()
|
595
610
|
@click.argument("path", type=click.Path(exists=True))
|
596
611
|
@click.pass_context
|
597
|
-
def workflow(ctx, path):
|
612
|
+
def workflow(ctx: click.Context, path: Path):
|
598
613
|
""""""
|
599
|
-
|
600
|
-
ctx.ensure_object(dict)
|
601
|
-
ctx.obj["workflow"] = wk
|
614
|
+
ctx.obj = app.Workflow(path)
|
602
615
|
|
603
616
|
@workflow.command()
|
617
|
+
@_pass_workflow
|
604
618
|
@click.pass_context
|
605
619
|
@click.argument("submission_idx", type=click.INT)
|
606
620
|
@click.argument("jobscript_idx", type=click.INT)
|
607
621
|
@click.argument("js_action_idx", type=click.INT)
|
608
622
|
@click.argument("ear_id", type=click.INT)
|
609
623
|
def write_commands(
|
610
|
-
ctx,
|
624
|
+
ctx: click.Context,
|
625
|
+
wf: Workflow,
|
611
626
|
submission_idx: int,
|
612
627
|
jobscript_idx: int,
|
613
628
|
js_action_idx: int,
|
614
629
|
ear_id: int,
|
615
630
|
):
|
616
631
|
app.CLI_logger.info(f"write commands for EAR ID {ear_id!r}.")
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
ear_id,
|
623
|
-
)
|
632
|
+
wf.write_commands(
|
633
|
+
submission_idx,
|
634
|
+
jobscript_idx,
|
635
|
+
js_action_idx,
|
636
|
+
ear_id,
|
624
637
|
)
|
638
|
+
ctx.exit()
|
625
639
|
|
626
640
|
@workflow.command()
|
641
|
+
@_pass_workflow
|
627
642
|
@click.pass_context
|
628
643
|
@click.argument("name")
|
629
644
|
@click.argument("value")
|
@@ -631,7 +646,8 @@ def _make_internal_CLI(app):
|
|
631
646
|
@click.argument("cmd_idx", type=click.INT)
|
632
647
|
@click.option("--stderr", is_flag=True, default=False)
|
633
648
|
def save_parameter(
|
634
|
-
ctx,
|
649
|
+
ctx: click.Context,
|
650
|
+
wf: Workflow,
|
635
651
|
name: str,
|
636
652
|
value: str,
|
637
653
|
ear_id: int,
|
@@ -643,9 +659,8 @@ def _make_internal_CLI(app):
|
|
643
659
|
f"{cmd_idx!r} (stderr={stderr!r})"
|
644
660
|
)
|
645
661
|
app.CLI_logger.debug(f"save parameter value is: {value!r}")
|
646
|
-
|
647
|
-
|
648
|
-
value = wk.process_shell_parameter_output(
|
662
|
+
with wf._store.cached_load():
|
663
|
+
value = wf.process_shell_parameter_output(
|
649
664
|
name=name,
|
650
665
|
value=value,
|
651
666
|
EAR_ID=ear_id,
|
@@ -653,23 +668,27 @@ def _make_internal_CLI(app):
|
|
653
668
|
stderr=stderr,
|
654
669
|
)
|
655
670
|
app.CLI_logger.debug(f"save parameter processed value is: {value!r}")
|
656
|
-
ctx.exit(
|
671
|
+
ctx.exit(wf.save_parameter(name=name, value=value, EAR_ID=ear_id))
|
657
672
|
|
658
673
|
@workflow.command()
|
674
|
+
@_pass_workflow
|
659
675
|
@click.pass_context
|
660
676
|
@click.argument("ear_id", type=click.INT)
|
661
|
-
def set_EAR_start(ctx, ear_id: int):
|
677
|
+
def set_EAR_start(ctx: click.Context, wf: Workflow, ear_id: int):
|
662
678
|
app.CLI_logger.info(f"set EAR start for EAR ID {ear_id!r}.")
|
663
|
-
|
679
|
+
wf.set_EAR_start(ear_id)
|
680
|
+
ctx.exit()
|
664
681
|
|
665
682
|
@workflow.command()
|
683
|
+
@_pass_workflow
|
666
684
|
@click.pass_context
|
667
685
|
@click.argument("js_idx", type=click.INT)
|
668
686
|
@click.argument("js_act_idx", type=click.INT)
|
669
687
|
@click.argument("ear_id", type=click.INT)
|
670
688
|
@click.argument("exit_code", type=click.INT)
|
671
689
|
def set_EAR_end(
|
672
|
-
ctx,
|
690
|
+
ctx: click.Context,
|
691
|
+
wf: Workflow,
|
673
692
|
js_idx: int,
|
674
693
|
js_act_idx: int,
|
675
694
|
ear_id: int,
|
@@ -678,38 +697,42 @@ def _make_internal_CLI(app):
|
|
678
697
|
app.CLI_logger.info(
|
679
698
|
f"set EAR end for EAR ID {ear_id!r} with exit code {exit_code!r}."
|
680
699
|
)
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
exit_code=exit_code,
|
687
|
-
)
|
700
|
+
wf.set_EAR_end(
|
701
|
+
js_idx=js_idx,
|
702
|
+
js_act_idx=js_act_idx,
|
703
|
+
EAR_ID=ear_id,
|
704
|
+
exit_code=exit_code,
|
688
705
|
)
|
706
|
+
ctx.exit()
|
689
707
|
|
690
708
|
@workflow.command()
|
709
|
+
@_pass_workflow
|
691
710
|
@click.pass_context
|
692
711
|
@click.argument("ear_id", type=click.INT)
|
693
|
-
def set_EAR_skip(ctx, ear_id: int):
|
712
|
+
def set_EAR_skip(ctx: click.Context, wf: Workflow, ear_id: int):
|
694
713
|
app.CLI_logger.info(f"set EAR skip for EAR ID {ear_id!r}.")
|
695
|
-
|
714
|
+
wf.set_EAR_skip(ear_id)
|
715
|
+
ctx.exit()
|
696
716
|
|
697
717
|
@workflow.command()
|
718
|
+
@_pass_workflow
|
698
719
|
@click.pass_context
|
699
720
|
@click.argument("ear_id", type=click.INT)
|
700
|
-
def get_EAR_skipped(ctx, ear_id: int):
|
721
|
+
def get_EAR_skipped(ctx: click.Context, wf: Workflow, ear_id: int):
|
701
722
|
"""Return 1 if the given EAR is to be skipped, else return 0."""
|
702
723
|
app.CLI_logger.info(f"get EAR skip for EAR ID {ear_id!r}.")
|
703
|
-
click.echo(int(
|
724
|
+
click.echo(int(wf.get_EAR_skipped(ear_id)))
|
704
725
|
|
705
726
|
@workflow.command()
|
727
|
+
@_pass_workflow
|
706
728
|
@click.pass_context
|
707
729
|
@click.argument("loop_name", type=click.STRING)
|
708
730
|
@click.argument("ear_id", type=click.INT)
|
709
|
-
def check_loop(ctx, loop_name: str, ear_id: int):
|
731
|
+
def check_loop(ctx: click.Context, wf: Workflow, loop_name: str, ear_id: int):
|
710
732
|
"""Check if an iteration has met its loop's termination condition."""
|
711
733
|
app.CLI_logger.info(f"check_loop for loop {loop_name!r} and EAR ID {ear_id!r}.")
|
712
|
-
|
734
|
+
wf.check_loop_termination(loop_name, ear_id)
|
735
|
+
ctx.exit()
|
713
736
|
|
714
737
|
# TODO: in general, maybe the workflow command group can expose the simple Workflow
|
715
738
|
# properties; maybe use a decorator on the Workflow property object to signify
|
@@ -718,17 +741,17 @@ def _make_internal_CLI(app):
|
|
718
741
|
return internal
|
719
742
|
|
720
743
|
|
721
|
-
def _make_template_components_CLI(app):
|
744
|
+
def _make_template_components_CLI(app: BaseApp):
|
722
745
|
@click.command()
|
723
|
-
def tc(help=True):
|
746
|
+
def tc(help: bool = True):
|
724
747
|
"""For showing template component data."""
|
725
748
|
pprint(app.template_components)
|
726
749
|
|
727
750
|
return tc
|
728
751
|
|
729
752
|
|
730
|
-
def _make_show_CLI(app):
|
731
|
-
def show_legend_callback(ctx, param, value):
|
753
|
+
def _make_show_CLI(app: BaseApp):
|
754
|
+
def show_legend_callback(ctx: click.Context, param, value: bool):
|
732
755
|
if not value or ctx.resilient_parsing:
|
733
756
|
return
|
734
757
|
app.show_legend()
|
@@ -765,14 +788,14 @@ def _make_show_CLI(app):
|
|
765
788
|
expose_value=False,
|
766
789
|
callback=show_legend_callback,
|
767
790
|
)
|
768
|
-
def show(max_recent, full, no_update):
|
791
|
+
def show(max_recent: int, full: bool, no_update: bool):
|
769
792
|
"""Show information about running and recently active workflows."""
|
770
793
|
app.show(max_recent=max_recent, full=full, no_update=no_update)
|
771
794
|
|
772
795
|
return show
|
773
796
|
|
774
797
|
|
775
|
-
def _make_zip_CLI(app):
|
798
|
+
def _make_zip_CLI(app: BaseApp):
|
776
799
|
@click.command(name="zip")
|
777
800
|
@click.argument("workflow_ref")
|
778
801
|
@zip_path_opt
|
@@ -782,13 +805,13 @@ def _make_zip_CLI(app):
|
|
782
805
|
@zip_include_rechunk_backups_opt
|
783
806
|
@workflow_ref_type_opt
|
784
807
|
def zip_workflow(
|
785
|
-
workflow_ref,
|
786
|
-
path,
|
787
|
-
overwrite,
|
788
|
-
log,
|
789
|
-
include_execute,
|
790
|
-
include_rechunk_backups,
|
791
|
-
ref_type,
|
808
|
+
workflow_ref: str,
|
809
|
+
path: str,
|
810
|
+
overwrite: bool,
|
811
|
+
log: str | None,
|
812
|
+
include_execute: bool,
|
813
|
+
include_rechunk_backups: bool,
|
814
|
+
ref_type: str | None,
|
792
815
|
):
|
793
816
|
"""Generate a copy of the specified workflow in the zip file format in the
|
794
817
|
current working directory.
|
@@ -811,12 +834,12 @@ def _make_zip_CLI(app):
|
|
811
834
|
return zip_workflow
|
812
835
|
|
813
836
|
|
814
|
-
def _make_unzip_CLI(app):
|
837
|
+
def _make_unzip_CLI(app: BaseApp):
|
815
838
|
@click.command(name="unzip")
|
816
839
|
@click.argument("workflow_path")
|
817
840
|
@unzip_path_opt
|
818
841
|
@unzip_log_opt
|
819
|
-
def unzip_workflow(workflow_path, path, log):
|
842
|
+
def unzip_workflow(workflow_path: str, path: str, log: str | None):
|
820
843
|
"""Generate a copy of the specified zipped workflow in the submittable Zarr
|
821
844
|
format in the current working directory.
|
822
845
|
|
@@ -829,11 +852,11 @@ def _make_unzip_CLI(app):
|
|
829
852
|
return unzip_workflow
|
830
853
|
|
831
854
|
|
832
|
-
def _make_cancel_CLI(app):
|
855
|
+
def _make_cancel_CLI(app: BaseApp):
|
833
856
|
@click.command()
|
834
857
|
@click.argument("workflow_ref")
|
835
858
|
@workflow_ref_type_opt
|
836
|
-
def cancel(workflow_ref, ref_type):
|
859
|
+
def cancel(workflow_ref: str, ref_type: str | None):
|
837
860
|
"""Stop all running jobscripts of the specified workflow.
|
838
861
|
|
839
862
|
WORKFLOW_REF is the local ID (that provided by the `show` command}) or the
|
@@ -845,14 +868,20 @@ def _make_cancel_CLI(app):
|
|
845
868
|
return cancel
|
846
869
|
|
847
870
|
|
848
|
-
def _make_rechunk_CLI(app):
|
871
|
+
def _make_rechunk_CLI(app: BaseApp):
|
849
872
|
@click.command(name="rechunk")
|
850
873
|
@click.argument("workflow_ref")
|
851
874
|
@workflow_ref_type_opt
|
852
875
|
@rechunk_backup_opt
|
853
876
|
@rechunk_chunk_size_opt
|
854
877
|
@rechunk_status_opt
|
855
|
-
def rechunk(
|
878
|
+
def rechunk(
|
879
|
+
workflow_ref: str,
|
880
|
+
ref_type: str | None,
|
881
|
+
backup: bool,
|
882
|
+
chunk_size: int,
|
883
|
+
status: bool,
|
884
|
+
):
|
856
885
|
"""Rechunk metadata/runs and parameters/base arrays.
|
857
886
|
|
858
887
|
WORKFLOW_REF is the local ID (that provided by the `show` command}) or the
|
@@ -866,7 +895,7 @@ def _make_rechunk_CLI(app):
|
|
866
895
|
return rechunk
|
867
896
|
|
868
897
|
|
869
|
-
def _make_open_CLI(app):
|
898
|
+
def _make_open_CLI(app: BaseApp):
|
870
899
|
@click.group(name="open")
|
871
900
|
def open_file():
|
872
901
|
"""Open a file (for example {app_name}'s log file) using the default
|
@@ -874,9 +903,9 @@ def _make_open_CLI(app):
|
|
874
903
|
|
875
904
|
@open_file.command()
|
876
905
|
@click.option("--path", is_flag=True, default=False)
|
877
|
-
def log(path=False):
|
906
|
+
def log(path: bool = False):
|
878
907
|
"""Open the {app_name} log file."""
|
879
|
-
file_path = app.config.
|
908
|
+
file_path = app.config.log_file_path
|
880
909
|
if path:
|
881
910
|
click.echo(file_path)
|
882
911
|
else:
|
@@ -884,9 +913,9 @@ def _make_open_CLI(app):
|
|
884
913
|
|
885
914
|
@open_file.command()
|
886
915
|
@click.option("--path", is_flag=True, default=False)
|
887
|
-
def config(path=False):
|
916
|
+
def config(path: bool = False):
|
888
917
|
"""Open the {app_name} config file, or retrieve it's path."""
|
889
|
-
file_path = app.config.
|
918
|
+
file_path = app.config.config_file_path
|
890
919
|
if path:
|
891
920
|
click.echo(file_path)
|
892
921
|
else:
|
@@ -895,34 +924,30 @@ def _make_open_CLI(app):
|
|
895
924
|
@open_file.command()
|
896
925
|
@click.option("--name")
|
897
926
|
@click.option("--path", is_flag=True, default=False)
|
898
|
-
def env_source(name=None, path=False):
|
927
|
+
def env_source(name: str | None = None, path: bool = False):
|
899
928
|
"""Open a named environment sources file, or the first one."""
|
900
|
-
sources
|
901
|
-
if not sources:
|
929
|
+
if not (sources := app.config.environment_sources):
|
902
930
|
raise ValueError("No environment sources specified in the config file.")
|
903
|
-
file_paths = []
|
904
931
|
if not name:
|
905
932
|
file_paths = [sources[0]]
|
906
933
|
else:
|
907
|
-
for
|
908
|
-
if i.name == name:
|
909
|
-
file_paths.append(i)
|
934
|
+
file_paths = [pth for pth in sources if pth.name == name]
|
910
935
|
if not file_paths:
|
911
936
|
raise ValueError(
|
912
937
|
f"No environment source named {name!r} could be found; available "
|
913
|
-
f"environment source files have names: {[
|
938
|
+
f"environment source files have names: {[pth.name for pth in sources]!r}"
|
914
939
|
)
|
915
940
|
|
916
941
|
assert len(file_paths) < 5 # don't open a stupid number of files
|
917
|
-
for
|
942
|
+
for pth in file_paths:
|
918
943
|
if path:
|
919
|
-
click.echo(
|
944
|
+
click.echo(pth)
|
920
945
|
else:
|
921
|
-
utils.open_file(
|
946
|
+
utils.open_file(pth)
|
922
947
|
|
923
948
|
@open_file.command()
|
924
949
|
@click.option("--path", is_flag=True, default=False)
|
925
|
-
def known_subs(path=False):
|
950
|
+
def known_subs(path: bool = False):
|
926
951
|
"""Open the known-submissions text file."""
|
927
952
|
file_path = app.known_subs_file_path
|
928
953
|
if path:
|
@@ -934,7 +959,7 @@ def _make_open_CLI(app):
|
|
934
959
|
@click.argument("workflow_ref")
|
935
960
|
@click.option("--path", is_flag=True, default=False)
|
936
961
|
@workflow_ref_type_opt
|
937
|
-
def workflow(workflow_ref, ref_type, path=False):
|
962
|
+
def workflow(workflow_ref: str, ref_type: str | None, path: bool = False):
|
938
963
|
"""Open a workflow directory using, for example, File Explorer on Windows."""
|
939
964
|
workflow_path = app._resolve_workflow_reference(workflow_ref, ref_type)
|
940
965
|
if path:
|
@@ -944,7 +969,7 @@ def _make_open_CLI(app):
|
|
944
969
|
|
945
970
|
@open_file.command()
|
946
971
|
@click.option("--path", is_flag=True, default=False)
|
947
|
-
def user_data_dir(path=False):
|
972
|
+
def user_data_dir(path: bool = False):
|
948
973
|
dir_path = app._ensure_user_data_dir()
|
949
974
|
if path:
|
950
975
|
click.echo(dir_path)
|
@@ -953,7 +978,7 @@ def _make_open_CLI(app):
|
|
953
978
|
|
954
979
|
@open_file.command()
|
955
980
|
@click.option("--path", is_flag=True, default=False)
|
956
|
-
def user_cache_dir(path=False):
|
981
|
+
def user_cache_dir(path: bool = False):
|
957
982
|
dir_path = app._ensure_user_cache_dir()
|
958
983
|
if path:
|
959
984
|
click.echo(dir_path)
|
@@ -962,7 +987,7 @@ def _make_open_CLI(app):
|
|
962
987
|
|
963
988
|
@open_file.command()
|
964
989
|
@click.option("--path", is_flag=True, default=False)
|
965
|
-
def user_runtime_dir(path=False):
|
990
|
+
def user_runtime_dir(path: bool = False):
|
966
991
|
dir_path = app._ensure_user_runtime_dir()
|
967
992
|
if path:
|
968
993
|
click.echo(dir_path)
|
@@ -971,7 +996,7 @@ def _make_open_CLI(app):
|
|
971
996
|
|
972
997
|
@open_file.command()
|
973
998
|
@click.option("--path", is_flag=True, default=False)
|
974
|
-
def user_data_hostname_dir(path=False):
|
999
|
+
def user_data_hostname_dir(path: bool = False):
|
975
1000
|
dir_path = app._ensure_user_data_hostname_dir()
|
976
1001
|
if path:
|
977
1002
|
click.echo(dir_path)
|
@@ -980,7 +1005,7 @@ def _make_open_CLI(app):
|
|
980
1005
|
|
981
1006
|
@open_file.command()
|
982
1007
|
@click.option("--path", is_flag=True, default=False)
|
983
|
-
def user_cache_hostname_dir(path=False):
|
1008
|
+
def user_cache_hostname_dir(path: bool = False):
|
984
1009
|
dir_path = app._ensure_user_cache_hostname_dir()
|
985
1010
|
if path:
|
986
1011
|
click.echo(dir_path)
|
@@ -989,32 +1014,31 @@ def _make_open_CLI(app):
|
|
989
1014
|
|
990
1015
|
@open_file.command()
|
991
1016
|
@click.option("--path", is_flag=True, default=False)
|
992
|
-
def demo_data_cache_dir(path=False):
|
1017
|
+
def demo_data_cache_dir(path: bool = False):
|
993
1018
|
dir_path = app._ensure_demo_data_cache_dir()
|
994
1019
|
if path:
|
995
1020
|
click.echo(dir_path)
|
996
1021
|
else:
|
997
1022
|
utils.open_file(dir_path)
|
998
1023
|
|
999
|
-
open_file
|
1000
|
-
log
|
1001
|
-
config
|
1002
|
-
|
1024
|
+
_set_help_name(open_file, app)
|
1025
|
+
_set_help_name(log, app)
|
1026
|
+
_set_help_name(config, app)
|
1003
1027
|
return open_file
|
1004
1028
|
|
1005
1029
|
|
1006
|
-
def _make_demo_data_CLI(app):
|
1030
|
+
def _make_demo_data_CLI(app: BaseApp):
|
1007
1031
|
"""Generate the CLI for interacting with example data files that are used in demo
|
1008
1032
|
workflows."""
|
1009
1033
|
|
1010
|
-
def list_callback(ctx, param, value):
|
1034
|
+
def list_callback(ctx: click.Context, param, value: bool):
|
1011
1035
|
if not value or ctx.resilient_parsing:
|
1012
1036
|
return
|
1013
1037
|
# TODO: format with Rich with a one-line description
|
1014
1038
|
click.echo("\n".join(app.list_demo_data_files()))
|
1015
1039
|
ctx.exit()
|
1016
1040
|
|
1017
|
-
def cache_all_callback(ctx, param, value):
|
1041
|
+
def cache_all_callback(ctx: click.Context, param, value: bool):
|
1018
1042
|
if not value or ctx.resilient_parsing:
|
1019
1043
|
return
|
1020
1044
|
app.cache_all_demo_data_files()
|
@@ -1036,7 +1060,7 @@ def _make_demo_data_CLI(app):
|
|
1036
1060
|
@demo_data.command("copy")
|
1037
1061
|
@click.argument("file_name")
|
1038
1062
|
@click.argument("destination")
|
1039
|
-
def copy_demo_data(file_name, destination):
|
1063
|
+
def copy_demo_data(file_name: str, destination: str):
|
1040
1064
|
"""Copy a demo data file to the specified location."""
|
1041
1065
|
app.copy_demo_data(file_name=file_name, dst=destination)
|
1042
1066
|
|
@@ -1050,14 +1074,14 @@ def _make_demo_data_CLI(app):
|
|
1050
1074
|
callback=cache_all_callback,
|
1051
1075
|
)
|
1052
1076
|
@click.argument("file_name")
|
1053
|
-
def cache_demo_data(file_name):
|
1077
|
+
def cache_demo_data(file_name: str):
|
1054
1078
|
"""Ensure a demo data file is in the demo data cache."""
|
1055
1079
|
app.cache_demo_data_file(file_name)
|
1056
1080
|
|
1057
1081
|
return demo_data
|
1058
1082
|
|
1059
1083
|
|
1060
|
-
def _make_manage_CLI(app):
|
1084
|
+
def _make_manage_CLI(app: BaseApp):
|
1061
1085
|
"""Generate the CLI for infrequent app management tasks."""
|
1062
1086
|
|
1063
1087
|
@click.group()
|
@@ -1074,7 +1098,7 @@ def _make_manage_CLI(app):
|
|
1074
1098
|
"--config-dir",
|
1075
1099
|
help="The directory containing the config file to be reset.",
|
1076
1100
|
)
|
1077
|
-
def reset_config(config_dir):
|
1101
|
+
def reset_config(config_dir: str):
|
1078
1102
|
"""Reset the configuration file to defaults.
|
1079
1103
|
|
1080
1104
|
This can be used if the current configuration file is invalid."""
|
@@ -1085,7 +1109,7 @@ def _make_manage_CLI(app):
|
|
1085
1109
|
"--config-dir",
|
1086
1110
|
help="The directory containing the config file whose path is to be returned.",
|
1087
1111
|
)
|
1088
|
-
def get_config_path(config_dir):
|
1112
|
+
def get_config_path(config_dir: str):
|
1089
1113
|
"""Print the config file path without loading the config.
|
1090
1114
|
|
1091
1115
|
This can be used instead of `{app_name} open config --path` if the config file
|
@@ -1106,7 +1130,7 @@ def _make_manage_CLI(app):
|
|
1106
1130
|
|
1107
1131
|
@manage.command("clear-cache")
|
1108
1132
|
@click.option("--hostname", is_flag=True, default=False)
|
1109
|
-
def clear_cache(hostname):
|
1133
|
+
def clear_cache(hostname: bool):
|
1110
1134
|
"""Delete the app cache directory."""
|
1111
1135
|
if hostname:
|
1112
1136
|
app.clear_user_cache_hostname_dir()
|
@@ -1121,12 +1145,12 @@ def _make_manage_CLI(app):
|
|
1121
1145
|
return manage
|
1122
1146
|
|
1123
1147
|
|
1124
|
-
def make_cli(app):
|
1148
|
+
def make_cli(app: BaseApp):
|
1125
1149
|
"""Generate the root CLI for the app."""
|
1126
1150
|
|
1127
1151
|
colorama_init(autoreset=True)
|
1128
1152
|
|
1129
|
-
def run_time_info_callback(ctx, param, value):
|
1153
|
+
def run_time_info_callback(ctx: click.Context, param, value: bool):
|
1130
1154
|
app.run_time_info.from_CLI = True
|
1131
1155
|
if not value or ctx.resilient_parsing:
|
1132
1156
|
return
|
@@ -1181,7 +1205,9 @@ def make_cli(app):
|
|
1181
1205
|
),
|
1182
1206
|
)
|
1183
1207
|
@click.pass_context
|
1184
|
-
def new_CLI(
|
1208
|
+
def new_CLI(
|
1209
|
+
ctx: click.Context, config_dir, config_key, with_config, timeit, timeit_file
|
1210
|
+
):
|
1185
1211
|
app.run_time_info.from_CLI = True
|
1186
1212
|
TimeIt.active = timeit or timeit_file
|
1187
1213
|
TimeIt.file_path = timeit_file
|
@@ -1208,7 +1234,12 @@ def make_cli(app):
|
|
1208
1234
|
@click.option("--use-current-env", is_flag=True, default=False)
|
1209
1235
|
@click.option("--setup", type=click.STRING)
|
1210
1236
|
@click.option("--env-source-file", type=click.STRING)
|
1211
|
-
def configure_env(
|
1237
|
+
def configure_env(
|
1238
|
+
name: str,
|
1239
|
+
use_current_env: bool,
|
1240
|
+
setup: list[str] | None = None,
|
1241
|
+
env_source_file: str | None = None,
|
1242
|
+
):
|
1212
1243
|
"""Configure an app environment, using, for example, the currently activated
|
1213
1244
|
Python environment."""
|
1214
1245
|
app.configure_env(
|
@@ -1216,7 +1247,7 @@ def make_cli(app):
|
|
1216
1247
|
setup=setup,
|
1217
1248
|
executables=None,
|
1218
1249
|
use_current_env=use_current_env,
|
1219
|
-
env_source_file=env_source_file,
|
1250
|
+
env_source_file=None if env_source_file is None else Path(env_source_file),
|
1220
1251
|
)
|
1221
1252
|
|
1222
1253
|
new_CLI.__doc__ = app.description
|