cmem-cmemc 25.6.0__py3-none-any.whl → 26.1.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/cli.py +11 -6
- cmem_cmemc/command.py +1 -1
- cmem_cmemc/command_group.py +27 -0
- cmem_cmemc/commands/acl.py +388 -20
- cmem_cmemc/commands/admin.py +10 -10
- cmem_cmemc/commands/client.py +12 -5
- cmem_cmemc/commands/config.py +106 -12
- cmem_cmemc/commands/dataset.py +162 -118
- cmem_cmemc/commands/file.py +117 -73
- cmem_cmemc/commands/graph.py +200 -72
- cmem_cmemc/commands/graph_imports.py +12 -5
- cmem_cmemc/commands/graph_insights.py +61 -25
- cmem_cmemc/commands/metrics.py +15 -9
- cmem_cmemc/commands/migration.py +12 -4
- cmem_cmemc/commands/package.py +548 -0
- cmem_cmemc/commands/project.py +155 -22
- cmem_cmemc/commands/python.py +8 -4
- cmem_cmemc/commands/query.py +119 -25
- cmem_cmemc/commands/scheduler.py +6 -4
- cmem_cmemc/commands/store.py +2 -1
- cmem_cmemc/commands/user.py +124 -24
- cmem_cmemc/commands/validation.py +15 -10
- cmem_cmemc/commands/variable.py +264 -61
- cmem_cmemc/commands/vocabulary.py +18 -13
- cmem_cmemc/commands/workflow.py +21 -11
- cmem_cmemc/completion.py +105 -105
- cmem_cmemc/context.py +38 -8
- cmem_cmemc/exceptions.py +8 -2
- cmem_cmemc/manual_helper/multi_page.py +0 -1
- cmem_cmemc/object_list.py +234 -7
- cmem_cmemc/string_processor.py +142 -5
- cmem_cmemc/title_helper.py +50 -0
- cmem_cmemc/utils.py +8 -7
- {cmem_cmemc-25.6.0.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/METADATA +6 -6
- cmem_cmemc-26.1.0rc1.dist-info/RECORD +62 -0
- {cmem_cmemc-25.6.0.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/WHEEL +1 -1
- cmem_cmemc-25.6.0.dist-info/RECORD +0 -61
- {cmem_cmemc-25.6.0.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/entry_points.txt +0 -0
- {cmem_cmemc-25.6.0.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/licenses/LICENSE +0 -0
cmem_cmemc/completion.py
CHANGED
|
@@ -4,11 +4,13 @@
|
|
|
4
4
|
import os
|
|
5
5
|
import pathlib
|
|
6
6
|
from collections import OrderedDict
|
|
7
|
+
from collections.abc import Callable
|
|
7
8
|
from contextlib import suppress
|
|
9
|
+
from functools import wraps
|
|
8
10
|
from typing import Any
|
|
9
11
|
|
|
10
12
|
import requests.exceptions
|
|
11
|
-
from click import Argument,
|
|
13
|
+
from click import Argument, Context
|
|
12
14
|
from click.shell_completion import CompletionItem, split_arg_string
|
|
13
15
|
from cmem.cmempy.dp.authorization.conditions import (
|
|
14
16
|
fetch_all_acls,
|
|
@@ -39,6 +41,7 @@ from natsort import natsorted, ns
|
|
|
39
41
|
|
|
40
42
|
from cmem_cmemc.constants import NS_ACL, NS_ACTION, NS_GROUP, NS_USER
|
|
41
43
|
from cmem_cmemc.context import ApplicationContext
|
|
44
|
+
from cmem_cmemc.exceptions import CmemcError
|
|
42
45
|
from cmem_cmemc.placeholder import QueryPlaceholder, get_placeholders_for_query
|
|
43
46
|
from cmem_cmemc.smart_path import SmartPath as Path
|
|
44
47
|
from cmem_cmemc.utils import (
|
|
@@ -53,6 +56,43 @@ SORT_BY_KEY = 0
|
|
|
53
56
|
SORT_BY_DESC = 1
|
|
54
57
|
|
|
55
58
|
|
|
59
|
+
def suppress_completion_errors(
|
|
60
|
+
func: Callable[..., list[CompletionItem]],
|
|
61
|
+
) -> Callable[..., list[CompletionItem]]:
|
|
62
|
+
"""Safely handle errors in shell completion functions.
|
|
63
|
+
|
|
64
|
+
When shell completion encounters connection errors (server down, network issues, etc.),
|
|
65
|
+
this decorator catches specific exceptions and returns an empty list instead of
|
|
66
|
+
propagating the error to the terminal.
|
|
67
|
+
|
|
68
|
+
Currently catches:
|
|
69
|
+
- requests.exceptions.ConnectionError: Server connection failures
|
|
70
|
+
|
|
71
|
+
Usage:
|
|
72
|
+
------
|
|
73
|
+
@suppress_completion_errors
|
|
74
|
+
def my_completion_func(ctx, param, incomplete):
|
|
75
|
+
# code that might fail (e.g., server calls)
|
|
76
|
+
return completion_items
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
Wrapped function that returns [] on caught exceptions
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
@wraps(func)
|
|
85
|
+
def wrapper(*args, **kwargs) -> list[CompletionItem]: # noqa: ANN002, ANN003
|
|
86
|
+
try:
|
|
87
|
+
return func(*args, **kwargs)
|
|
88
|
+
except requests.exceptions.ConnectionError:
|
|
89
|
+
# Silently fail during shell completion - return empty list
|
|
90
|
+
# This prevents error messages from appearing during tab completion
|
|
91
|
+
return []
|
|
92
|
+
|
|
93
|
+
return wrapper
|
|
94
|
+
|
|
95
|
+
|
|
56
96
|
def finalize_completion(
|
|
57
97
|
candidates: list,
|
|
58
98
|
incomplete: str = "",
|
|
@@ -82,7 +122,7 @@ def finalize_completion(
|
|
|
82
122
|
|
|
83
123
|
"""
|
|
84
124
|
if sort_by not in (SORT_BY_KEY, SORT_BY_DESC, NOT_SORTED):
|
|
85
|
-
raise
|
|
125
|
+
raise CmemcError("sort_by should be -1, 0 or 1.")
|
|
86
126
|
incomplete = incomplete.lower()
|
|
87
127
|
if len(candidates) == 0:
|
|
88
128
|
return candidates
|
|
@@ -127,7 +167,7 @@ def finalize_completion(
|
|
|
127
167
|
)
|
|
128
168
|
return [CompletionItem(value=element[0], help=element[1]) for element in sorted_list]
|
|
129
169
|
|
|
130
|
-
raise
|
|
170
|
+
raise CmemcError(
|
|
131
171
|
"Candidates should be a list of strings or a list of tuples." f" Got {candidates}"
|
|
132
172
|
)
|
|
133
173
|
|
|
@@ -160,6 +200,7 @@ def add_metadata_parameter(list_: list | None = None) -> list:
|
|
|
160
200
|
return list_
|
|
161
201
|
|
|
162
202
|
|
|
203
|
+
@suppress_completion_errors
|
|
163
204
|
def acl_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
164
205
|
"""Prepare a list of access condition identifier"""
|
|
165
206
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -174,6 +215,7 @@ def acl_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionIt
|
|
|
174
215
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
175
216
|
|
|
176
217
|
|
|
218
|
+
@suppress_completion_errors
|
|
177
219
|
def acl_actions(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
178
220
|
"""Prepare a list of access condition actions"""
|
|
179
221
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -198,6 +240,7 @@ def acl_actions(ctx: Context, param: Argument, incomplete: str) -> list[Completi
|
|
|
198
240
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
199
241
|
|
|
200
242
|
|
|
243
|
+
@suppress_completion_errors
|
|
201
244
|
def acl_users(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
202
245
|
"""Prepare a list of access condition users"""
|
|
203
246
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -219,6 +262,7 @@ def acl_users(ctx: Context, param: Argument, incomplete: str) -> list[Completion
|
|
|
219
262
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
220
263
|
|
|
221
264
|
|
|
265
|
+
@suppress_completion_errors
|
|
222
266
|
def acl_groups(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
223
267
|
"""Prepare a list of access condition groups"""
|
|
224
268
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -267,6 +311,7 @@ def add_read_only_and_uri_property_parameters(list_: list | None = None) -> list
|
|
|
267
311
|
return list_
|
|
268
312
|
|
|
269
313
|
|
|
314
|
+
@suppress_completion_errors
|
|
270
315
|
def dataset_parameter(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
271
316
|
"""Prepare a list of dataset parameters for a dataset type."""
|
|
272
317
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -317,6 +362,7 @@ def dataset_parameter(ctx: Context, param: Argument, incomplete: str) -> list[Co
|
|
|
317
362
|
return [CompletionItem(value=option[0], help=option[1]) for option in options]
|
|
318
363
|
|
|
319
364
|
|
|
365
|
+
@suppress_completion_errors
|
|
320
366
|
def dataset_types(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
321
367
|
"""Prepare a list of dataset types."""
|
|
322
368
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -336,6 +382,7 @@ def dataset_types(ctx: Context, param: Argument, incomplete: str) -> list[Comple
|
|
|
336
382
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
337
383
|
|
|
338
384
|
|
|
385
|
+
@suppress_completion_errors
|
|
339
386
|
def dataset_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
340
387
|
"""Prepare a list of projectid:datasetid dataset identifier."""
|
|
341
388
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -345,43 +392,19 @@ def dataset_ids(ctx: Context, param: Argument, incomplete: str) -> list[Completi
|
|
|
345
392
|
return finalize_completion(candidates=options, incomplete=incomplete)
|
|
346
393
|
|
|
347
394
|
|
|
348
|
-
|
|
349
|
-
"""Prepare a list of filter names and values for dataset list filter."""
|
|
350
|
-
filter_names = [
|
|
351
|
-
("project", "Filter by project ID."),
|
|
352
|
-
("regex", "Filter by regular expression on the dataset label."),
|
|
353
|
-
("tag", "Filter by tag label."),
|
|
354
|
-
("type", "Filter by dataset type."),
|
|
355
|
-
]
|
|
356
|
-
filter_regex = [
|
|
357
|
-
("^Final:", "Example: Dataset label starts with 'Final:'."),
|
|
358
|
-
(
|
|
359
|
-
r"[12][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]",
|
|
360
|
-
"Example: Dataset label contains a date-like string.",
|
|
361
|
-
),
|
|
362
|
-
]
|
|
363
|
-
options = []
|
|
364
|
-
args = get_completion_args(incomplete)
|
|
365
|
-
if args[len(args) - 1] == "--filter":
|
|
366
|
-
options = finalize_completion(candidates=filter_names, incomplete=incomplete)
|
|
367
|
-
if args[len(args) - 1] == "type":
|
|
368
|
-
options = dataset_types(ctx, param, incomplete)
|
|
369
|
-
if args[len(args) - 1] == "project":
|
|
370
|
-
options = project_ids(ctx, param, incomplete)
|
|
371
|
-
if args[len(args) - 1] == "tag":
|
|
372
|
-
options = tag_labels(ctx, param, incomplete, "dataset")
|
|
373
|
-
if args[len(args) - 1] == "regex":
|
|
374
|
-
options = finalize_completion(candidates=filter_regex, incomplete=incomplete)
|
|
375
|
-
return options
|
|
376
|
-
|
|
377
|
-
|
|
395
|
+
@suppress_completion_errors
|
|
378
396
|
def resource_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
379
397
|
"""Prepare a list of projectid:resourceid resource identifier."""
|
|
380
398
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
381
|
-
options = [
|
|
399
|
+
options = []
|
|
400
|
+
for _ in get_all_resources():
|
|
401
|
+
if check_option_in_params(_["id"], ctx.params.get(str(param.name))):
|
|
402
|
+
continue
|
|
403
|
+
options.append(_["id"])
|
|
382
404
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
383
405
|
|
|
384
406
|
|
|
407
|
+
@suppress_completion_errors
|
|
385
408
|
def scheduler_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
386
409
|
"""Prepare a list of projectid:schedulerid scheduler identifier."""
|
|
387
410
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -417,11 +440,13 @@ def vocabularies(
|
|
|
417
440
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
418
441
|
|
|
419
442
|
|
|
443
|
+
@suppress_completion_errors
|
|
420
444
|
def installed_vocabularies(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
421
445
|
"""Prepare a list of installed vocabulary graphs."""
|
|
422
446
|
return vocabularies(ctx, param, incomplete, filter_="installed")
|
|
423
447
|
|
|
424
448
|
|
|
449
|
+
@suppress_completion_errors
|
|
425
450
|
def installable_vocabularies(
|
|
426
451
|
ctx: Context, param: Argument, incomplete: str
|
|
427
452
|
) -> list[CompletionItem]:
|
|
@@ -444,6 +469,7 @@ def file_list(
|
|
|
444
469
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_KEY)
|
|
445
470
|
|
|
446
471
|
|
|
472
|
+
@suppress_completion_errors
|
|
447
473
|
def workflow_io_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
448
474
|
"""Prepare a list of io workflows."""
|
|
449
475
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -455,11 +481,13 @@ def workflow_io_ids(ctx: Context, param: Argument, incomplete: str) -> list[Comp
|
|
|
455
481
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
456
482
|
|
|
457
483
|
|
|
484
|
+
@suppress_completion_errors
|
|
458
485
|
def replay_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
459
486
|
"""Prepare a list of JSON replay files."""
|
|
460
487
|
return file_list(incomplete=incomplete, suffix=".json", description="JSON query replay file")
|
|
461
488
|
|
|
462
489
|
|
|
490
|
+
@suppress_completion_errors
|
|
463
491
|
def installed_package_names(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
464
492
|
"""Prepare a list of installed packages."""
|
|
465
493
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -467,6 +495,7 @@ def installed_package_names(ctx: Context, param: Argument, incomplete: str) -> l
|
|
|
467
495
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_KEY)
|
|
468
496
|
|
|
469
497
|
|
|
498
|
+
@suppress_completion_errors
|
|
470
499
|
def published_package_names(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
471
500
|
"""List of plugin packages scraped from pypi.org."""
|
|
472
501
|
options = [(_.name, f"{_.version}: {_.description}") for _ in get_published_packages()]
|
|
@@ -483,6 +512,7 @@ def python_package_files(ctx: Context, param: Argument, incomplete: str) -> list
|
|
|
483
512
|
)
|
|
484
513
|
|
|
485
514
|
|
|
515
|
+
@suppress_completion_errors
|
|
486
516
|
def installable_packages(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
487
517
|
"""Installable packages from files and pypi.org."""
|
|
488
518
|
return python_package_files(ctx, param, incomplete) + published_package_names(
|
|
@@ -490,6 +520,7 @@ def installable_packages(ctx: Context, param: Argument, incomplete: str) -> list
|
|
|
490
520
|
)
|
|
491
521
|
|
|
492
522
|
|
|
523
|
+
@suppress_completion_errors
|
|
493
524
|
def workflow_io_output_files(
|
|
494
525
|
ctx: Context, param: Argument, incomplete: str
|
|
495
526
|
) -> list[CompletionItem]:
|
|
@@ -504,6 +535,7 @@ def workflow_io_output_files(
|
|
|
504
535
|
)
|
|
505
536
|
|
|
506
537
|
|
|
538
|
+
@suppress_completion_errors
|
|
507
539
|
def workflow_io_input_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
508
540
|
"""Prepare a list of acceptable workflow io input files."""
|
|
509
541
|
files = []
|
|
@@ -548,6 +580,7 @@ def get_dataset_file_mapping() -> dict[str, dict[str, str]]:
|
|
|
548
580
|
}
|
|
549
581
|
|
|
550
582
|
|
|
583
|
+
@suppress_completion_errors
|
|
551
584
|
def dataset_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
552
585
|
"""Prepare a list of dataset files."""
|
|
553
586
|
files = []
|
|
@@ -570,6 +603,7 @@ def dataset_files(ctx: Context, param: Argument, incomplete: str) -> list[Comple
|
|
|
570
603
|
return files + filtered_multicsv
|
|
571
604
|
|
|
572
605
|
|
|
606
|
+
@suppress_completion_errors
|
|
573
607
|
def project_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
574
608
|
"""Prepare a list of workspace files."""
|
|
575
609
|
return file_list(
|
|
@@ -579,11 +613,23 @@ def project_files(ctx: Context, param: Argument, incomplete: str) -> list[Comple
|
|
|
579
613
|
)
|
|
580
614
|
|
|
581
615
|
|
|
616
|
+
@suppress_completion_errors
|
|
582
617
|
def ini_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
583
618
|
"""Prepare a list of workspace files."""
|
|
584
619
|
return file_list(incomplete=incomplete, suffix=".ini", description="INI file")
|
|
585
620
|
|
|
586
621
|
|
|
622
|
+
@suppress_completion_errors
|
|
623
|
+
def acl_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
624
|
+
"""Prepare a list of ACL files."""
|
|
625
|
+
return file_list(
|
|
626
|
+
incomplete=incomplete,
|
|
627
|
+
suffix=".acls.json",
|
|
628
|
+
description="eccenca Corporate Memory ACL backup file",
|
|
629
|
+
)
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
@suppress_completion_errors
|
|
587
633
|
def workspace_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
588
634
|
"""Prepare a list of workspace files."""
|
|
589
635
|
return file_list(
|
|
@@ -600,6 +646,7 @@ def sparql_files(ctx: Context, param: Argument, incomplete: str) -> list[Complet
|
|
|
600
646
|
) + file_list(incomplete=incomplete, suffix=".rq", description="SPARQL query file")
|
|
601
647
|
|
|
602
648
|
|
|
649
|
+
@suppress_completion_errors
|
|
603
650
|
def triple_files(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
604
651
|
"""Prepare a list of triple files."""
|
|
605
652
|
return (
|
|
@@ -620,6 +667,7 @@ def triple_files(ctx: Context, param: Argument, incomplete: str) -> list[Complet
|
|
|
620
667
|
)
|
|
621
668
|
|
|
622
669
|
|
|
670
|
+
@suppress_completion_errors
|
|
623
671
|
def sparql_accept_types(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
624
672
|
"""Prepare a list of commonly used SPARQL accept content types."""
|
|
625
673
|
examples = [
|
|
@@ -634,6 +682,7 @@ def sparql_accept_types(ctx: Context, param: Argument, incomplete: str) -> list[
|
|
|
634
682
|
return finalize_completion(candidates=examples, incomplete=incomplete)
|
|
635
683
|
|
|
636
684
|
|
|
685
|
+
@suppress_completion_errors
|
|
637
686
|
def placeholder(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
638
687
|
"""Prepare a list of placeholder from the to-be executed queries."""
|
|
639
688
|
args = get_completion_args(incomplete)
|
|
@@ -683,6 +732,7 @@ def remote_queries(ctx: Context, param: Argument, incomplete: str) -> list[Compl
|
|
|
683
732
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
684
733
|
|
|
685
734
|
|
|
735
|
+
@suppress_completion_errors
|
|
686
736
|
def remote_queries_and_sparql_files(
|
|
687
737
|
ctx: Context, param: Argument, incomplete: str
|
|
688
738
|
) -> list[CompletionItem]:
|
|
@@ -692,6 +742,7 @@ def remote_queries_and_sparql_files(
|
|
|
692
742
|
return remote + files
|
|
693
743
|
|
|
694
744
|
|
|
745
|
+
@suppress_completion_errors
|
|
695
746
|
def workflow_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
696
747
|
"""Prepare a list of projectid:taskid workflow identifier."""
|
|
697
748
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -706,6 +757,7 @@ def workflow_ids(ctx: Context, param: Argument, incomplete: str) -> list[Complet
|
|
|
706
757
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
707
758
|
|
|
708
759
|
|
|
760
|
+
@suppress_completion_errors
|
|
709
761
|
def marshalling_plugins(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
710
762
|
"""Prepare a list of supported workspace/project import/export plugins."""
|
|
711
763
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -721,6 +773,7 @@ def marshalling_plugins(ctx: Context, param: Argument, incomplete: str) -> list[
|
|
|
721
773
|
)
|
|
722
774
|
|
|
723
775
|
|
|
776
|
+
@suppress_completion_errors
|
|
724
777
|
def project_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
725
778
|
"""Prepare a list of project IDs for auto-completion."""
|
|
726
779
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -757,6 +810,7 @@ def _prepare_graph_options(
|
|
|
757
810
|
return options
|
|
758
811
|
|
|
759
812
|
|
|
813
|
+
@suppress_completion_errors
|
|
760
814
|
def graph_uris_skip_check(
|
|
761
815
|
ctx: Context, param: Argument, incomplete: str, writeable: bool = True, readonly: bool = True
|
|
762
816
|
) -> list[CompletionItem]:
|
|
@@ -767,6 +821,7 @@ def graph_uris_skip_check(
|
|
|
767
821
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
768
822
|
|
|
769
823
|
|
|
824
|
+
@suppress_completion_errors
|
|
770
825
|
def graph_uris(
|
|
771
826
|
ctx: Context, param: Argument, incomplete: str, writeable: bool = True, readonly: bool = True
|
|
772
827
|
) -> list[CompletionItem]:
|
|
@@ -775,6 +830,7 @@ def graph_uris(
|
|
|
775
830
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
776
831
|
|
|
777
832
|
|
|
833
|
+
@suppress_completion_errors
|
|
778
834
|
def ignore_graph_uris(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
779
835
|
"""Prepare a list of import graphs for auto-completion."""
|
|
780
836
|
data_graph = ctx.args[0]
|
|
@@ -785,11 +841,13 @@ def ignore_graph_uris(ctx: Context, param: Argument, incomplete: str) -> list[Co
|
|
|
785
841
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
786
842
|
|
|
787
843
|
|
|
844
|
+
@suppress_completion_errors
|
|
788
845
|
def writable_graph_uris(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
789
846
|
"""Prepare a list of writable graphs for auto-completion."""
|
|
790
847
|
return graph_uris(ctx, param, incomplete, writeable=True, readonly=False)
|
|
791
848
|
|
|
792
849
|
|
|
850
|
+
@suppress_completion_errors
|
|
793
851
|
def graph_uris_with_all_graph_uri(
|
|
794
852
|
ctx: Context, param: Argument, incomplete: str
|
|
795
853
|
) -> list[CompletionItem]:
|
|
@@ -806,6 +864,7 @@ def graph_uris_with_all_graph_uri(
|
|
|
806
864
|
return options
|
|
807
865
|
|
|
808
866
|
|
|
867
|
+
@suppress_completion_errors
|
|
809
868
|
def connections(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
810
869
|
"""Prepare a list of config connections for auto-completion."""
|
|
811
870
|
# since ctx does not have an obj here, we re-create the object
|
|
@@ -814,6 +873,7 @@ def connections(ctx: Context, param: Argument, incomplete: str) -> list[Completi
|
|
|
814
873
|
return finalize_completion(candidates=options, incomplete=incomplete)
|
|
815
874
|
|
|
816
875
|
|
|
876
|
+
@suppress_completion_errors
|
|
817
877
|
def graph_export_templates(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
818
878
|
"""Prepare a list of example templates for the graph export command."""
|
|
819
879
|
examples = [
|
|
@@ -828,6 +888,7 @@ def graph_export_templates(ctx: Context, param: Argument, incomplete: str) -> li
|
|
|
828
888
|
return finalize_completion(candidates=examples, incomplete=incomplete)
|
|
829
889
|
|
|
830
890
|
|
|
891
|
+
@suppress_completion_errors
|
|
831
892
|
def project_export_templates(
|
|
832
893
|
ctx: Context, param: Argument, incomplete: str
|
|
833
894
|
) -> list[CompletionItem]:
|
|
@@ -840,6 +901,7 @@ def project_export_templates(
|
|
|
840
901
|
return finalize_completion(candidates=examples, incomplete=incomplete)
|
|
841
902
|
|
|
842
903
|
|
|
904
|
+
@suppress_completion_errors
|
|
843
905
|
def workspace_export_templates(
|
|
844
906
|
ctx: Context, param: Argument, incomplete: str
|
|
845
907
|
) -> list[CompletionItem]:
|
|
@@ -852,30 +914,7 @@ def workspace_export_templates(
|
|
|
852
914
|
return finalize_completion(candidates=examples, incomplete=incomplete)
|
|
853
915
|
|
|
854
916
|
|
|
855
|
-
|
|
856
|
-
"""Prepare a list of filter names and values for graph list filter."""
|
|
857
|
-
filter_names = [
|
|
858
|
-
(
|
|
859
|
-
"access",
|
|
860
|
-
"List only graphs which have a certain access condition " "(readonly or writeable).",
|
|
861
|
-
),
|
|
862
|
-
("imported-by", "List only graphs which are in the import tree of a " "specified graph."),
|
|
863
|
-
]
|
|
864
|
-
filter_values_access = [
|
|
865
|
-
("readonly", "List only graphs which are NOT writable for the current user."),
|
|
866
|
-
("writeable", "List only graphs which ARE writeable for the current user."),
|
|
867
|
-
]
|
|
868
|
-
args = get_completion_args(incomplete)
|
|
869
|
-
options = []
|
|
870
|
-
if args[len(args) - 1] == "--filter":
|
|
871
|
-
options = finalize_completion(candidates=filter_names, incomplete=incomplete)
|
|
872
|
-
if args[len(args) - 1] == "access":
|
|
873
|
-
options = finalize_completion(candidates=filter_values_access, incomplete=incomplete)
|
|
874
|
-
if args[len(args) - 1] == "imported-by":
|
|
875
|
-
options = graph_uris(ctx, param, incomplete)
|
|
876
|
-
return options
|
|
877
|
-
|
|
878
|
-
|
|
917
|
+
@suppress_completion_errors
|
|
879
918
|
def variable_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
880
919
|
"""Prepare a list of variables IDs for auto-completion."""
|
|
881
920
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -893,53 +932,7 @@ def variable_ids(ctx: Context, param: Argument, incomplete: str) -> list[Complet
|
|
|
893
932
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_KEY)
|
|
894
933
|
|
|
895
934
|
|
|
896
|
-
|
|
897
|
-
"""Prepare a list of filter names and values for variable list filter."""
|
|
898
|
-
filter_names = [
|
|
899
|
-
("project", "Filter for variables from a specific project."),
|
|
900
|
-
(
|
|
901
|
-
"regex",
|
|
902
|
-
"Filter for variables with a regular expression search over "
|
|
903
|
-
"id, value and description.",
|
|
904
|
-
),
|
|
905
|
-
]
|
|
906
|
-
filter_values_regex = [
|
|
907
|
-
("ending$", "Variables name ends with 'ending'."),
|
|
908
|
-
("^starting", "Variables name starts with 'starting'."),
|
|
909
|
-
]
|
|
910
|
-
args = get_completion_args(incomplete)
|
|
911
|
-
if args[len(args) - 1] == "--filter":
|
|
912
|
-
return [CompletionItem(value=f[0], help=f[1]) for f in filter_names]
|
|
913
|
-
if args[len(args) - 1] == "regex":
|
|
914
|
-
return finalize_completion(candidates=filter_values_regex, incomplete=incomplete)
|
|
915
|
-
if args[len(args) - 1] == "project":
|
|
916
|
-
return project_ids(ctx, param, incomplete)
|
|
917
|
-
return []
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
def resource_list_filter(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
921
|
-
"""Prepare a list of filter names and values for resource list filter."""
|
|
922
|
-
filter_names = [
|
|
923
|
-
("project", "Filter for file resources from a specific project."),
|
|
924
|
-
(
|
|
925
|
-
"regex",
|
|
926
|
-
"Filter for file resources with a regular expression search on " "the name field.",
|
|
927
|
-
),
|
|
928
|
-
]
|
|
929
|
-
filter_values_regex = [
|
|
930
|
-
("csv$", "File resources which name ends with .csv"),
|
|
931
|
-
("2021-10-[0-9][0-9]", "File resources which name has a date from 2021-10 in it"),
|
|
932
|
-
]
|
|
933
|
-
args = get_completion_args(incomplete)
|
|
934
|
-
if args[len(args) - 1] == "--filter":
|
|
935
|
-
return [CompletionItem(value=f[0], help=f[1]) for f in filter_names]
|
|
936
|
-
if args[len(args) - 1] == "project":
|
|
937
|
-
return project_ids(ctx, param, incomplete)
|
|
938
|
-
if args[len(args) - 1] == "regex":
|
|
939
|
-
return finalize_completion(candidates=filter_values_regex, incomplete=incomplete)
|
|
940
|
-
return []
|
|
941
|
-
|
|
942
|
-
|
|
935
|
+
@suppress_completion_errors
|
|
943
936
|
def workflow_list_filter(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
944
937
|
"""Prepare a list of filter names and values for workflow list filter."""
|
|
945
938
|
filter_names = [
|
|
@@ -977,6 +970,7 @@ def workflow_list_filter(ctx: Context, param: Argument, incomplete: str) -> list
|
|
|
977
970
|
return finalize_completion(candidates=options, incomplete=incomplete)
|
|
978
971
|
|
|
979
972
|
|
|
973
|
+
@suppress_completion_errors
|
|
980
974
|
def tag_labels(
|
|
981
975
|
ctx: Context, param: Argument, incomplete: str, item_type: str
|
|
982
976
|
) -> list[CompletionItem]:
|
|
@@ -997,6 +991,7 @@ def tag_labels(
|
|
|
997
991
|
)
|
|
998
992
|
|
|
999
993
|
|
|
994
|
+
@suppress_completion_errors
|
|
1000
995
|
def status_keys(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
1001
996
|
"""Prepare a list of status keys for the admin status command."""
|
|
1002
997
|
os.environ["CMEMPY_IS_CHATTY"] = "false"
|
|
@@ -1006,6 +1001,7 @@ def status_keys(ctx: Context, param: Argument, incomplete: str) -> list[Completi
|
|
|
1006
1001
|
return finalize_completion(candidates=options, incomplete=incomplete)
|
|
1007
1002
|
|
|
1008
1003
|
|
|
1004
|
+
@suppress_completion_errors
|
|
1009
1005
|
def user_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
1010
1006
|
"""Prepare a list of username for admin update/delete/password command."""
|
|
1011
1007
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -1013,6 +1009,7 @@ def user_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionI
|
|
|
1013
1009
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
1014
1010
|
|
|
1015
1011
|
|
|
1012
|
+
@suppress_completion_errors
|
|
1016
1013
|
def user_group_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
1017
1014
|
"""Prepare a list of group name for admin user update --(un)assign-group parameter"""
|
|
1018
1015
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -1039,6 +1036,7 @@ def user_group_ids(ctx: Context, param: Argument, incomplete: str) -> list[Compl
|
|
|
1039
1036
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
1040
1037
|
|
|
1041
1038
|
|
|
1039
|
+
@suppress_completion_errors
|
|
1042
1040
|
def client_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
1043
1041
|
"""Prepare a list of client ids for admin secret and update command."""
|
|
1044
1042
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -1046,6 +1044,7 @@ def client_ids(ctx: Context, param: Argument, incomplete: str) -> list[Completio
|
|
|
1046
1044
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
1047
1045
|
|
|
1048
1046
|
|
|
1047
|
+
@suppress_completion_errors
|
|
1049
1048
|
def transformation_task_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
1050
1049
|
"""Prepare a list of projectId:transformation task identifier."""
|
|
1051
1050
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -1055,6 +1054,7 @@ def transformation_task_ids(ctx: Context, param: Argument, incomplete: str) -> l
|
|
|
1055
1054
|
return finalize_completion(candidates=options, incomplete=incomplete, sort_by=SORT_BY_DESC)
|
|
1056
1055
|
|
|
1057
1056
|
|
|
1057
|
+
@suppress_completion_errors
|
|
1058
1058
|
def resource_paths(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
1059
1059
|
"""Prepare a list of file resource paths within a project.
|
|
1060
1060
|
|
cmem_cmemc/context.py
CHANGED
|
@@ -15,7 +15,9 @@ from shutil import which
|
|
|
15
15
|
import click
|
|
16
16
|
import cmem.cmempy.config as cmempy_config
|
|
17
17
|
import urllib3
|
|
18
|
+
from cmem.cmempy.config import get_cmem_base_uri
|
|
18
19
|
from cmem.cmempy.health import get_di_version, get_explore_version
|
|
20
|
+
from cmem_client.client import Client
|
|
19
21
|
from pygments import highlight
|
|
20
22
|
from pygments.formatters import get_formatter_by_name
|
|
21
23
|
from pygments.lexers import get_lexer_by_name
|
|
@@ -55,6 +57,34 @@ KNOWN_SECRET_KEYS = ("OAUTH_PASSWORD", "OAUTH_CLIENT_SECRET", "OAUTH_ACCESS_TOKE
|
|
|
55
57
|
SSL_VERIFY_WARNING = "SSL verification is disabled (SSL_VERIFY=False)."
|
|
56
58
|
|
|
57
59
|
|
|
60
|
+
def build_caption(
|
|
61
|
+
count: int,
|
|
62
|
+
item_name: str,
|
|
63
|
+
instance: str | None = None,
|
|
64
|
+
filtered: bool = False,
|
|
65
|
+
plural: str | None = None,
|
|
66
|
+
) -> str:
|
|
67
|
+
"""Build a standardized caption for table outputs.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
----
|
|
71
|
+
count: Number of items in the table
|
|
72
|
+
item_name: Name of the items (e.g., "file", "project", "query")
|
|
73
|
+
instance: Instance URI (if None, uses get_cmem_base_uri())
|
|
74
|
+
filtered: Whether the results are filtered
|
|
75
|
+
plural: Optional Plural form of the item_name (e.g. "queries"), with giving
|
|
76
|
+
a plural form, simply a 's' is added for plural.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
-------
|
|
80
|
+
Caption string in format: "X thing(s) of INSTANCE (filtered)"
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
term = (plural if plural else f"{item_name}s") if count != 1 else item_name
|
|
84
|
+
base = f"{count} {term} of {instance or get_cmem_base_uri()}"
|
|
85
|
+
return f"{base} (filtered)" if filtered else base
|
|
86
|
+
|
|
87
|
+
|
|
58
88
|
class ApplicationContext:
|
|
59
89
|
"""Context of the command line interface."""
|
|
60
90
|
|
|
@@ -72,9 +102,6 @@ class ApplicationContext:
|
|
|
72
102
|
console: Console
|
|
73
103
|
console_width: int | None = None
|
|
74
104
|
|
|
75
|
-
# pylint: disable=too-many-instance-attributes
|
|
76
|
-
# pylint: disable=too-many-public-methods
|
|
77
|
-
|
|
78
105
|
def __init__(
|
|
79
106
|
self,
|
|
80
107
|
config_file: str,
|
|
@@ -93,6 +120,11 @@ class ApplicationContext:
|
|
|
93
120
|
self.console = Console(markup=True, emoji_variant="emoji")
|
|
94
121
|
self.update_console_width()
|
|
95
122
|
|
|
123
|
+
@property
|
|
124
|
+
def client(self) -> Client:
|
|
125
|
+
"""The cmem_client Client object."""
|
|
126
|
+
return Client.from_cmempy()
|
|
127
|
+
|
|
96
128
|
@staticmethod
|
|
97
129
|
def from_params(params: dict) -> "ApplicationContext":
|
|
98
130
|
"""Create an ApplicationContext instance from a dictionary.
|
|
@@ -273,9 +305,9 @@ class ApplicationContext:
|
|
|
273
305
|
return
|
|
274
306
|
if section_string not in self.get_config():
|
|
275
307
|
raise InvalidConfigurationError(
|
|
276
|
-
self,
|
|
277
308
|
f"There is no connection '{section_string}' configured in "
|
|
278
309
|
f"config '{self.config_file}'.",
|
|
310
|
+
app=self,
|
|
279
311
|
)
|
|
280
312
|
self.connection = section_string
|
|
281
313
|
|
|
@@ -294,10 +326,10 @@ class ApplicationContext:
|
|
|
294
326
|
config.read(self.get_config_file(), encoding="utf-8")
|
|
295
327
|
except configparser.Error as error:
|
|
296
328
|
raise InvalidConfigurationError(
|
|
297
|
-
self,
|
|
298
329
|
"The following config parser error needs to be fixed with your config file:\n"
|
|
299
330
|
f"{error!s}\n"
|
|
300
331
|
"You can use the 'config edit' command to fix this.",
|
|
332
|
+
app=self,
|
|
301
333
|
) from error
|
|
302
334
|
except Exception as error: # noqa: BLE001
|
|
303
335
|
self.echo_debug(f"Could not read config file - provide empty config: {error!s}")
|
|
@@ -337,7 +369,6 @@ class ApplicationContext:
|
|
|
337
369
|
2024-05-17: also allows list of strings now
|
|
338
370
|
2024-05-17: new prepend_line parameter
|
|
339
371
|
"""
|
|
340
|
-
# pylint: disable=invalid-name
|
|
341
372
|
click.echo("") if prepend_line is True else None
|
|
342
373
|
messages: list[str] = [message] if isinstance(message, str) else message
|
|
343
374
|
for _ in messages:
|
|
@@ -434,6 +465,7 @@ class ApplicationContext:
|
|
|
434
465
|
)
|
|
435
466
|
if caption is not None:
|
|
436
467
|
table.caption = caption
|
|
468
|
+
table.min_width = len(caption)
|
|
437
469
|
for header in headers:
|
|
438
470
|
table.add_column(header, overflow="fold")
|
|
439
471
|
for row_source in rows:
|
|
@@ -450,13 +482,11 @@ class ApplicationContext:
|
|
|
450
482
|
|
|
451
483
|
def echo_success(self, message: str, nl: bool = True, condition: bool = True) -> None:
|
|
452
484
|
"""Output success message, if not suppressed by --quiet."""
|
|
453
|
-
# pylint: disable=invalid-name
|
|
454
485
|
self.echo_info(message, fg="green", nl=nl, condition=condition)
|
|
455
486
|
|
|
456
487
|
@staticmethod
|
|
457
488
|
def echo_result(message: str, nl: bool = True) -> None:
|
|
458
489
|
"""Output result message, can NOT be suppressed by --quiet."""
|
|
459
|
-
# pylint: disable=invalid-name
|
|
460
490
|
click.echo(message, nl=nl)
|
|
461
491
|
|
|
462
492
|
def check_concrete_version(self, name: str, version: str, target_version: str) -> None:
|