cmem-cmemc 25.5.0rc1__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 +59 -31
- cmem_cmemc/commands/acl.py +403 -26
- 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 +163 -172
- cmem_cmemc/commands/file.py +509 -0
- cmem_cmemc/commands/graph.py +200 -72
- cmem_cmemc/commands/graph_imports.py +12 -5
- cmem_cmemc/commands/graph_insights.py +157 -53
- 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 +157 -22
- cmem_cmemc/commands/python.py +9 -5
- 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 +31 -17
- cmem_cmemc/commands/workflow.py +21 -11
- cmem_cmemc/completion.py +126 -109
- cmem_cmemc/context.py +40 -10
- cmem_cmemc/exceptions.py +8 -2
- cmem_cmemc/manual_helper/graph.py +2 -2
- cmem_cmemc/manual_helper/multi_page.py +5 -7
- cmem_cmemc/object_list.py +234 -7
- cmem_cmemc/placeholder.py +2 -2
- cmem_cmemc/string_processor.py +153 -4
- cmem_cmemc/title_helper.py +50 -0
- cmem_cmemc/utils.py +9 -8
- {cmem_cmemc-25.5.0rc1.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/METADATA +7 -6
- cmem_cmemc-26.1.0rc1.dist-info/RECORD +62 -0
- {cmem_cmemc-25.5.0rc1.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/WHEEL +1 -1
- cmem_cmemc/commands/resource.py +0 -220
- cmem_cmemc-25.5.0rc1.dist-info/RECORD +0 -61
- {cmem_cmemc-25.5.0rc1.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/entry_points.txt +0 -0
- {cmem_cmemc-25.5.0rc1.dist-info → cmem_cmemc-26.1.0rc1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Graph Insights command group"""
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import time
|
|
4
4
|
|
|
5
5
|
import click
|
|
6
6
|
from click import Argument, Context
|
|
@@ -11,10 +11,17 @@ from requests import HTTPError
|
|
|
11
11
|
|
|
12
12
|
from cmem_cmemc.command import CmemcCommand
|
|
13
13
|
from cmem_cmemc.command_group import CmemcGroup
|
|
14
|
-
from cmem_cmemc.completion import
|
|
14
|
+
from cmem_cmemc.completion import (
|
|
15
|
+
NOT_SORTED,
|
|
16
|
+
finalize_completion,
|
|
17
|
+
graph_uris,
|
|
18
|
+
suppress_completion_errors,
|
|
19
|
+
)
|
|
20
|
+
from cmem_cmemc.context import ApplicationContext, build_caption
|
|
15
21
|
from cmem_cmemc.exceptions import CmemcError
|
|
16
22
|
from cmem_cmemc.object_list import (
|
|
17
23
|
DirectListPropertyFilter,
|
|
24
|
+
DirectMultiValuePropertyFilter,
|
|
18
25
|
DirectValuePropertyFilter,
|
|
19
26
|
ObjectList,
|
|
20
27
|
transform_lower,
|
|
@@ -22,11 +29,30 @@ from cmem_cmemc.object_list import (
|
|
|
22
29
|
from cmem_cmemc.string_processor import GraphLink, TimeAgo
|
|
23
30
|
from cmem_cmemc.utils import get_graphs_as_dict, struct_to_table
|
|
24
31
|
|
|
25
|
-
if TYPE_CHECKING:
|
|
26
|
-
from cmem_cmemc.context import ApplicationContext
|
|
27
32
|
|
|
33
|
+
def get_api_url(path: str = "") -> str:
|
|
34
|
+
"""Get URLs of the graph insights API.
|
|
35
|
+
|
|
36
|
+
Constructs the full URL for accessing graph insights API endpoints by combining
|
|
37
|
+
the DataPlatform API endpoint with the semspect extension base path and an
|
|
38
|
+
optional resource path.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
path: The API resource path to append to the base URL. Defaults to an empty
|
|
42
|
+
string for the root endpoint.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
The complete URL for the specified graph insights API endpoint.
|
|
46
|
+
|
|
47
|
+
Example:
|
|
48
|
+
>>> get_api_url()
|
|
49
|
+
'https://example.com/dataplatform/api/ext/semspect'
|
|
50
|
+
>>> get_api_url("/snapshot/status")
|
|
51
|
+
'https://example.com/dataplatform/api/ext/semspect/snapshot/status'
|
|
28
52
|
|
|
29
|
-
|
|
53
|
+
"""
|
|
54
|
+
base_url = get_dp_api_endpoint() + "/api/ext/semspect"
|
|
55
|
+
return f"{base_url}{path}"
|
|
30
56
|
|
|
31
57
|
|
|
32
58
|
def is_available() -> bool:
|
|
@@ -38,7 +64,7 @@ def is_available() -> bool:
|
|
|
38
64
|
}
|
|
39
65
|
"""
|
|
40
66
|
try:
|
|
41
|
-
data: dict[str, bool] = get_json(
|
|
67
|
+
data: dict[str, bool] = get_json(get_api_url())
|
|
42
68
|
except HTTPError:
|
|
43
69
|
return False
|
|
44
70
|
return bool(data["isActive"] is True and data["isUserAllowed"] is True)
|
|
@@ -46,23 +72,27 @@ def is_available() -> bool:
|
|
|
46
72
|
|
|
47
73
|
def check_availability(ctx: click.Context) -> None:
|
|
48
74
|
"""Check availability of graph insights endpoints or raise an exception"""
|
|
75
|
+
_ = ctx
|
|
49
76
|
if is_available():
|
|
50
77
|
return
|
|
51
|
-
|
|
52
|
-
raise CmemcError(app, "Graph Insights is not available.")
|
|
78
|
+
raise CmemcError("Graph Insights is not available.")
|
|
53
79
|
|
|
54
80
|
|
|
55
81
|
def get_snapshots(ctx: click.Context) -> list[dict[str, str | bool | list[str]]]:
|
|
56
82
|
"""Get the snapshot list (all snapshots)"""
|
|
57
83
|
check_availability(ctx)
|
|
58
84
|
data: list[dict[str, str | bool | list[str]]] = get_json(
|
|
59
|
-
|
|
85
|
+
get_api_url("/snapshot/status"), params={"includeManagementOnly": True}
|
|
60
86
|
)
|
|
61
87
|
return data
|
|
62
88
|
|
|
63
89
|
|
|
90
|
+
@suppress_completion_errors
|
|
64
91
|
def complete_snapshot_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]: # noqa: ARG001
|
|
65
92
|
"""Provide auto-completion for snapshot Ids"""
|
|
93
|
+
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
94
|
+
if not is_available():
|
|
95
|
+
return []
|
|
66
96
|
snapshots = get_snapshots(ctx)
|
|
67
97
|
snapshots = sorted(
|
|
68
98
|
snapshots, key=lambda snapshot: snapshot["updateInfoTimestamp"], reverse=True
|
|
@@ -102,6 +132,17 @@ snapshot_list = ObjectList(
|
|
|
102
132
|
description="Snapshots with a specific affected graph (main or sub-graphs).",
|
|
103
133
|
property_key="allGraphsSynced",
|
|
104
134
|
),
|
|
135
|
+
DirectValuePropertyFilter(
|
|
136
|
+
name="valid",
|
|
137
|
+
description="Snapshots with a specific validity indicator.",
|
|
138
|
+
property_key="isValid",
|
|
139
|
+
transform=transform_lower,
|
|
140
|
+
),
|
|
141
|
+
DirectMultiValuePropertyFilter(
|
|
142
|
+
name="ids",
|
|
143
|
+
description="Internal filter for multiple snapshot IDs.",
|
|
144
|
+
property_key="databaseId",
|
|
145
|
+
),
|
|
105
146
|
],
|
|
106
147
|
)
|
|
107
148
|
|
|
@@ -147,21 +188,26 @@ def list_command(ctx: Context, filter_: tuple[tuple[str, str]], id_only: bool, r
|
|
|
147
188
|
main_graph = _["mainGraphSynced"]
|
|
148
189
|
updated = _["updateInfoTimestamp"]
|
|
149
190
|
status = _["status"]
|
|
191
|
+
is_valid = _["isValid"]
|
|
150
192
|
if main_graph not in graphs:
|
|
151
193
|
main_graph = rf"\[missing: {main_graph}]"
|
|
152
|
-
table.append([id_, main_graph, updated, status])
|
|
194
|
+
table.append([id_, main_graph, updated, status, is_valid])
|
|
153
195
|
|
|
196
|
+
filtered = len(filter_) > 0
|
|
154
197
|
app.echo_info_table(
|
|
155
198
|
table,
|
|
156
|
-
headers=["ID", "Main Graph", "Updated", "Status"],
|
|
199
|
+
headers=["ID", "Main Graph", "Updated", "Status", "Valid"],
|
|
157
200
|
sort_column=0,
|
|
158
201
|
cell_processing={1: GraphLink(), 2: TimeAgo()},
|
|
159
|
-
|
|
202
|
+
caption=build_caption(len(table), "graph insight snapshot", filtered=filtered),
|
|
203
|
+
empty_table_message="No graph insight snapshots found for these filters."
|
|
204
|
+
if filtered
|
|
205
|
+
else "No graph insight snapshots found.",
|
|
160
206
|
)
|
|
161
207
|
|
|
162
208
|
|
|
163
209
|
@click.command(cls=CmemcCommand, name="delete")
|
|
164
|
-
@click.argument("
|
|
210
|
+
@click.argument("snapshot_ids", nargs=-1, type=click.STRING, shell_complete=complete_snapshot_ids)
|
|
165
211
|
@click.option(
|
|
166
212
|
"--filter",
|
|
167
213
|
"filter_",
|
|
@@ -173,49 +219,87 @@ def list_command(ctx: Context, filter_: tuple[tuple[str, str]], id_only: bool, r
|
|
|
173
219
|
@click.option("-a", "--all", "all_", is_flag=True, help="Delete all snapshots.")
|
|
174
220
|
@click.pass_context
|
|
175
221
|
def delete_command(
|
|
176
|
-
ctx: Context,
|
|
222
|
+
ctx: Context, snapshot_ids: tuple[str], filter_: tuple[tuple[str, str]], all_: bool
|
|
177
223
|
) -> None:
|
|
178
|
-
"""Delete
|
|
224
|
+
"""Delete graph insight snapshots.
|
|
179
225
|
|
|
180
226
|
Graph Insight Snapshots are identified by an ID.
|
|
181
|
-
|
|
182
|
-
|
|
227
|
+
|
|
228
|
+
Warning: Snapshots will be deleted without prompting.
|
|
229
|
+
|
|
230
|
+
Note: Snapshots can be listed by using the `graph insights list` command.
|
|
183
231
|
"""
|
|
184
232
|
check_availability(ctx)
|
|
185
233
|
app: ApplicationContext = ctx.obj
|
|
186
|
-
|
|
187
|
-
|
|
234
|
+
|
|
235
|
+
# Validation: require at least one selection method
|
|
236
|
+
if not snapshot_ids and not filter_ and not all_:
|
|
237
|
+
raise click.UsageError(
|
|
238
|
+
"Either provide at least one snapshot ID, "
|
|
239
|
+
"use a --filter option, or use the --all flag."
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
if snapshot_ids and (all_ or filter_):
|
|
243
|
+
raise click.UsageError("Either specify snapshot IDs OR use a --filter or the --all option.")
|
|
188
244
|
|
|
189
245
|
if all_:
|
|
190
246
|
app.echo_info("Deleting all snapshots ... ", nl=False)
|
|
191
|
-
request(method="DELETE", uri=
|
|
192
|
-
app.echo_success("
|
|
247
|
+
request(method="DELETE", uri=get_api_url("/snapshot"))
|
|
248
|
+
app.echo_success("deleted")
|
|
193
249
|
return
|
|
194
250
|
|
|
195
|
-
|
|
196
|
-
all_snapshot_ids = [_["databaseId"] for _ in all_snapshots]
|
|
251
|
+
# Get snapshots to delete based on selection method
|
|
197
252
|
filter_to_apply = list(filter_) if filter_ else []
|
|
198
|
-
if
|
|
199
|
-
|
|
253
|
+
if snapshot_ids:
|
|
254
|
+
# Use internal multi-value filter for multiple IDs
|
|
255
|
+
filter_to_apply.append(("ids", ",".join(snapshot_ids)))
|
|
200
256
|
snapshots_to_delete = snapshot_list.apply_filters(ctx=ctx, filter_=filter_to_apply)
|
|
201
|
-
if not snapshots_to_delete:
|
|
202
|
-
raise click.UsageError("No snapshots found to delete.")
|
|
203
257
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
258
|
+
if not snapshots_to_delete and snapshot_ids:
|
|
259
|
+
raise CmemcError(
|
|
260
|
+
f"Snapshot ID(s) {', '.join(snapshot_ids)} not found. "
|
|
261
|
+
"Use the 'graph insights list' command to get a list of existing snapshots."
|
|
262
|
+
)
|
|
263
|
+
|
|
264
|
+
if not snapshots_to_delete and not snapshot_ids:
|
|
265
|
+
raise CmemcError("No snapshots found to delete.")
|
|
266
|
+
|
|
267
|
+
# Avoid double removal as well as sort IDs
|
|
268
|
+
ids_to_delete = sorted({_["databaseId"] for _ in snapshots_to_delete}, key=lambda v: v.lower())
|
|
269
|
+
count = len(ids_to_delete)
|
|
270
|
+
|
|
271
|
+
# Delete each snapshot
|
|
272
|
+
for current, id_to_delete in enumerate(ids_to_delete, start=1):
|
|
273
|
+
current_string = str(current).zfill(len(str(count)))
|
|
274
|
+
app.echo_info(f"Delete snapshot {current_string}/{count}: {id_to_delete} ... ", nl=False)
|
|
275
|
+
request(method="DELETE", uri=get_api_url(f"/snapshot/{id_to_delete}"))
|
|
276
|
+
app.echo_success("deleted")
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def wait_for_snapshot(snapshot_id: str, polling_interval: int) -> None:
|
|
280
|
+
"""Poll until the snapshot reaches 'DONE' status."""
|
|
281
|
+
while True:
|
|
282
|
+
snapshot: dict[str, str | bool | list[str]] = get_json(
|
|
283
|
+
get_api_url(f"/snapshot/status/{snapshot_id}")
|
|
284
|
+
)
|
|
285
|
+
if snapshot.get("status") == "DONE":
|
|
286
|
+
break
|
|
287
|
+
time.sleep(polling_interval)
|
|
213
288
|
|
|
214
289
|
|
|
215
290
|
@click.command(cls=CmemcCommand, name="create")
|
|
216
291
|
@click.argument("iri", type=click.STRING, shell_complete=graph_uris)
|
|
292
|
+
@click.option("--wait", is_flag=True, help="Wait until snapshot creation is done.")
|
|
293
|
+
@click.option(
|
|
294
|
+
"--polling-interval",
|
|
295
|
+
type=click.IntRange(min=0, max=60),
|
|
296
|
+
show_default=True,
|
|
297
|
+
default=1,
|
|
298
|
+
help="How many seconds to wait between status polls. Status polls are"
|
|
299
|
+
" cheap, so a higher polling interval is most likely not needed.",
|
|
300
|
+
)
|
|
217
301
|
@click.pass_context
|
|
218
|
-
def create_command(ctx: Context, iri: str) -> None:
|
|
302
|
+
def create_command(ctx: Context, iri: str, wait: bool, polling_interval: int) -> None:
|
|
219
303
|
"""Create or update a graph insight snapshot.
|
|
220
304
|
|
|
221
305
|
Create a graph insight snapshot for a given graph.
|
|
@@ -225,8 +309,14 @@ def create_command(ctx: Context, iri: str) -> None:
|
|
|
225
309
|
check_availability(ctx)
|
|
226
310
|
app: ApplicationContext = ctx.obj
|
|
227
311
|
app.echo_info(f"Create / Update graph snapshot for graph {iri} ... ", nl=False)
|
|
228
|
-
|
|
229
|
-
|
|
312
|
+
snapshot_id = request(
|
|
313
|
+
method="POST", uri=get_api_url("/snapshot"), params={"contextGraph": iri}
|
|
314
|
+
).text
|
|
315
|
+
app.echo_success("started", nl=not wait)
|
|
316
|
+
if wait:
|
|
317
|
+
app.echo_info(" ... ", nl=False)
|
|
318
|
+
wait_for_snapshot(snapshot_id, polling_interval)
|
|
319
|
+
app.echo_success("created")
|
|
230
320
|
|
|
231
321
|
|
|
232
322
|
@click.command(cls=CmemcCommand, name="update")
|
|
@@ -240,9 +330,23 @@ def create_command(ctx: Context, iri: str) -> None:
|
|
|
240
330
|
multiple=True,
|
|
241
331
|
)
|
|
242
332
|
@click.option("-a", "--all", "all_", is_flag=True, help="Delete all snapshots.")
|
|
333
|
+
@click.option("--wait", is_flag=True, help="Wait until snapshot creation is done.")
|
|
334
|
+
@click.option(
|
|
335
|
+
"--polling-interval",
|
|
336
|
+
type=click.IntRange(min=0, max=60),
|
|
337
|
+
show_default=True,
|
|
338
|
+
default=1,
|
|
339
|
+
help="How many seconds to wait between status polls. Status polls are"
|
|
340
|
+
" cheap, so a higher polling interval is most likely not needed.",
|
|
341
|
+
)
|
|
243
342
|
@click.pass_context
|
|
244
|
-
def update_command(
|
|
245
|
-
ctx: Context,
|
|
343
|
+
def update_command( # noqa: PLR0913
|
|
344
|
+
ctx: Context,
|
|
345
|
+
snapshot_id: str | None,
|
|
346
|
+
filter_: tuple[tuple[str, str]],
|
|
347
|
+
all_: bool,
|
|
348
|
+
wait: bool,
|
|
349
|
+
polling_interval: int,
|
|
246
350
|
) -> None:
|
|
247
351
|
"""Update a graph insight snapshot.
|
|
248
352
|
|
|
@@ -259,24 +363,24 @@ def update_command(
|
|
|
259
363
|
filter_to_apply.append(("id", snapshot_id))
|
|
260
364
|
snapshots_to_update = snapshot_list.apply_filters(ctx=ctx, filter_=filter_to_apply)
|
|
261
365
|
|
|
262
|
-
all_snapshots = get_snapshots(ctx)
|
|
263
|
-
all_snapshot_ids = [_["databaseId"] for _ in all_snapshots]
|
|
264
|
-
|
|
265
366
|
if all_:
|
|
266
367
|
snapshots_to_update = get_snapshots(ctx)
|
|
267
368
|
|
|
268
|
-
if not snapshots_to_update:
|
|
269
|
-
raise
|
|
369
|
+
if not snapshots_to_update and snapshot_id:
|
|
370
|
+
raise CmemcError(f"Snapshot ID '{snapshot_id}' does not exist.")
|
|
371
|
+
|
|
372
|
+
if not snapshots_to_update and not snapshot_id:
|
|
373
|
+
raise CmemcError("No snapshots found to update.")
|
|
270
374
|
|
|
271
|
-
for _ in snapshots_to_update:
|
|
272
|
-
id_to_update = _["databaseId"]
|
|
273
|
-
if id_to_update not in all_snapshot_ids:
|
|
274
|
-
raise click.UsageError(f"Snapshot ID '{id_to_update}' does not exist.")
|
|
275
375
|
for _ in snapshots_to_update:
|
|
276
376
|
id_to_update = _["databaseId"]
|
|
277
377
|
app.echo_info(f"Update snapshot {id_to_update} ... ", nl=False)
|
|
278
|
-
request(method="PUT", uri=f"
|
|
279
|
-
app.echo_success("started")
|
|
378
|
+
request(method="PUT", uri=get_api_url(f"/snapshot/{id_to_update}"))
|
|
379
|
+
app.echo_success("started", nl=not wait)
|
|
380
|
+
if wait:
|
|
381
|
+
app.echo_info(" ... ", nl=False)
|
|
382
|
+
wait_for_snapshot(id_to_update, polling_interval)
|
|
383
|
+
app.echo_success("updated")
|
|
280
384
|
|
|
281
385
|
|
|
282
386
|
@click.command(cls=CmemcCommand, name="inspect")
|
|
@@ -288,7 +392,7 @@ def inspect_command(ctx: Context, snapshot_id: str, raw: bool) -> None:
|
|
|
288
392
|
check_availability(ctx)
|
|
289
393
|
app: ApplicationContext = ctx.obj
|
|
290
394
|
snapshot: dict[str, str | bool | list[str]] = get_json(
|
|
291
|
-
f"
|
|
395
|
+
get_api_url(f"/snapshot/status/{snapshot_id}")
|
|
292
396
|
)
|
|
293
397
|
if raw:
|
|
294
398
|
app.echo_info_json(snapshot)
|
cmem_cmemc/commands/metrics.py
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
"""metrics commands for cmem command line interface."""
|
|
2
2
|
|
|
3
3
|
import click
|
|
4
|
-
from click import Argument,
|
|
4
|
+
from click import Argument, Context, UsageError
|
|
5
5
|
from click.shell_completion import CompletionItem
|
|
6
6
|
from cmem.cmempy.api import request
|
|
7
|
-
from cmem.cmempy.config import
|
|
7
|
+
from cmem.cmempy.config import get_di_api_endpoint, get_dp_api_endpoint
|
|
8
8
|
from prometheus_client.parser import text_string_to_metric_families
|
|
9
9
|
from requests import HTTPError
|
|
10
10
|
|
|
11
11
|
from cmem_cmemc import completion
|
|
12
12
|
from cmem_cmemc.command import CmemcCommand
|
|
13
13
|
from cmem_cmemc.command_group import CmemcGroup
|
|
14
|
-
from cmem_cmemc.
|
|
14
|
+
from cmem_cmemc.completion import suppress_completion_errors
|
|
15
|
+
from cmem_cmemc.context import ApplicationContext, build_caption
|
|
16
|
+
from cmem_cmemc.exceptions import CmemcError
|
|
15
17
|
from cmem_cmemc.object_list import (
|
|
16
18
|
DirectValuePropertyFilter,
|
|
17
19
|
ObjectList,
|
|
@@ -94,6 +96,7 @@ metrics_list = ObjectList(
|
|
|
94
96
|
)
|
|
95
97
|
|
|
96
98
|
|
|
99
|
+
@suppress_completion_errors
|
|
97
100
|
def _complete_metrics_id(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]: # noqa: ARG001
|
|
98
101
|
"""Prepare a list of metric identifier."""
|
|
99
102
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -101,6 +104,7 @@ def _complete_metrics_id(ctx: Context, param: Argument, incomplete: str) -> list
|
|
|
101
104
|
return completion.finalize_completion(candidates=candidates, incomplete=incomplete)
|
|
102
105
|
|
|
103
106
|
|
|
107
|
+
@suppress_completion_errors
|
|
104
108
|
def _complete_metric_label_filter(
|
|
105
109
|
ctx: Context,
|
|
106
110
|
param: Argument, # noqa: ARG001
|
|
@@ -141,11 +145,11 @@ def _filter_samples(family: dict, label_filter: tuple[tuple[str, str], ...]) ->
|
|
|
141
145
|
sample_labels = sample[1]
|
|
142
146
|
for name, value in label_filter:
|
|
143
147
|
if name not in labels:
|
|
144
|
-
raise
|
|
148
|
+
raise CmemcError(
|
|
145
149
|
f"The metric '{family_name}' does " f"not have a label named '{name}'."
|
|
146
150
|
)
|
|
147
151
|
if value not in labels[name]:
|
|
148
|
-
raise
|
|
152
|
+
raise CmemcError(
|
|
149
153
|
f"The metric '{family_name}' does "
|
|
150
154
|
f"not have a label '{name}' with the value '{value}'."
|
|
151
155
|
)
|
|
@@ -157,7 +161,6 @@ def _filter_samples(family: dict, label_filter: tuple[tuple[str, str], ...]) ->
|
|
|
157
161
|
return samples
|
|
158
162
|
|
|
159
163
|
|
|
160
|
-
# pylint: disable-msg=too-many-arguments
|
|
161
164
|
@click.command(cls=CmemcCommand, name="get")
|
|
162
165
|
@click.argument("metric_id", required=True, type=click.STRING, shell_complete=_complete_metrics_id)
|
|
163
166
|
@click.option(
|
|
@@ -214,7 +217,7 @@ def get_command(
|
|
|
214
217
|
return
|
|
215
218
|
|
|
216
219
|
if len(samples) == 0:
|
|
217
|
-
raise
|
|
220
|
+
raise CmemcError(
|
|
218
221
|
"No data - the given label combination filtered out "
|
|
219
222
|
f"all available samples of the metric {metric_id}."
|
|
220
223
|
)
|
|
@@ -308,12 +311,15 @@ def list_command(
|
|
|
308
311
|
]
|
|
309
312
|
for _ in data
|
|
310
313
|
]
|
|
314
|
+
filtered = len(filter_) > 0
|
|
311
315
|
app.echo_info_table(
|
|
312
316
|
table,
|
|
313
317
|
headers=["ID", "Type", "L", "S", "Documentation"],
|
|
314
318
|
sort_column=0,
|
|
315
|
-
caption=
|
|
316
|
-
empty_table_message="No metrics
|
|
319
|
+
caption=build_caption(len(table), "metric", filtered=filtered),
|
|
320
|
+
empty_table_message="No metrics found for these filters."
|
|
321
|
+
if filtered
|
|
322
|
+
else "No metrics available.",
|
|
317
323
|
)
|
|
318
324
|
|
|
319
325
|
|
cmem_cmemc/commands/migration.py
CHANGED
|
@@ -8,8 +8,12 @@ from click.shell_completion import CompletionItem
|
|
|
8
8
|
|
|
9
9
|
from cmem_cmemc.command import CmemcCommand
|
|
10
10
|
from cmem_cmemc.command_group import CmemcGroup
|
|
11
|
-
from cmem_cmemc.completion import
|
|
12
|
-
|
|
11
|
+
from cmem_cmemc.completion import (
|
|
12
|
+
check_option_in_params,
|
|
13
|
+
finalize_completion,
|
|
14
|
+
suppress_completion_errors,
|
|
15
|
+
)
|
|
16
|
+
from cmem_cmemc.context import ApplicationContext, build_caption
|
|
13
17
|
from cmem_cmemc.migrations.access_conditions_243 import (
|
|
14
18
|
MoveAccessConditionsToNewGraph,
|
|
15
19
|
RenameAuthVocabularyResources,
|
|
@@ -65,6 +69,7 @@ def get_migrations(ctx: click.Context) -> list[dict]: # noqa: ARG001
|
|
|
65
69
|
return data
|
|
66
70
|
|
|
67
71
|
|
|
72
|
+
@suppress_completion_errors
|
|
68
73
|
def complete_migration_ids(ctx: Context, param: Argument, incomplete: str) -> list[CompletionItem]:
|
|
69
74
|
"""Prepare a list of migration recipe IDs"""
|
|
70
75
|
ApplicationContext.set_connection_from_params(ctx.find_root().params)
|
|
@@ -153,12 +158,15 @@ def list_command(
|
|
|
153
158
|
]
|
|
154
159
|
for _ in data
|
|
155
160
|
]
|
|
161
|
+
filtered = len(filter_) > 0
|
|
156
162
|
app.echo_info_table(
|
|
157
163
|
table,
|
|
158
164
|
headers=["ID", "Description", "Tags", "First Version"],
|
|
159
165
|
sort_column=3,
|
|
160
|
-
caption=
|
|
161
|
-
empty_table_message="No migrations
|
|
166
|
+
caption=build_caption(len(table), "migration", filtered=filtered),
|
|
167
|
+
empty_table_message="No migrations found for these filters."
|
|
168
|
+
if filtered
|
|
169
|
+
else "No migrations available.",
|
|
162
170
|
)
|
|
163
171
|
|
|
164
172
|
|