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.
Files changed (51) hide show
  1. cmem_cmemc/__init__.py +7 -12
  2. cmem_cmemc/command.py +20 -0
  3. cmem_cmemc/command_group.py +70 -0
  4. cmem_cmemc/commands/__init__.py +0 -81
  5. cmem_cmemc/commands/acl.py +118 -62
  6. cmem_cmemc/commands/admin.py +46 -35
  7. cmem_cmemc/commands/client.py +2 -1
  8. cmem_cmemc/commands/config.py +3 -1
  9. cmem_cmemc/commands/dataset.py +27 -24
  10. cmem_cmemc/commands/graph.py +100 -16
  11. cmem_cmemc/commands/metrics.py +195 -79
  12. cmem_cmemc/commands/migration.py +265 -0
  13. cmem_cmemc/commands/project.py +62 -17
  14. cmem_cmemc/commands/python.py +57 -26
  15. cmem_cmemc/commands/query.py +23 -14
  16. cmem_cmemc/commands/resource.py +10 -2
  17. cmem_cmemc/commands/scheduler.py +10 -2
  18. cmem_cmemc/commands/store.py +118 -14
  19. cmem_cmemc/commands/user.py +8 -2
  20. cmem_cmemc/commands/validation.py +304 -113
  21. cmem_cmemc/commands/variable.py +10 -2
  22. cmem_cmemc/commands/vocabulary.py +48 -29
  23. cmem_cmemc/commands/workflow.py +86 -59
  24. cmem_cmemc/commands/workspace.py +27 -8
  25. cmem_cmemc/completion.py +185 -141
  26. cmem_cmemc/constants.py +2 -0
  27. cmem_cmemc/context.py +88 -42
  28. cmem_cmemc/manual_helper/graph.py +1 -0
  29. cmem_cmemc/manual_helper/multi_page.py +3 -1
  30. cmem_cmemc/migrations/__init__.py +1 -0
  31. cmem_cmemc/migrations/abc.py +84 -0
  32. cmem_cmemc/migrations/access_conditions_243.py +118 -0
  33. cmem_cmemc/migrations/bootstrap_data.py +30 -0
  34. cmem_cmemc/migrations/shapes_widget_integrations_243.py +194 -0
  35. cmem_cmemc/migrations/workspace_configurations.py +28 -0
  36. cmem_cmemc/object_list.py +53 -22
  37. cmem_cmemc/parameter_types/__init__.py +1 -0
  38. cmem_cmemc/parameter_types/path.py +69 -0
  39. cmem_cmemc/smart_path/__init__.py +94 -0
  40. cmem_cmemc/smart_path/clients/__init__.py +63 -0
  41. cmem_cmemc/smart_path/clients/http.py +65 -0
  42. cmem_cmemc/string_processor.py +77 -0
  43. cmem_cmemc/title_helper.py +41 -0
  44. cmem_cmemc/utils.py +114 -47
  45. {cmem_cmemc-24.2.0rc1.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/LICENSE +1 -1
  46. cmem_cmemc-24.3.0rc1.dist-info/METADATA +89 -0
  47. cmem_cmemc-24.3.0rc1.dist-info/RECORD +53 -0
  48. {cmem_cmemc-24.2.0rc1.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/WHEEL +1 -1
  49. cmem_cmemc-24.2.0rc1.dist-info/METADATA +0 -69
  50. cmem_cmemc-24.2.0rc1.dist-info/RECORD +0 -37
  51. {cmem_cmemc-24.2.0rc1.dist-info → cmem_cmemc-24.3.0rc1.dist-info}/entry_points.txt +0 -0
@@ -1,15 +1,33 @@
1
1
  """DataPlatform store commands for the cmem command line interface."""
2
+
2
3
  import os
3
- from pathlib import Path
4
+ from dataclasses import dataclass
4
5
 
5
6
  import click
6
- from click import UsageError
7
+ from click import Argument, Context, UsageError
8
+ from click.shell_completion import CompletionItem
7
9
  from cmem.cmempy.dp.admin import create_showcase_data, delete_bootstrap_data, import_bootstrap_data
8
10
  from cmem.cmempy.dp.admin.backup import get_zip, post_zip
11
+ from cmem.cmempy.dp.workspace import migrate_workspaces
12
+ from cmem.cmempy.health import get_dp_info
13
+ from jinja2 import Template
9
14
 
10
- from cmem_cmemc import completion
11
- from cmem_cmemc.commands import CmemcCommand, CmemcGroup
15
+ from cmem_cmemc.command import CmemcCommand
16
+ from cmem_cmemc.command_group import CmemcGroup
17
+ from cmem_cmemc.completion import file_list
12
18
  from cmem_cmemc.context import ApplicationContext
19
+ from cmem_cmemc.parameter_types.path import ClickSmartPath
20
+ from cmem_cmemc.smart_path import SmartPath as Path
21
+ from cmem_cmemc.utils import validate_zipfile
22
+
23
+
24
+ def complete_store_backup_files(
25
+ ctx: Context, # noqa: ARG001
26
+ param: Argument, # noqa: ARG001
27
+ incomplete: str,
28
+ ) -> list[CompletionItem]:
29
+ """Prepare a list of Store Backip Files."""
30
+ return file_list(incomplete=incomplete, suffix=".store.zip", description="Store Backup File")
13
31
 
14
32
 
15
33
  @click.command(cls=CmemcCommand, name="bootstrap")
@@ -32,6 +50,8 @@ def bootstrap_command(app: ApplicationContext, import_: bool, remove: bool) -> N
32
50
 
33
51
  Note: The removal of existing bootstrap data will search for resources which are
34
52
  flagged with the isSystemResource property.
53
+
54
+ Note: The import part of this command is equivalent to the 'bootstrap-data' migration recipe
35
55
  """
36
56
  if import_ and remove or not import_ and not remove:
37
57
  raise UsageError("Either use the --import or the --remove option.")
@@ -90,17 +110,24 @@ def showcase_command(app: ApplicationContext, scale: int, create: bool, delete:
90
110
  @click.command(cls=CmemcCommand, name="export")
91
111
  @click.argument(
92
112
  "BACKUP_FILE",
93
- shell_complete=completion.graph_backup_files,
94
- required=True,
95
- type=click.Path(writable=True, allow_dash=False, dir_okay=False),
113
+ shell_complete=complete_store_backup_files,
114
+ required=False,
115
+ type=ClickSmartPath(writable=True, allow_dash=False, dir_okay=False),
96
116
  )
97
117
  @click.option(
98
118
  "--overwrite",
99
119
  is_flag=True,
100
- help="Overwrite existing files. " "This is a dangerous option, so use it with care.",
120
+ hidden=True,
121
+ )
122
+ @click.option(
123
+ "--replace",
124
+ is_flag=True,
125
+ help="Replace existing files. This is a dangerous option, so use it with care.",
101
126
  )
102
127
  @click.pass_obj
103
- def export_command(app: ApplicationContext, backup_file: str, overwrite: bool) -> None:
128
+ def export_command(
129
+ app: ApplicationContext, backup_file: str, overwrite: bool, replace: bool
130
+ ) -> None:
104
131
  """Backup all knowledge graphs to a ZIP archive.
105
132
 
106
133
  The backup file is a ZIP archive containing all knowledge graphs (one
@@ -109,9 +136,17 @@ def export_command(app: ApplicationContext, backup_file: str, overwrite: bool) -
109
136
  This command will create lots of load on the server.
110
137
  It can take a long time to complete.
111
138
  """
112
- if Path(backup_file).exists() and overwrite is not True:
139
+ if not backup_file:
140
+ backup_file = Template("{{date}}-{{connection}}.store.zip").render(app.get_template_data())
141
+ if overwrite:
142
+ replace = overwrite
143
+ app.echo_warning(
144
+ "The option --overwrite is deprecated and will be removed with the next major release."
145
+ " Please use the --replace option instead."
146
+ )
147
+ if Path(backup_file).exists() and replace is not True:
113
148
  raise ValueError(
114
- f"Export file {backup_file} already exists and --overwrite " "option is not used."
149
+ f"Export file {backup_file} already exists and --replace option is not used."
115
150
  )
116
151
  with get_zip() as request:
117
152
  request.raise_for_status()
@@ -132,15 +167,19 @@ def export_command(app: ApplicationContext, backup_file: str, overwrite: bool) -
132
167
  app.echo_info(".", nl=False)
133
168
  byte_counter = 0
134
169
  app.echo_debug(f"Wrote {overall_byte_counter} bytes to {backup_file}.")
135
- app.echo_success(" done")
170
+ if validate_zipfile(zipfile=backup_file):
171
+ app.echo_debug(f"{backup_file} successfully validated")
172
+ app.echo_success(" done")
173
+ else:
174
+ app.echo_error(" error (file corrupt)")
136
175
 
137
176
 
138
177
  @click.command(cls=CmemcCommand, name="import")
139
178
  @click.argument(
140
179
  "BACKUP_FILE",
141
- shell_complete=completion.graph_backup_files,
180
+ shell_complete=complete_store_backup_files,
142
181
  required=True,
143
- type=click.Path(readable=True, exists=True, allow_dash=False, dir_okay=False),
182
+ type=ClickSmartPath(readable=True, exists=True, allow_dash=False, dir_okay=False),
144
183
  )
145
184
  @click.pass_obj
146
185
  def import_command(app: ApplicationContext, backup_file: str) -> None:
@@ -166,6 +205,70 @@ def import_command(app: ApplicationContext, backup_file: str) -> None:
166
205
  app.echo_success(" done")
167
206
 
168
207
 
208
+ @dataclass
209
+ class CommandResult:
210
+ """Represents the result of a command execution"""
211
+
212
+ data: list
213
+ headers: list[str]
214
+ caption: str
215
+ empty_state_message: str
216
+
217
+
218
+ def _migrate_workspaces() -> CommandResult:
219
+ """Migrate workspace configurations to the current CMEM version."""
220
+ request = migrate_workspaces()
221
+ return CommandResult(
222
+ data=[(iri,) for iri in request],
223
+ headers=["IRI"],
224
+ caption="Migrated workspace configurations",
225
+ empty_state_message="No migrateable workspace configurations found.",
226
+ )
227
+
228
+
229
+ def _get_migrate_workspaces() -> CommandResult:
230
+ """Retrieve workspace configurations that have been migrated to the current CMEM version."""
231
+ dp_info = get_dp_info()
232
+ migratable_workspace_configurations = dp_info["workspaceConfiguration"]["workspacesToMigrate"]
233
+ return CommandResult(
234
+ data=[(_["iri"], _["label"]) for _ in migratable_workspace_configurations],
235
+ headers=["IRI", "LABEL"],
236
+ caption="Migrateable configurations workspaces",
237
+ empty_state_message="No migrateable workspace configurations found.",
238
+ )
239
+
240
+
241
+ @click.command("migrate")
242
+ @click.option(
243
+ "--workspaces",
244
+ is_flag=True,
245
+ help="Migrate workspace configurations to the current version.",
246
+ )
247
+ @click.pass_obj
248
+ def migrate_command(app: ApplicationContext, workspaces: bool) -> None:
249
+ """Migrate configuration resources to the current version.
250
+
251
+ This command serves two purposes: (1) When invoked without an option, it lists
252
+ all migrateable configuration resources. (2) When invoked with the `--workspaces`
253
+ option, it migrates the workspace configurations to the current version.
254
+ """
255
+ app.echo_warning(
256
+ "The command is deprecated and will be removed with the next major release. "
257
+ "Please use the `admin migration` command group instead."
258
+ )
259
+ result = _migrate_workspaces() if workspaces else _get_migrate_workspaces()
260
+
261
+ if result.data:
262
+ app.echo_info_table(
263
+ result.data,
264
+ headers=result.headers,
265
+ sort_column=0,
266
+ caption=result.caption,
267
+ )
268
+ else:
269
+ app.echo_success(result.empty_state_message)
270
+
271
+
169
272
  @click.group(cls=CmemcGroup)
170
273
  def store() -> CmemcGroup: # type: ignore[empty-body]
171
274
  """Import, export and bootstrap the knowledge graph store.
@@ -179,3 +282,4 @@ store.add_command(showcase_command)
179
282
  store.add_command(bootstrap_command)
180
283
  store.add_command(export_command)
181
284
  store.add_command(import_command)
285
+ store.add_command(migrate_command)
@@ -1,4 +1,5 @@
1
1
  """Keycloak user management commands"""
2
+
2
3
  import sys
3
4
  from getpass import getpass
4
5
 
@@ -19,7 +20,8 @@ from cmem.cmempy.keycloak.user import (
19
20
  )
20
21
 
21
22
  from cmem_cmemc import completion
22
- from cmem_cmemc.commands import CmemcCommand, CmemcGroup
23
+ from cmem_cmemc.command import CmemcCommand
24
+ from cmem_cmemc.command_group import CmemcGroup
23
25
  from cmem_cmemc.context import ApplicationContext
24
26
  from cmem_cmemc.object_list import (
25
27
  DirectValuePropertyFilter,
@@ -115,7 +117,11 @@ def list_command(
115
117
  for usr in users
116
118
  ]
117
119
  app.echo_info_table(
118
- table, headers=["Username", "First Name", "Last Name", "Email"], sort_column=0
120
+ table,
121
+ headers=["Username", "First Name", "Last Name", "Email"],
122
+ sort_column=0,
123
+ empty_table_message="No user accounts found. "
124
+ "Use the `admin user create` command to create an account.",
119
125
  )
120
126
 
121
127