cmem-client 0.5.0__py3-none-any.whl → 0.6.0__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_client/client.py +16 -0
- cmem_client/exceptions.py +12 -0
- cmem_client/models/resource.py +25 -0
- cmem_client/repositories/files.py +181 -0
- cmem_client/repositories/marketplace_packages.py +68 -7
- cmem_client/repositories/protocols/delete_item.py +1 -2
- {cmem_client-0.5.0.dist-info → cmem_client-0.6.0.dist-info}/METADATA +2 -2
- {cmem_client-0.5.0.dist-info → cmem_client-0.6.0.dist-info}/RECORD +10 -8
- {cmem_client-0.5.0.dist-info → cmem_client-0.6.0.dist-info}/WHEEL +0 -0
- {cmem_client-0.5.0.dist-info → cmem_client-0.6.0.dist-info}/licenses/LICENSE +0 -0
cmem_client/client.py
CHANGED
|
@@ -40,6 +40,7 @@ from cmem_client.config import Config
|
|
|
40
40
|
from cmem_client.exceptions import ClientNoAuthProviderError
|
|
41
41
|
from cmem_client.logging_utils import install_trace_logger
|
|
42
42
|
from cmem_client.models.logging_config import LoggingConfig
|
|
43
|
+
from cmem_client.repositories.files import FilesRepository
|
|
43
44
|
from cmem_client.repositories.graph_imports import GraphImportsRepository
|
|
44
45
|
from cmem_client.repositories.graphs import GraphsRepository
|
|
45
46
|
from cmem_client.repositories.marketplace_packages import MarketplacePackagesRepository
|
|
@@ -113,6 +114,9 @@ class Client:
|
|
|
113
114
|
_workflows: WorkflowsRepository
|
|
114
115
|
"""WorkflowsRepository object for workflow operations."""
|
|
115
116
|
|
|
117
|
+
_files: FilesRepository
|
|
118
|
+
"""FilesRepository object for file operations."""
|
|
119
|
+
|
|
116
120
|
def __init__(
|
|
117
121
|
self,
|
|
118
122
|
config: Config,
|
|
@@ -483,3 +487,15 @@ class Client:
|
|
|
483
487
|
except AttributeError:
|
|
484
488
|
self._workflows = WorkflowsRepository(client=self)
|
|
485
489
|
return self._workflows
|
|
490
|
+
|
|
491
|
+
@property
|
|
492
|
+
def files(self) -> FilesRepository:
|
|
493
|
+
"""Get the files repository for managing files
|
|
494
|
+
|
|
495
|
+
Returns: The files repository instance, created lazy on first access.
|
|
496
|
+
"""
|
|
497
|
+
try:
|
|
498
|
+
return self._files
|
|
499
|
+
except AttributeError:
|
|
500
|
+
self._files = FilesRepository(client=self)
|
|
501
|
+
return self._files
|
cmem_client/exceptions.py
CHANGED
|
@@ -80,3 +80,15 @@ class MarketplacePackagesDeleteError(RepositoryModificationError):
|
|
|
80
80
|
|
|
81
81
|
class MarketplacePackagesExportError(BaseError):
|
|
82
82
|
"""Exception raised when a marketplace packages export fails."""
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class FilesImportError(RepositoryModificationError):
|
|
86
|
+
"""Exception raised when a file import fails."""
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class FilesDeleteError(RepositoryModificationError):
|
|
90
|
+
"""Exception raised when a file import fails."""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
class FilesExportError(RepositoryModificationError):
|
|
94
|
+
"""Exception raised when a file export fails."""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""A file resource model"""
|
|
2
|
+
|
|
3
|
+
from pydantic import Field
|
|
4
|
+
|
|
5
|
+
from cmem_client.models.base import Model, ReadRepositoryItem
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ResourceResponse(Model):
|
|
9
|
+
"""API response model for a file resource"""
|
|
10
|
+
|
|
11
|
+
name: str = Field(description="Resource name")
|
|
12
|
+
full_path: str = Field(description="Path of the resource", alias="fullPath")
|
|
13
|
+
modified: str = Field(description="Resource last modified time")
|
|
14
|
+
size: int = Field(description="Resource size")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Resource(Model, ReadRepositoryItem):
|
|
18
|
+
"""A file resource."""
|
|
19
|
+
|
|
20
|
+
file_id: str
|
|
21
|
+
project_id: str
|
|
22
|
+
|
|
23
|
+
def get_id(self) -> str:
|
|
24
|
+
"""Get the resource ID in format 'project_id:file_id'"""
|
|
25
|
+
return f"{self.project_id}:{self.file_id}"
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"""Files Repository."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
7
|
+
|
|
8
|
+
from httpx import HTTPError
|
|
9
|
+
from pydantic import TypeAdapter
|
|
10
|
+
|
|
11
|
+
from cmem_client.repositories.protocols.export_item import ExportConfig, ExportItemProtocol
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
|
|
16
|
+
from cmem_client.client import Client
|
|
17
|
+
|
|
18
|
+
from cmem_client.exceptions import FilesDeleteError, FilesExportError, FilesImportError
|
|
19
|
+
from cmem_client.models.item import FileImportItem, ImportItem
|
|
20
|
+
from cmem_client.models.resource import Resource, ResourceResponse
|
|
21
|
+
from cmem_client.repositories.base.plain_list import PlainListRepository
|
|
22
|
+
from cmem_client.repositories.protocols.delete_item import DeleteConfig, DeleteItemProtocol
|
|
23
|
+
from cmem_client.repositories.protocols.import_item import ImportConfig, ImportItemProtocol
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class FilesImportConfig(ImportConfig):
|
|
27
|
+
"""Files Import Configuration."""
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FilesExportConfig(ExportConfig):
|
|
31
|
+
"""Files Export Configuration."""
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class FilesDeleteConfig(DeleteConfig):
|
|
35
|
+
"""Files Delete Configuration."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class FilesRepository(PlainListRepository, ImportItemProtocol, DeleteItemProtocol, ExportItemProtocol):
|
|
39
|
+
"""Repository for files"""
|
|
40
|
+
|
|
41
|
+
_client: Client
|
|
42
|
+
_dict: dict[str, Resource]
|
|
43
|
+
_allowed_import_items: ClassVar[Sequence[type[ImportItem]]] = [FileImportItem]
|
|
44
|
+
|
|
45
|
+
def fetch_data(self) -> None:
|
|
46
|
+
"""Fetch all file resources from all projects."""
|
|
47
|
+
self._dict = {}
|
|
48
|
+
for project_id in self._client.projects:
|
|
49
|
+
for resource_data in self._get_resources(project_id):
|
|
50
|
+
resource = Resource(file_id=resource_data.full_path, project_id=project_id)
|
|
51
|
+
self._dict[resource.get_id()] = resource
|
|
52
|
+
|
|
53
|
+
def _get_resources(self, project_id: str) -> list[ResourceResponse]:
|
|
54
|
+
"""GET retrieve list of resources."""
|
|
55
|
+
url = self._client.config.url_build_api / "workspace/projects" / project_id / "resources"
|
|
56
|
+
response = self._client.http.get(url=url)
|
|
57
|
+
response.raise_for_status()
|
|
58
|
+
adapter = TypeAdapter(list[ResourceResponse])
|
|
59
|
+
return adapter.validate_json(response.content)
|
|
60
|
+
|
|
61
|
+
def _import_item(
|
|
62
|
+
self,
|
|
63
|
+
path: Path | None = None,
|
|
64
|
+
replace: bool = False,
|
|
65
|
+
key: str | None = None,
|
|
66
|
+
configuration: FilesImportConfig | None = None,
|
|
67
|
+
) -> str:
|
|
68
|
+
"""Import a file to a specific project.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
path: Local file path to upload
|
|
72
|
+
replace: Whether to replace existing file
|
|
73
|
+
key: Composite key in format 'project_id:file_path'
|
|
74
|
+
configuration: Import configuration
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Composite key in format 'project_id:file_path'
|
|
78
|
+
"""
|
|
79
|
+
_ = configuration
|
|
80
|
+
|
|
81
|
+
if path is None:
|
|
82
|
+
raise FilesImportError("Path to file necessary.")
|
|
83
|
+
|
|
84
|
+
if key is None:
|
|
85
|
+
raise FilesImportError("Key in format 'project_id:file_path' is required.")
|
|
86
|
+
|
|
87
|
+
if ":" not in key:
|
|
88
|
+
raise FilesImportError(f"Invalid key format. Expected 'project_id:file_path', got '{key}'")
|
|
89
|
+
|
|
90
|
+
project_id, resource_name = key.split(":", 1)
|
|
91
|
+
|
|
92
|
+
if not replace and key in self._dict:
|
|
93
|
+
raise FilesImportError(f"File {key} already exists. Try replace.")
|
|
94
|
+
|
|
95
|
+
url = self._client.config.url_build_api / "workspace/projects" / project_id / "files"
|
|
96
|
+
|
|
97
|
+
with path.open("rb") as file:
|
|
98
|
+
try:
|
|
99
|
+
response = self._client.http.put(url, params={"path": resource_name}, content=file)
|
|
100
|
+
response.raise_for_status()
|
|
101
|
+
except HTTPError as e:
|
|
102
|
+
raise FilesImportError(f"Could not upload file '{resource_name}' to project '{project_id}'.") from e
|
|
103
|
+
|
|
104
|
+
self.fetch_data()
|
|
105
|
+
return key
|
|
106
|
+
|
|
107
|
+
def _delete_item(self, key: str, configuration: FilesDeleteConfig | None = None) -> None:
|
|
108
|
+
"""Delete a file.
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
key: Composite key in format 'project_id:file_path'
|
|
112
|
+
configuration: Delete configuration
|
|
113
|
+
"""
|
|
114
|
+
_ = configuration
|
|
115
|
+
|
|
116
|
+
if ":" not in key:
|
|
117
|
+
raise FilesDeleteError(f"Invalid key format. Expected 'project_id:file_path', got '{key}'")
|
|
118
|
+
|
|
119
|
+
project_id, file_path = key.split(":", 1)
|
|
120
|
+
|
|
121
|
+
url = self._client.config.url_build_api / "workspace/projects" / project_id / "files"
|
|
122
|
+
try:
|
|
123
|
+
response = self._client.http.delete(url=url, params={"path": file_path})
|
|
124
|
+
response.raise_for_status()
|
|
125
|
+
except HTTPError as e:
|
|
126
|
+
raise FilesDeleteError(f"Could not delete file '{file_path}' from project '{project_id}'.") from e
|
|
127
|
+
|
|
128
|
+
def _export_item(
|
|
129
|
+
self,
|
|
130
|
+
key: str,
|
|
131
|
+
path: Path | None,
|
|
132
|
+
replace: bool = False,
|
|
133
|
+
configuration: FilesExportConfig | None = None,
|
|
134
|
+
) -> Path:
|
|
135
|
+
"""Export a file from a specific project.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
key: Composite key in format 'project_id:file_path'
|
|
139
|
+
path: Target export path
|
|
140
|
+
replace: Whether to replace existing file
|
|
141
|
+
configuration: Export configuration
|
|
142
|
+
"""
|
|
143
|
+
_ = configuration
|
|
144
|
+
|
|
145
|
+
if key is None:
|
|
146
|
+
raise FilesExportError("No resource key specified.")
|
|
147
|
+
|
|
148
|
+
if ":" not in key:
|
|
149
|
+
raise FilesExportError(f"Invalid key format. Expected 'project_id:file_path', got '{key}'")
|
|
150
|
+
|
|
151
|
+
project_id, file_path = key.split(":", 1)
|
|
152
|
+
|
|
153
|
+
if path is None:
|
|
154
|
+
target_path = Path(file_path)
|
|
155
|
+
elif path.is_dir():
|
|
156
|
+
target_path = path / file_path
|
|
157
|
+
else:
|
|
158
|
+
target_path = path
|
|
159
|
+
|
|
160
|
+
if target_path.exists() and not replace:
|
|
161
|
+
raise FilesExportError(f"File '{target_path}' already exists. Try replace=True.")
|
|
162
|
+
|
|
163
|
+
url = self._client.config.url_build_api / "workspace/projects" / project_id / "files"
|
|
164
|
+
|
|
165
|
+
try:
|
|
166
|
+
with self._client.http.stream(
|
|
167
|
+
"GET",
|
|
168
|
+
url,
|
|
169
|
+
params={"path": file_path},
|
|
170
|
+
) as response:
|
|
171
|
+
response.raise_for_status()
|
|
172
|
+
|
|
173
|
+
target_path.parent.mkdir(parents=True, exist_ok=True)
|
|
174
|
+
with target_path.open("wb") as file:
|
|
175
|
+
for chunk in response.iter_bytes():
|
|
176
|
+
file.write(chunk)
|
|
177
|
+
|
|
178
|
+
except HTTPError as e:
|
|
179
|
+
raise FilesExportError(f"Could not export file '{file_path}' from project '{project_id}'.") from e
|
|
180
|
+
|
|
181
|
+
return target_path
|
|
@@ -12,8 +12,8 @@ from pathlib import Path
|
|
|
12
12
|
from typing import TYPE_CHECKING, ClassVar
|
|
13
13
|
from zipfile import BadZipFile, ZipFile
|
|
14
14
|
|
|
15
|
-
from eccenca_marketplace_client.dependencies import
|
|
16
|
-
from eccenca_marketplace_client.
|
|
15
|
+
from eccenca_marketplace_client.models.dependencies import MarketplacePackageDependency, PythonPackageDependency
|
|
16
|
+
from eccenca_marketplace_client.models.files import GraphFileSpec, ImageFileSpec, ProjectFileSpec, TextFileSpec
|
|
17
17
|
from eccenca_marketplace_client.ontology import (
|
|
18
18
|
NS_IRI,
|
|
19
19
|
get_data_graph_iri,
|
|
@@ -29,7 +29,9 @@ from cmem_client.exceptions import (
|
|
|
29
29
|
MarketplacePackagesExportError,
|
|
30
30
|
MarketplacePackagesImportError,
|
|
31
31
|
)
|
|
32
|
+
from cmem_client.models.project import Project, ProjectMetaData
|
|
32
33
|
from cmem_client.models.python_package import PythonPackage
|
|
34
|
+
from cmem_client.repositories.files import FilesImportConfig
|
|
33
35
|
from cmem_client.repositories.graph_imports import GraphImport
|
|
34
36
|
|
|
35
37
|
if TYPE_CHECKING:
|
|
@@ -46,6 +48,7 @@ from cmem_client.repositories.protocols.export_item import ExportConfig, ExportI
|
|
|
46
48
|
from cmem_client.repositories.protocols.import_item import ImportConfig, ImportItemProtocol
|
|
47
49
|
|
|
48
50
|
MAX_DEPENDENCY_DEPTH = 5
|
|
51
|
+
MARKETPLACE_PROJECT_ID = "marketplace-packages"
|
|
49
52
|
|
|
50
53
|
|
|
51
54
|
class MarketplacePackagesImportConfig(ImportConfig):
|
|
@@ -123,13 +126,16 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
123
126
|
tmp_file.write(ontology_graph.serialize(format="turtle").encode("utf-8"))
|
|
124
127
|
|
|
125
128
|
try:
|
|
129
|
+
get_ontology_graph()
|
|
126
130
|
self._client.graphs.import_item(
|
|
127
|
-
path=tmp_path,
|
|
131
|
+
path=tmp_path,
|
|
132
|
+
replace=False,
|
|
133
|
+
key=NS_IRI,
|
|
128
134
|
)
|
|
129
135
|
finally:
|
|
130
136
|
tmp_path.unlink(missing_ok=True)
|
|
131
137
|
|
|
132
|
-
def _import_item( # noqa: C901, PLR0912
|
|
138
|
+
def _import_item( # noqa: C901, PLR0912, PLR0915
|
|
133
139
|
self,
|
|
134
140
|
path: Path | None = None,
|
|
135
141
|
replace: bool = False,
|
|
@@ -176,6 +182,7 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
176
182
|
imported_imports: list[str] = []
|
|
177
183
|
imported_python_packages: list[str] = []
|
|
178
184
|
imported_vocabulary_packages: list[str] = []
|
|
185
|
+
imported_files: list[str] = []
|
|
179
186
|
|
|
180
187
|
if manifest.package_id in self._dict:
|
|
181
188
|
if replace:
|
|
@@ -183,6 +190,8 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
183
190
|
else:
|
|
184
191
|
raise MarketplacePackagesImportError("Package already imported. Try replace.")
|
|
185
192
|
|
|
193
|
+
self._create_assets_project()
|
|
194
|
+
|
|
186
195
|
if not configuration.ignore_dependencies:
|
|
187
196
|
# import python package dependencies first
|
|
188
197
|
for dependency in manifest.dependencies:
|
|
@@ -193,7 +202,7 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
193
202
|
imported_python_packages.append(dependency.pypi_id)
|
|
194
203
|
|
|
195
204
|
for dependency in manifest.dependencies:
|
|
196
|
-
if isinstance(dependency,
|
|
205
|
+
if isinstance(dependency, MarketplacePackageDependency) and dependency.package_id not in self._dict:
|
|
197
206
|
if configuration.dependency_level >= MAX_DEPENDENCY_DEPTH:
|
|
198
207
|
self.logger.warning(
|
|
199
208
|
"Skipping dependency '%s' because the max depth of '%s' was reached.",
|
|
@@ -238,6 +247,17 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
238
247
|
self._client.graph_imports.create_item(item=new_import, skip_if_existing=True)
|
|
239
248
|
imported_imports.append(new_import.get_id())
|
|
240
249
|
|
|
250
|
+
for file in manifest.files:
|
|
251
|
+
file_resource_path = f"{manifest.package_id}/{file.file_path}"
|
|
252
|
+
composite_key = f"{MARKETPLACE_PROJECT_ID}:{file_resource_path}"
|
|
253
|
+
self._client.files.import_item(
|
|
254
|
+
path=package_version.get_file_path(file.file_path),
|
|
255
|
+
key=composite_key,
|
|
256
|
+
replace=True,
|
|
257
|
+
configuration=FilesImportConfig(use_archive_handler=False),
|
|
258
|
+
)
|
|
259
|
+
imported_files.append(composite_key)
|
|
260
|
+
|
|
241
261
|
self._add_package_triples(package_version)
|
|
242
262
|
|
|
243
263
|
# Rollback graphs + imports, projects, python packages
|
|
@@ -254,6 +274,8 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
254
274
|
self._client.python_packages.delete_item(key=python_package_id, skip_if_missing=True)
|
|
255
275
|
for vocabulary_id in imported_vocabulary_packages:
|
|
256
276
|
self._client.marketplace_packages.delete_item(key=vocabulary_id, skip_if_missing=True)
|
|
277
|
+
for file in imported_files:
|
|
278
|
+
self._client.files.delete_item(key=file, skip_if_missing=True)
|
|
257
279
|
raise MarketplacePackagesImportError(f"Failed to import package ({error!s})") from error
|
|
258
280
|
|
|
259
281
|
self.fetch_data()
|
|
@@ -311,6 +333,14 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
311
333
|
)
|
|
312
334
|
exported_files.append((exported_path, file_spec.file_path))
|
|
313
335
|
|
|
336
|
+
if isinstance(file_spec, (ImageFileSpec, TextFileSpec)):
|
|
337
|
+
file_path = tmp_path / file_spec.file_path
|
|
338
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
339
|
+
file_resource_path = f"{manifest.package_id}/{file_spec.file_path}"
|
|
340
|
+
composite_key = f"{MARKETPLACE_PROJECT_ID}:{file_resource_path}"
|
|
341
|
+
self._client.files.export_item(key=composite_key, path=file_path)
|
|
342
|
+
exported_files.append((file_path, file_spec.file_path))
|
|
343
|
+
|
|
314
344
|
manifest_path = tmp_path / "manifest.json"
|
|
315
345
|
manifest_path.write_text(manifest_json_str, encoding="utf-8")
|
|
316
346
|
|
|
@@ -338,7 +368,7 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
338
368
|
|
|
339
369
|
return path
|
|
340
370
|
|
|
341
|
-
def _delete_item(self, key: str, configuration: MarketplacePackagesDeleteConfig | None = None) -> None:
|
|
371
|
+
def _delete_item(self, key: str, configuration: MarketplacePackagesDeleteConfig | None = None) -> None: # noqa: C901
|
|
342
372
|
"""Delete a package by its package_id.
|
|
343
373
|
|
|
344
374
|
This method need be extended for new FileSpecs.
|
|
@@ -369,7 +399,7 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
369
399
|
key=dependency.pypi_id, skip_if_missing=configuration.skip_missing_dependencies
|
|
370
400
|
)
|
|
371
401
|
|
|
372
|
-
if isinstance(dependency,
|
|
402
|
+
if isinstance(dependency, MarketplacePackageDependency):
|
|
373
403
|
dependants = self._graph.get_package_dependants(dependency.package_id)
|
|
374
404
|
dependants.remove(package_id)
|
|
375
405
|
if len(dependants) > 0:
|
|
@@ -393,8 +423,18 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
393
423
|
deleted_import = GraphImport(from_graph=str(from_graph), to_graph=str(graph.graph_iri))
|
|
394
424
|
self._client.graph_imports.delete_item(key=deleted_import.get_id(), skip_if_missing=True)
|
|
395
425
|
|
|
426
|
+
for file in manifest.files:
|
|
427
|
+
file_resource_path = f"{manifest.package_id}/{file.file_path}"
|
|
428
|
+
composite_key = f"{MARKETPLACE_PROJECT_ID}:{file_resource_path}"
|
|
429
|
+
self._client.files.delete_item(key=composite_key, skip_if_missing=True)
|
|
430
|
+
|
|
396
431
|
self._client.store.sparql.update(get_delete_query(package_iri))
|
|
397
432
|
|
|
433
|
+
# Remaining package is removed by the protocol, marketplace vocabulary and project can be deleted safely
|
|
434
|
+
if len(self._dict) == 1 and key in self._dict:
|
|
435
|
+
self._client.graphs.delete_item(NS_IRI, skip_if_missing=True)
|
|
436
|
+
self._client.projects.delete_item(MARKETPLACE_PROJECT_ID, skip_if_missing=True)
|
|
437
|
+
|
|
398
438
|
def _add_package_triples(self, package: PackageVersion) -> None:
|
|
399
439
|
"""Add a package to the data config graph in the Corporate Memory instance.
|
|
400
440
|
|
|
@@ -484,3 +524,24 @@ class MarketplacePackagesRepository(Repository, ImportItemProtocol, ExportItemPr
|
|
|
484
524
|
)
|
|
485
525
|
|
|
486
526
|
return package_version
|
|
527
|
+
|
|
528
|
+
def _create_assets_project(self) -> None:
|
|
529
|
+
"""Create the assets project for the marketplace."""
|
|
530
|
+
if MARKETPLACE_PROJECT_ID in self._client.projects:
|
|
531
|
+
return
|
|
532
|
+
mp_assets = Project(
|
|
533
|
+
name=MARKETPLACE_PROJECT_ID,
|
|
534
|
+
metaData=ProjectMetaData(
|
|
535
|
+
label="Marketplace Packages",
|
|
536
|
+
description="""This project contains all files that were installed via Marketplace packages.
|
|
537
|
+
|
|
538
|
+
This project was created when you installed your first package.
|
|
539
|
+
It will be deleted after the last package is uninstalled.
|
|
540
|
+
|
|
541
|
+
For more information about marketplace packages, have a look at
|
|
542
|
+
[documentation.eccenca.com](https://go.eccenca.com/feature/marketplace-packages).
|
|
543
|
+
""",
|
|
544
|
+
),
|
|
545
|
+
)
|
|
546
|
+
self._client.projects.create_item(mp_assets)
|
|
547
|
+
self._client.projects.fetch_data()
|
|
@@ -67,14 +67,13 @@ class DeleteItemProtocol(Protocol[ItemType, DeleteItemConfig_contra]):
|
|
|
67
67
|
RepositoryModificationError: if an error occurs while creating the item
|
|
68
68
|
HTTPError: for any other http error
|
|
69
69
|
"""
|
|
70
|
-
_ = configuration
|
|
71
70
|
if key not in self._dict:
|
|
72
71
|
if not skip_if_missing:
|
|
73
72
|
raise RepositoryModificationError(f"Repository item '{key}' does not exists.")
|
|
74
73
|
self.logger.info("Item '%s' does not exists, therefore not deleting.", key)
|
|
75
74
|
return
|
|
76
75
|
try:
|
|
77
|
-
self._delete_item(key=key)
|
|
76
|
+
self._delete_item(key=key, configuration=configuration)
|
|
78
77
|
except HTTPError as error:
|
|
79
78
|
raise RepositoryModificationError(f"Error on deleting repository item '{key}'.") from error
|
|
80
79
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cmem-client
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.0
|
|
4
4
|
Summary: Next generation eccenca Corporate Memory client library.
|
|
5
5
|
License: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -14,7 +14,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
14
14
|
Classifier: Programming Language :: Python :: 3.13
|
|
15
15
|
Classifier: Programming Language :: Python :: 3.14
|
|
16
16
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
-
Requires-Dist: eccenca-marketplace-client (>=0.
|
|
17
|
+
Requires-Dist: eccenca-marketplace-client (>=0.6.0,<0.7.0)
|
|
18
18
|
Requires-Dist: httpx (>=0.27.0,<0.28.0)
|
|
19
19
|
Requires-Dist: pydantic (>=2.8.2,<3.0.0)
|
|
20
20
|
Requires-Dist: pyjwt (>=2.8.0,<3.0.0)
|
|
@@ -4,14 +4,14 @@ cmem_client/auth_provider/abc.py,sha256=ILt0G4ggscPU6m1ZtXdHeoK8t7zNyglaJ4Z9hAOP
|
|
|
4
4
|
cmem_client/auth_provider/client_credentials.py,sha256=iYzlRBJGWyLrX4k-Jj84zvY95p1pHFVxI_cb3CQG37k,9329
|
|
5
5
|
cmem_client/auth_provider/password.py,sha256=FzIt1RAvm33oDRyOdzXi3QGMfgtduE0QgerYsQI4LBI,11745
|
|
6
6
|
cmem_client/auth_provider/prefetched_token.py,sha256=pwT_gPtUaebMqpYnv1sKodHhAusGotXy4cGmVGWZvp0,6666
|
|
7
|
-
cmem_client/client.py,sha256=
|
|
7
|
+
cmem_client/client.py,sha256=qugUUEdRFhF39ib48uubCyjJmqxPzhbr4GDjrT-_95c,19287
|
|
8
8
|
cmem_client/components/__init__.py,sha256=DjuLm0R-UNidKROXBZFRa2SkTElqcFpFTkodLrGsJqk,448
|
|
9
9
|
cmem_client/components/graph_store.py,sha256=N3cJXNbebt6ov8UVs368gg8DfOE_62cJtoQw4nLLNBU,13905
|
|
10
10
|
cmem_client/components/marketplace.py,sha256=aPswFFdyV9yibDDqQ5cOCsOhzrG9kEgM5Q6Hu0DbOac,6658
|
|
11
11
|
cmem_client/components/sparql_wrapper.py,sha256=75fo52S3S_XQ8z8ShSwHaFoHtKCLJxE-H-xNLFJnWLo,1630
|
|
12
12
|
cmem_client/components/workspace.py,sha256=L5DtVU-tf4EL56Uu3UCWBJBHODfu4ptDrZ6ZobPS_Z0,8866
|
|
13
13
|
cmem_client/config.py,sha256=YgciVNv4eP7jlGXT4wGM5FPkx9oIfPuf7jvh56PQEJ0,14108
|
|
14
|
-
cmem_client/exceptions.py,sha256=
|
|
14
|
+
cmem_client/exceptions.py,sha256=iaLODfx1vQeROeoXQBcVkIoyHOC-eRKZjUCZ-NH8Ihk,2883
|
|
15
15
|
cmem_client/logging_utils.py,sha256=aFsvsx6bao3-4rUoh3xows7OmN2bGBnN2obz4VenbSc,1756
|
|
16
16
|
cmem_client/models/__init__.py,sha256=__1KnflCo_HP7G-73oaZ091ENkJK30sxfm3l1nSOR_8,701
|
|
17
17
|
cmem_client/models/access_condition.py,sha256=1_BOUlhl8YiPRlFUTm25Q3dz2QVJoVd8JMHiDelVjVc,5625
|
|
@@ -24,6 +24,7 @@ cmem_client/models/logging_config.py,sha256=_pzI545AjyPf2LGaq_bqa9XbkFQa27R4bFjj
|
|
|
24
24
|
cmem_client/models/package.py,sha256=I8cL4pSNtVw1sZM2x7s5h6GfR-IpGXHc75MytrDe_ww,954
|
|
25
25
|
cmem_client/models/project.py,sha256=jfOZzw5ESqkgyn2InpiVDKdyzh-G5YQpc_zI6PJJ3gA,1457
|
|
26
26
|
cmem_client/models/python_package.py,sha256=4grVO5y57X0xwHhyRp51KYDzzjpX-IIn1fj20PEPlDw,689
|
|
27
|
+
cmem_client/models/resource.py,sha256=LR5Y6ptJdh6jY6yugtp83XH5TX8eJSNVu9UMPB6htrc,710
|
|
27
28
|
cmem_client/models/token.py,sha256=L7lc3xATw0A_-FSoEyqOam8e9rbPwGMm1wm0xP9-Ixc,1314
|
|
28
29
|
cmem_client/models/url.py,sha256=9Ao1afKdoJP8aQ4QNhhi7p6P0RJPNvJOtFAarmDfThM,1180
|
|
29
30
|
cmem_client/models/workflow.py,sha256=9ZzlwoU5ZTmZW1w8KBb8NRFw0xb0d3wqgrIUp9S3U8w,3749
|
|
@@ -35,18 +36,19 @@ cmem_client/repositories/base/paged_list.py,sha256=MwypWtYSCkNsaR-U3KvEnOh3yff9l
|
|
|
35
36
|
cmem_client/repositories/base/plain_list.py,sha256=qF-HhiEIHsMXIW1dKdTlk9Tq4bRxuV-xrFYXpMXYy5U,1433
|
|
36
37
|
cmem_client/repositories/base/task_search.py,sha256=zeDFQLTn8Sbsvjjo0ntge8tUfbGjKtxklWYypboq61M,2305
|
|
37
38
|
cmem_client/repositories/datasets.py,sha256=y5dq665rqA_Sm4Zpgu90ojZjy-KkqCG1vBlmegEMT9A,1351
|
|
39
|
+
cmem_client/repositories/files.py,sha256=n8wCiwAEQLpQYAplHlCWboaDL-2vIUPqigdNV9TMp0A,6404
|
|
38
40
|
cmem_client/repositories/graph_imports.py,sha256=NTVR6lAgUpGkKJsxbOWswG9AS2FwzkIJUX73C-vAJb8,3070
|
|
39
41
|
cmem_client/repositories/graphs.py,sha256=Y7jz0DCUj1y55lO2egSc9Ys607le1vg4TmVLdINju40,17847
|
|
40
|
-
cmem_client/repositories/marketplace_packages.py,sha256=
|
|
42
|
+
cmem_client/repositories/marketplace_packages.py,sha256=mLpVlG_HZFneyCLlDiR_EkmbxJEFAmShwJeQFwILFAo,24605
|
|
41
43
|
cmem_client/repositories/projects.py,sha256=aY35uw1wp_ocV-WKh3ouFBClkBB5MTsQaKC1cZ95RY8,8642
|
|
42
44
|
cmem_client/repositories/protocols/__init__.py,sha256=qXSmMthpY6Tp9FpLZP32GM4cERDflTZoWpSCrEQHNcc,656
|
|
43
45
|
cmem_client/repositories/protocols/create_item.py,sha256=9ZFOcfFc9yqtNnclk7LpqMBiE7iGKASxpx49YYLCzbw,4771
|
|
44
|
-
cmem_client/repositories/protocols/delete_item.py,sha256=
|
|
46
|
+
cmem_client/repositories/protocols/delete_item.py,sha256=T8Odl7x5ZTZyuHMLfkXzRiBZDNa7yTPLi-TYYEfARKE,3431
|
|
45
47
|
cmem_client/repositories/protocols/export_item.py,sha256=wI0UDF8zpeEeUl5T-DzNGExlAf9csh_gqstKQI9TWN0,4193
|
|
46
48
|
cmem_client/repositories/protocols/import_item.py,sha256=k4Z0XjDEC2KEIcCSN9-fBqarxAAoEFltoJnQXo2Rylk,5708
|
|
47
49
|
cmem_client/repositories/python_packages.py,sha256=_XlMzvXhzt-33QTuiJnxWSVSeBUYOxufFaGAq0UoLm4,2120
|
|
48
50
|
cmem_client/repositories/workflows.py,sha256=ZTlKIwQXGgad96UKa6Ic1wh3Xhpy6KIOR2LolGW519U,4893
|
|
49
|
-
cmem_client-0.
|
|
50
|
-
cmem_client-0.
|
|
51
|
-
cmem_client-0.
|
|
52
|
-
cmem_client-0.
|
|
51
|
+
cmem_client-0.6.0.dist-info/METADATA,sha256=maaDIfIO2A8pE7LydnN6Xe59c00wg4Z3YP4N2U25WuQ,2916
|
|
52
|
+
cmem_client-0.6.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
|
|
53
|
+
cmem_client-0.6.0.dist-info/licenses/LICENSE,sha256=5t6lcWcFU3TBO5wwq9PYNbgzfVfFUuL-80v5BTGuuMQ,11334
|
|
54
|
+
cmem_client-0.6.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|