cmem-cmemc 24.2.0rc1__py3-none-any.whl → 24.3.0rc1__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.
- cmem_cmemc/__init__.py +7 -12
- cmem_cmemc/command.py +20 -0
- cmem_cmemc/command_group.py +70 -0
- cmem_cmemc/commands/__init__.py +0 -81
- cmem_cmemc/commands/acl.py +118 -62
- cmem_cmemc/commands/admin.py +46 -35
- cmem_cmemc/commands/client.py +2 -1
- cmem_cmemc/commands/config.py +3 -1
- cmem_cmemc/commands/dataset.py +27 -24
- cmem_cmemc/commands/graph.py +100 -16
- cmem_cmemc/commands/metrics.py +195 -79
- cmem_cmemc/commands/migration.py +265 -0
- cmem_cmemc/commands/project.py +62 -17
- cmem_cmemc/commands/python.py +57 -26
- cmem_cmemc/commands/query.py +23 -14
- cmem_cmemc/commands/resource.py +10 -2
- cmem_cmemc/commands/scheduler.py +10 -2
- cmem_cmemc/commands/store.py +118 -14
- cmem_cmemc/commands/user.py +8 -2
- cmem_cmemc/commands/validation.py +304 -113
- cmem_cmemc/commands/variable.py +10 -2
- cmem_cmemc/commands/vocabulary.py +48 -29
- cmem_cmemc/commands/workflow.py +86 -59
- cmem_cmemc/commands/workspace.py +27 -8
- cmem_cmemc/completion.py +185 -141
- cmem_cmemc/constants.py +2 -0
- cmem_cmemc/context.py +88 -42
- cmem_cmemc/manual_helper/graph.py +1 -0
- cmem_cmemc/manual_helper/multi_page.py +3 -1
- cmem_cmemc/migrations/__init__.py +1 -0
- cmem_cmemc/migrations/abc.py +84 -0
- cmem_cmemc/migrations/access_conditions_243.py +118 -0
- cmem_cmemc/migrations/bootstrap_data.py +30 -0
- cmem_cmemc/migrations/shapes_widget_integrations_243.py +194 -0
- cmem_cmemc/migrations/workspace_configurations.py +28 -0
- cmem_cmemc/object_list.py +53 -22
- cmem_cmemc/parameter_types/__init__.py +1 -0
- cmem_cmemc/parameter_types/path.py +69 -0
- cmem_cmemc/smart_path/__init__.py +94 -0
- cmem_cmemc/smart_path/clients/__init__.py +63 -0
- cmem_cmemc/smart_path/clients/http.py +65 -0
- cmem_cmemc/string_processor.py +77 -0
- cmem_cmemc/title_helper.py +41 -0
- cmem_cmemc/utils.py +114 -47
- {cmem_cmemc-24.2.0rc1.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/LICENSE +1 -1
- cmem_cmemc-24.3.0rc1.dist-info/METADATA +89 -0
- cmem_cmemc-24.3.0rc1.dist-info/RECORD +53 -0
- {cmem_cmemc-24.2.0rc1.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/WHEEL +1 -1
- cmem_cmemc-24.2.0rc1.dist-info/METADATA +0 -69
- cmem_cmemc-24.2.0rc1.dist-info/RECORD +0 -37
- {cmem_cmemc-24.2.0rc1.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/entry_points.txt +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""vocabularies commands for cmem command line interface."""
|
|
2
|
+
|
|
2
3
|
import io
|
|
3
|
-
from datetime import
|
|
4
|
+
from datetime import datetime, timezone
|
|
4
5
|
from re import match
|
|
5
6
|
from urllib.parse import urlparse
|
|
6
7
|
|
|
@@ -21,8 +22,10 @@ from rdflib.plugins.parsers.notation3 import BadSyntax
|
|
|
21
22
|
from six.moves.urllib.parse import quote
|
|
22
23
|
|
|
23
24
|
from cmem_cmemc import completion
|
|
24
|
-
from cmem_cmemc.
|
|
25
|
+
from cmem_cmemc.command import CmemcCommand
|
|
26
|
+
from cmem_cmemc.command_group import CmemcGroup
|
|
25
27
|
from cmem_cmemc.context import ApplicationContext
|
|
28
|
+
from cmem_cmemc.parameter_types.path import ClickSmartPath
|
|
26
29
|
|
|
27
30
|
GET_ONTOLOGY_IRI_QUERY = """
|
|
28
31
|
PREFIX owl: <http://www.w3.org/2002/07/owl#>
|
|
@@ -71,22 +74,29 @@ def _validate_vocabs_to_process(iris: tuple[str], filter_: str, all_flag: bool)
|
|
|
71
74
|
list is without duplicates, and validated if they exist
|
|
72
75
|
"""
|
|
73
76
|
if iris == () and not all_flag:
|
|
74
|
-
raise
|
|
77
|
+
raise click.UsageError(
|
|
75
78
|
"Either specify at least one vocabulary IRI "
|
|
76
79
|
"or use the --all option to process over all vocabularies."
|
|
77
80
|
)
|
|
78
|
-
|
|
79
|
-
all_vocabs = [_["iri"] for _ in get_vocabularies(filter_=filter_)]
|
|
81
|
+
all_vocabs = {_["iri"]: _ for _ in get_vocabularies()}
|
|
80
82
|
if all_flag:
|
|
81
|
-
# in case --all is given, all vocabs are processed
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
83
|
+
# in case --all is given, all installable / installed vocabs are processed
|
|
84
|
+
if filter_ == "installed": # uninstall command
|
|
85
|
+
return [_ for _ in all_vocabs if all_vocabs[_]["installed"]]
|
|
86
|
+
# install command
|
|
87
|
+
return [_ for _ in all_vocabs if not all_vocabs[_]["installed"]]
|
|
88
|
+
|
|
89
|
+
vocabs_to_process = list(set(iris)) # avoid double removal / installation
|
|
90
|
+
# test if one of the vocabs does not exist or is already installed / not installed
|
|
87
91
|
for _ in vocabs_to_process:
|
|
88
|
-
|
|
89
|
-
|
|
92
|
+
# uninstall command
|
|
93
|
+
if filter_ == "installed" and (_ not in all_vocabs or not all_vocabs[_]["installed"]):
|
|
94
|
+
raise click.UsageError(f"Vocabulary {_} not installed.")
|
|
95
|
+
if filter_ == "installable": # install command
|
|
96
|
+
if _ not in all_vocabs:
|
|
97
|
+
raise click.UsageError(f"Vocabulary {_} does not exist.")
|
|
98
|
+
if all_vocabs[_]["installed"]:
|
|
99
|
+
raise click.UsageError(f"Vocabulary {_} already installed.")
|
|
90
100
|
return vocabs_to_process
|
|
91
101
|
|
|
92
102
|
|
|
@@ -140,7 +150,7 @@ def _insert_catalog_entry(iri: str, prefix: str, namespace: str, label: str, lan
|
|
|
140
150
|
iri=iri,
|
|
141
151
|
prefix=prefix,
|
|
142
152
|
namespace=namespace,
|
|
143
|
-
date=datetime.now(tz=
|
|
153
|
+
date=datetime.now(tz=timezone.utc).date(),
|
|
144
154
|
label=label,
|
|
145
155
|
language=language,
|
|
146
156
|
description="vocabulary imported with cmemc",
|
|
@@ -150,7 +160,7 @@ def _insert_catalog_entry(iri: str, prefix: str, namespace: str, label: str, lan
|
|
|
150
160
|
|
|
151
161
|
|
|
152
162
|
def _get_vocabulary_metadata_from_file(
|
|
153
|
-
file: io.
|
|
163
|
+
file: io.BytesIO, namespace_given: bool = False
|
|
154
164
|
) -> dict[str, str]:
|
|
155
165
|
"""Get potential graph iri and prefix/namespace from a turtle file."""
|
|
156
166
|
metadata = {"iri": "", "prefix": "", "namespace": ""}
|
|
@@ -263,7 +273,13 @@ def list_command(app: ApplicationContext, id_only: bool, filter_: str, raw: bool
|
|
|
263
273
|
except (KeyError, TypeError):
|
|
264
274
|
label = _["vocabularyLabel"] if _["vocabularyLabel"] else "[no label given]"
|
|
265
275
|
table.append((iri, label))
|
|
266
|
-
app.echo_info_table(
|
|
276
|
+
app.echo_info_table(
|
|
277
|
+
table,
|
|
278
|
+
headers=["Vocabulary Graph IRI", "Label"],
|
|
279
|
+
sort_column=1,
|
|
280
|
+
empty_table_message="No installed vocabularies found. "
|
|
281
|
+
"Use the `vocabulary install` command to install vocabulary from the catalog.",
|
|
282
|
+
)
|
|
267
283
|
|
|
268
284
|
|
|
269
285
|
@click.command(cls=CmemcCommand, name="install")
|
|
@@ -315,10 +331,7 @@ def uninstall_command(app: ApplicationContext, iris: tuple[str], all_: bool) ->
|
|
|
315
331
|
"FILE",
|
|
316
332
|
required=True,
|
|
317
333
|
shell_complete=completion.triple_files,
|
|
318
|
-
type=
|
|
319
|
-
allow_dash=True,
|
|
320
|
-
readable=True,
|
|
321
|
-
),
|
|
334
|
+
type=ClickSmartPath(allow_dash=True, readable=True, remote_okay=True),
|
|
322
335
|
)
|
|
323
336
|
@click.option(
|
|
324
337
|
"--namespace",
|
|
@@ -345,19 +358,19 @@ def import_command(
|
|
|
345
358
|
description which correctly uses the `vann:preferredNamespacePrefix` and
|
|
346
359
|
`vann:preferredNamespaceUri` properties.
|
|
347
360
|
"""
|
|
348
|
-
|
|
349
|
-
with
|
|
350
|
-
|
|
351
|
-
|
|
361
|
+
_buffer = io.BytesIO()
|
|
362
|
+
with ClickSmartPath.open(file) as file_handle:
|
|
363
|
+
_buffer.write(file_handle.read())
|
|
364
|
+
_buffer.seek(0)
|
|
352
365
|
|
|
353
366
|
# fetch metadata
|
|
354
367
|
if namespace != (None, None):
|
|
355
368
|
_validate_namespace(app, namespace)
|
|
356
|
-
meta_data = _get_vocabulary_metadata_from_file(
|
|
369
|
+
meta_data = _get_vocabulary_metadata_from_file(_buffer, True)
|
|
357
370
|
meta_data["prefix"] = namespace[0] # type: ignore[assignment]
|
|
358
371
|
meta_data["namespace"] = namespace[1] # type: ignore[assignment]
|
|
359
372
|
else:
|
|
360
|
-
meta_data = _get_vocabulary_metadata_from_file(
|
|
373
|
+
meta_data = _get_vocabulary_metadata_from_file(_buffer, False)
|
|
361
374
|
iri = meta_data["iri"]
|
|
362
375
|
|
|
363
376
|
success_message = "done"
|
|
@@ -368,8 +381,8 @@ def import_command(
|
|
|
368
381
|
raise ValueError(f"Proposed graph {iri} does already exist.")
|
|
369
382
|
app.echo_info(f"Import {file} as vocabulary to {iri} ... ", nl=False)
|
|
370
383
|
# upload graph
|
|
371
|
-
|
|
372
|
-
graph_api.post_streamed(iri,
|
|
384
|
+
_buffer.seek(0)
|
|
385
|
+
graph_api.post_streamed(iri, _buffer, replace=True)
|
|
373
386
|
|
|
374
387
|
# resolve label
|
|
375
388
|
resolved_label_object: dict = resolve([iri], graph=iri)[iri]
|
|
@@ -438,7 +451,13 @@ def cache_list_command(app: ApplicationContext, id_only: bool, raw: bool) -> Non
|
|
|
438
451
|
for vocab in cache_["vocabularies"]:
|
|
439
452
|
table = _transform_cache_to_table(vocab["classes"], table)
|
|
440
453
|
table = _transform_cache_to_table(vocab["properties"], table)
|
|
441
|
-
app.echo_info_table(
|
|
454
|
+
app.echo_info_table(
|
|
455
|
+
table,
|
|
456
|
+
headers=["IRI", "Type", "Label"],
|
|
457
|
+
sort_column=0,
|
|
458
|
+
empty_table_message="No cache entries found. "
|
|
459
|
+
"Use the `vocabulary install` command to install a vocabulary.",
|
|
460
|
+
)
|
|
442
461
|
|
|
443
462
|
|
|
444
463
|
@click.group(cls=CmemcGroup)
|
cmem_cmemc/commands/workflow.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
"""workflow commands for cmem command line interface."""
|
|
2
|
+
|
|
2
3
|
import re
|
|
3
4
|
import sys
|
|
4
5
|
import time
|
|
5
|
-
from datetime import
|
|
6
|
-
from pathlib import Path
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
7
|
|
|
8
8
|
import click
|
|
9
9
|
import timeago
|
|
10
10
|
from click import UsageError
|
|
11
|
-
from cmem.cmempy.workflow import
|
|
11
|
+
from cmem.cmempy.workflow import get_workflows
|
|
12
12
|
from cmem.cmempy.workflow.workflow import (
|
|
13
13
|
execute_workflow_io,
|
|
14
14
|
get_workflow_editor_uri,
|
|
@@ -26,9 +26,12 @@ from requests import Response
|
|
|
26
26
|
from requests.status_codes import codes
|
|
27
27
|
|
|
28
28
|
from cmem_cmemc import completion
|
|
29
|
-
from cmem_cmemc.
|
|
29
|
+
from cmem_cmemc.command import CmemcCommand
|
|
30
|
+
from cmem_cmemc.command_group import CmemcGroup
|
|
30
31
|
from cmem_cmemc.commands.scheduler import scheduler
|
|
31
32
|
from cmem_cmemc.context import ApplicationContext
|
|
33
|
+
from cmem_cmemc.parameter_types.path import ClickSmartPath
|
|
34
|
+
from cmem_cmemc.smart_path import SmartPath as Path
|
|
32
35
|
|
|
33
36
|
WORKFLOW_FILTER_TYPES = sorted(["project", "regex", "tag", "io"])
|
|
34
37
|
WORKFLOW_LIST_FILTER_HELP_TEXT = (
|
|
@@ -40,40 +43,41 @@ WORKFLOW_LIST_FILTER_HELP_TEXT = (
|
|
|
40
43
|
IO_WARNING_NO_RESULT = "The workflow was executed but produced no result."
|
|
41
44
|
IO_WARNING_NO_OUTPUT_DEFINED = "The workflow was executed, a result was " "received but dropped."
|
|
42
45
|
|
|
43
|
-
MIME_CSV = "application/x-plugin-csv"
|
|
44
|
-
MIME_XLS = "application/x-plugin-excel"
|
|
45
|
-
MIME_NT = "application/n-triples"
|
|
46
|
-
MIME_JSON = "application/x-plugin-json"
|
|
47
|
-
MIME_XML = "application/xml"
|
|
48
|
-
MIME_FILE = "application/octet-stream"
|
|
49
|
-
MIME_ZIP = "application/x-plugin-multiCsv"
|
|
50
|
-
MIME_ALIGNMENT = "text/alignment"
|
|
51
|
-
MIME_TEXT = "text/plain"
|
|
52
|
-
|
|
53
|
-
VALID_OUTPUT_EXTENSIONS = {
|
|
54
|
-
".csv": MIME_CSV,
|
|
55
|
-
".xlsx": MIME_XLS,
|
|
56
|
-
".nt": MIME_NT,
|
|
57
|
-
".ttl": MIME_NT,
|
|
58
|
-
".json": MIME_JSON,
|
|
59
|
-
".xml": MIME_XML,
|
|
60
|
-
}
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
".
|
|
64
|
-
".
|
|
65
|
-
".
|
|
66
|
-
".
|
|
67
|
-
".
|
|
68
|
-
".
|
|
69
|
-
".
|
|
47
|
+
FILE_EXTENSIONS_TO_PLUGIN_ID = {
|
|
48
|
+
".nt": "file",
|
|
49
|
+
".ttl": "file",
|
|
50
|
+
".csv": "csv",
|
|
51
|
+
".json": "json",
|
|
52
|
+
".xml": "xml",
|
|
53
|
+
".txt": "text",
|
|
54
|
+
".xlsx": "excel",
|
|
55
|
+
".zip": "multiCsv",
|
|
70
56
|
}
|
|
71
57
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
58
|
+
# Derive valid extensions from FILE_EXTENSIONS_TO_PLUGIN_ID keys
|
|
59
|
+
VALID_EXTENSIONS = list(FILE_EXTENSIONS_TO_PLUGIN_ID.keys())
|
|
60
|
+
PLUGIN_MIME_TYPES = [f"application/x-plugin-{_}" for _ in FILE_EXTENSIONS_TO_PLUGIN_ID.values()]
|
|
61
|
+
# Define additional mime types for input and output
|
|
62
|
+
EXTRA_INPUT_MIME_TYPES = [
|
|
63
|
+
"application/json",
|
|
64
|
+
"application/xml",
|
|
65
|
+
"text/csv",
|
|
66
|
+
]
|
|
67
|
+
|
|
68
|
+
EXTRA_OUTPUT_MIME_TYPES = [
|
|
69
|
+
"application/json",
|
|
70
|
+
"application/xml",
|
|
71
|
+
"application/n-triples",
|
|
72
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
73
|
+
"text/csv",
|
|
74
|
+
]
|
|
75
|
+
|
|
76
|
+
STDOUT_UNSUPPORTED_MIME_TYPES = {
|
|
77
|
+
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "excel",
|
|
78
|
+
"application/x-plugin-excel": "excel",
|
|
79
|
+
"application/x-plugin-multiCsv": "ZIP",
|
|
80
|
+
}
|
|
77
81
|
|
|
78
82
|
|
|
79
83
|
def _get_workflow_tag_labels(workflow_: dict) -> list:
|
|
@@ -185,9 +189,10 @@ def _io_check_request(info: dict, input_file: str, output_file: str, output_mime
|
|
|
185
189
|
"This workflow has a defined output so you need to use the '-o' "
|
|
186
190
|
"parameter to retrieve data from it."
|
|
187
191
|
)
|
|
188
|
-
if output_mimetype
|
|
192
|
+
if output_mimetype in STDOUT_UNSUPPORTED_MIME_TYPES and output_file == "-":
|
|
189
193
|
raise ValueError(
|
|
190
|
-
"Trying to output an
|
|
194
|
+
f"Trying to output an {STDOUT_UNSUPPORTED_MIME_TYPES[output_mimetype]} "
|
|
195
|
+
"file to stdout will fail.\n"
|
|
191
196
|
"Please output to a regular file instead "
|
|
192
197
|
"(workflow was not executed)."
|
|
193
198
|
)
|
|
@@ -226,11 +231,9 @@ def _io_guess_output(output_file: str) -> str:
|
|
|
226
231
|
if output_file == "-":
|
|
227
232
|
raise ValueError("Output mime-type not guessable, please use the --output-mimetype option.")
|
|
228
233
|
file_extension = Path(output_file).suffix
|
|
229
|
-
if file_extension in
|
|
230
|
-
|
|
231
|
-
)
|
|
232
|
-
return VALID_OUTPUT_EXTENSIONS[file_extension]
|
|
233
|
-
valid_extensions = ", ".join(VALID_OUTPUT_EXTENSIONS.keys())
|
|
234
|
+
if file_extension in VALID_EXTENSIONS:
|
|
235
|
+
return f"application/x-plugin-{FILE_EXTENSIONS_TO_PLUGIN_ID[file_extension]}"
|
|
236
|
+
valid_extensions = ", ".join(VALID_EXTENSIONS)
|
|
234
237
|
raise ValueError(
|
|
235
238
|
f"Files with the extension {file_extension} can not be generated. "
|
|
236
239
|
f"Try one of {valid_extensions}"
|
|
@@ -242,11 +245,9 @@ def _io_guess_input(input_file: str) -> str:
|
|
|
242
245
|
if input_file == "-":
|
|
243
246
|
raise ValueError("Input mime-type not guessable, please use the --output-mimetype option.")
|
|
244
247
|
file_extension = Path(input_file).suffix
|
|
245
|
-
if file_extension in
|
|
246
|
-
|
|
247
|
-
)
|
|
248
|
-
return VALID_INPUT_EXTENSIONS[file_extension]
|
|
249
|
-
valid_extensions = ", ".join(VALID_INPUT_EXTENSIONS.keys())
|
|
248
|
+
if file_extension in VALID_EXTENSIONS:
|
|
249
|
+
return f"application/x-plugin-{FILE_EXTENSIONS_TO_PLUGIN_ID[file_extension]}"
|
|
250
|
+
valid_extensions = ", ".join(VALID_EXTENSIONS)
|
|
250
251
|
raise ValueError(
|
|
251
252
|
f"Files with the extension {file_extension} can not be processed. "
|
|
252
253
|
f"Try one of {valid_extensions}"
|
|
@@ -319,8 +320,8 @@ def _workflow_echo_status(app: ApplicationContext, status: dict) -> None:
|
|
|
319
320
|
canceled only exists sometimes
|
|
320
321
|
"""
|
|
321
322
|
# prepare human friendly relative time
|
|
322
|
-
now = datetime.now(tz=
|
|
323
|
-
stamp = datetime.fromtimestamp(status["lastUpdateTime"] / 1000, tz=
|
|
323
|
+
now = datetime.now(tz=timezone.utc)
|
|
324
|
+
stamp = datetime.fromtimestamp(status["lastUpdateTime"] / 1000, tz=timezone.utc)
|
|
324
325
|
time_ago = timeago.format(stamp, now, "en")
|
|
325
326
|
status_name = status["statusName"]
|
|
326
327
|
status_message = status["message"]
|
|
@@ -338,9 +339,9 @@ def _workflow_echo_status(app: ApplicationContext, status: dict) -> None:
|
|
|
338
339
|
f"statusName is {status_name}, expecting one of: " "Running, Canceling or Waiting."
|
|
339
340
|
)
|
|
340
341
|
# not running can be Idle or Finished
|
|
341
|
-
if
|
|
342
|
+
if status.get("failed"):
|
|
342
343
|
app.echo_error(message, nl=True, err=False)
|
|
343
|
-
elif
|
|
344
|
+
elif status.get("cancelled"):
|
|
344
345
|
app.echo_warning(message)
|
|
345
346
|
elif status["statusName"] == "Idle":
|
|
346
347
|
app.echo_info(message)
|
|
@@ -440,7 +441,7 @@ def execute_command( # noqa: PLR0913
|
|
|
440
441
|
"--input",
|
|
441
442
|
"-i",
|
|
442
443
|
"input_file",
|
|
443
|
-
type=
|
|
444
|
+
type=ClickSmartPath(allow_dash=False, dir_okay=False, readable=True),
|
|
444
445
|
shell_complete=completion.workflow_io_input_files,
|
|
445
446
|
help="From which file the input is taken. If the workflow "
|
|
446
447
|
"has no defined variable input dataset, this option is not allowed.",
|
|
@@ -449,7 +450,7 @@ def execute_command( # noqa: PLR0913
|
|
|
449
450
|
"--output",
|
|
450
451
|
"-o",
|
|
451
452
|
"output_file",
|
|
452
|
-
type=
|
|
453
|
+
type=ClickSmartPath(
|
|
453
454
|
allow_dash=False,
|
|
454
455
|
dir_okay=False,
|
|
455
456
|
writable=True,
|
|
@@ -465,7 +466,13 @@ def execute_command( # noqa: PLR0913
|
|
|
465
466
|
help="Which input format should be processed: If not given, cmemc will "
|
|
466
467
|
"try to guess the mime type based on the file extension or will "
|
|
467
468
|
"fail.",
|
|
468
|
-
type=click.Choice(
|
|
469
|
+
type=click.Choice(
|
|
470
|
+
[
|
|
471
|
+
*PLUGIN_MIME_TYPES,
|
|
472
|
+
*EXTRA_INPUT_MIME_TYPES,
|
|
473
|
+
"guess",
|
|
474
|
+
]
|
|
475
|
+
),
|
|
469
476
|
default="guess",
|
|
470
477
|
)
|
|
471
478
|
@click.option(
|
|
@@ -474,7 +481,13 @@ def execute_command( # noqa: PLR0913
|
|
|
474
481
|
"try to guess the mime type based on the file extension or will "
|
|
475
482
|
"fail. In case of an output to stdout, a default mime type "
|
|
476
483
|
"will be used (JSON).",
|
|
477
|
-
type=click.Choice(
|
|
484
|
+
type=click.Choice(
|
|
485
|
+
[
|
|
486
|
+
*PLUGIN_MIME_TYPES,
|
|
487
|
+
*EXTRA_OUTPUT_MIME_TYPES,
|
|
488
|
+
"guess",
|
|
489
|
+
]
|
|
490
|
+
),
|
|
478
491
|
default="guess",
|
|
479
492
|
)
|
|
480
493
|
@click.option(
|
|
@@ -498,10 +511,19 @@ def io_command( # noqa: PLR0913
|
|
|
498
511
|
) -> None:
|
|
499
512
|
"""Execute a workflow with file input/output.
|
|
500
513
|
|
|
501
|
-
With this command, you can execute a workflow that uses
|
|
514
|
+
With this command, you can execute a workflow that uses replaceable datasets
|
|
502
515
|
as input, output or for configuration. Use the input parameter to feed
|
|
503
516
|
data into the workflow. Likewise, use output for retrieval of the workflow
|
|
504
|
-
result. Workflows without a
|
|
517
|
+
result. Workflows without a replaceable dataset will throw an error.
|
|
518
|
+
|
|
519
|
+
Note: Regarding the input dataset configuration - the following rules apply:
|
|
520
|
+
If autoconfig is enabled ('--autoconfig', the default), the dataset
|
|
521
|
+
configuration is guessed.
|
|
522
|
+
If autoconfig is disabled ('--no-autoconfig') and the type of the dataset
|
|
523
|
+
file is the same as the replaceable dataset in the workflow, the configuration
|
|
524
|
+
from this dataset is copied.
|
|
525
|
+
If autoconfig is disabled and the type of the dataset file is different from the
|
|
526
|
+
replaceable dataset in the workflow, the default config is used.
|
|
505
527
|
"""
|
|
506
528
|
project_id, task_id = workflow_id.split(":")
|
|
507
529
|
if output_file and output_mimetype == "guess":
|
|
@@ -525,7 +547,6 @@ def io_command( # noqa: PLR0913
|
|
|
525
547
|
f"output_mime_type={output_mimetype}, "
|
|
526
548
|
f"auto_config={autoconfig}"
|
|
527
549
|
)
|
|
528
|
-
|
|
529
550
|
response = execute_workflow_io(
|
|
530
551
|
project_name=project_id,
|
|
531
552
|
task_name=task_id,
|
|
@@ -597,7 +618,13 @@ def list_command(
|
|
|
597
618
|
_["label"],
|
|
598
619
|
]
|
|
599
620
|
table.append(row)
|
|
600
|
-
app.echo_info_table(
|
|
621
|
+
app.echo_info_table(
|
|
622
|
+
table,
|
|
623
|
+
headers=["Workflow ID", "Label"],
|
|
624
|
+
sort_column=1,
|
|
625
|
+
empty_table_message="No workflows found. "
|
|
626
|
+
"Open a project in the web interface and create a new workflow there.",
|
|
627
|
+
)
|
|
601
628
|
|
|
602
629
|
|
|
603
630
|
@click.command(cls=CmemcCommand, name="status")
|
cmem_cmemc/commands/workspace.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""workspace commands for cmem command line interface."""
|
|
2
|
+
|
|
2
3
|
import os
|
|
3
|
-
from pathlib import Path
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
6
|
from cmem.cmempy.workspace import reload_workspace
|
|
@@ -9,9 +9,12 @@ from cmem.cmempy.workspace.import_ import import_workspace
|
|
|
9
9
|
from jinja2 import Template
|
|
10
10
|
|
|
11
11
|
from cmem_cmemc import completion
|
|
12
|
-
from cmem_cmemc.
|
|
12
|
+
from cmem_cmemc.command import CmemcCommand
|
|
13
|
+
from cmem_cmemc.command_group import CmemcGroup
|
|
13
14
|
from cmem_cmemc.commands.python import python
|
|
14
15
|
from cmem_cmemc.context import ApplicationContext
|
|
16
|
+
from cmem_cmemc.parameter_types.path import ClickSmartPath
|
|
17
|
+
from cmem_cmemc.smart_path import SmartPath as Path
|
|
15
18
|
|
|
16
19
|
|
|
17
20
|
@click.command(cls=CmemcCommand, name="export")
|
|
@@ -19,7 +22,12 @@ from cmem_cmemc.context import ApplicationContext
|
|
|
19
22
|
"-o",
|
|
20
23
|
"--overwrite",
|
|
21
24
|
is_flag=True,
|
|
22
|
-
|
|
25
|
+
hidden=True,
|
|
26
|
+
)
|
|
27
|
+
@click.option(
|
|
28
|
+
"--replace",
|
|
29
|
+
is_flag=True,
|
|
30
|
+
help="Replace existing files. This is a dangerous option, so use it with care.",
|
|
23
31
|
)
|
|
24
32
|
@click.option(
|
|
25
33
|
"--type",
|
|
@@ -49,11 +57,16 @@ from cmem_cmemc.context import ApplicationContext
|
|
|
49
57
|
"file",
|
|
50
58
|
shell_complete=completion.workspace_files,
|
|
51
59
|
required=False,
|
|
52
|
-
type=
|
|
60
|
+
type=ClickSmartPath(writable=True, allow_dash=False, dir_okay=False),
|
|
53
61
|
)
|
|
54
62
|
@click.pass_obj
|
|
55
|
-
def export_command(
|
|
56
|
-
app: ApplicationContext,
|
|
63
|
+
def export_command( # noqa: PLR0913
|
|
64
|
+
app: ApplicationContext,
|
|
65
|
+
overwrite: bool,
|
|
66
|
+
replace: bool,
|
|
67
|
+
marshalling_plugin: str,
|
|
68
|
+
template: str,
|
|
69
|
+
file: str,
|
|
57
70
|
) -> None:
|
|
58
71
|
"""Export the complete workspace (all projects) to a ZIP file.
|
|
59
72
|
|
|
@@ -64,13 +77,19 @@ def export_command(
|
|
|
64
77
|
The file name is optional and will be generated with by
|
|
65
78
|
the template if absent.
|
|
66
79
|
"""
|
|
80
|
+
if overwrite:
|
|
81
|
+
replace = overwrite
|
|
82
|
+
app.echo_warning(
|
|
83
|
+
"The option --overwrite is deprecated and will be removed with the next major release."
|
|
84
|
+
" Please use the --replace option instead."
|
|
85
|
+
)
|
|
67
86
|
if file is None:
|
|
68
87
|
# prepare the template data and create the actual file incl. suffix
|
|
69
88
|
template_data = app.get_template_data()
|
|
70
89
|
file = Template(template).render(template_data) + ".zip"
|
|
71
90
|
file = os.path.normpath(file)
|
|
72
91
|
app.echo_info(f"Export workspace to {file} ... ", nl=False)
|
|
73
|
-
if Path(file).exists() and
|
|
92
|
+
if Path(file).exists() and replace is not True:
|
|
74
93
|
app.echo_error("file exists")
|
|
75
94
|
else:
|
|
76
95
|
# output directory is created lazy
|
|
@@ -95,7 +114,7 @@ def export_command(
|
|
|
95
114
|
@click.argument(
|
|
96
115
|
"file",
|
|
97
116
|
shell_complete=completion.workspace_files,
|
|
98
|
-
type=
|
|
117
|
+
type=ClickSmartPath(readable=True, allow_dash=False, dir_okay=False),
|
|
99
118
|
)
|
|
100
119
|
@click.pass_obj
|
|
101
120
|
def import_command(app: ApplicationContext, file: str, marshalling_plugin: str) -> None:
|