digitalkin 0.1.1__py3-none-any.whl → 0.2.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.
Files changed (77) hide show
  1. base_server/__init__.py +1 -0
  2. base_server/mock/__init__.py +5 -0
  3. base_server/mock/mock_pb2.py +39 -0
  4. base_server/mock/mock_pb2_grpc.py +102 -0
  5. base_server/server_async_insecure.py +124 -0
  6. base_server/server_async_secure.py +142 -0
  7. base_server/server_sync_insecure.py +102 -0
  8. base_server/server_sync_secure.py +121 -0
  9. digitalkin/__init__.py +1 -11
  10. digitalkin/__version__.py +1 -4
  11. digitalkin/{grpc → grpc_servers}/__init__.py +1 -13
  12. digitalkin/{grpc → grpc_servers}/_base_server.py +3 -3
  13. digitalkin/{grpc → grpc_servers}/module_server.py +30 -12
  14. digitalkin/{grpc → grpc_servers}/module_servicer.py +30 -14
  15. digitalkin/{grpc → grpc_servers}/registry_server.py +6 -4
  16. digitalkin/{grpc → grpc_servers}/registry_servicer.py +8 -2
  17. digitalkin/{grpc → grpc_servers}/utils/factory.py +6 -4
  18. digitalkin/grpc_servers/utils/grpc_client_wrapper.py +68 -0
  19. digitalkin/{grpc → grpc_servers}/utils/models.py +1 -1
  20. digitalkin/models/__init__.py +1 -4
  21. digitalkin/models/module/__init__.py +8 -2
  22. digitalkin/models/module/module_types.py +10 -0
  23. digitalkin/models/services/__init__.py +0 -5
  24. digitalkin/modules/__init__.py +3 -3
  25. digitalkin/modules/_base_module.py +64 -27
  26. digitalkin/modules/archetype_module.py +2 -6
  27. digitalkin/modules/job_manager.py +46 -28
  28. digitalkin/modules/tool_module.py +3 -7
  29. digitalkin/modules/trigger_module.py +2 -7
  30. digitalkin/services/__init__.py +7 -9
  31. digitalkin/services/agent/__init__.py +2 -2
  32. digitalkin/services/agent/agent_strategy.py +3 -6
  33. digitalkin/services/agent/default_agent.py +1 -4
  34. digitalkin/services/base_strategy.py +18 -0
  35. digitalkin/services/cost/__init__.py +4 -3
  36. digitalkin/services/cost/cost_strategy.py +35 -5
  37. digitalkin/services/cost/default_cost.py +22 -5
  38. digitalkin/services/cost/grpc_cost.py +81 -0
  39. digitalkin/services/filesystem/__init__.py +4 -3
  40. digitalkin/services/filesystem/default_filesystem.py +197 -17
  41. digitalkin/services/filesystem/filesystem_strategy.py +54 -15
  42. digitalkin/services/filesystem/grpc_filesystem.py +209 -0
  43. digitalkin/services/identity/__init__.py +2 -2
  44. digitalkin/services/identity/default_identity.py +1 -1
  45. digitalkin/services/identity/identity_strategy.py +3 -1
  46. digitalkin/services/registry/__init__.py +2 -2
  47. digitalkin/services/registry/default_registry.py +1 -4
  48. digitalkin/services/registry/registry_strategy.py +3 -6
  49. digitalkin/services/services_config.py +176 -0
  50. digitalkin/services/services_models.py +61 -0
  51. digitalkin/services/setup/default_setup.py +222 -0
  52. digitalkin/services/setup/grpc_setup.py +307 -0
  53. digitalkin/services/setup/setup_strategy.py +145 -0
  54. digitalkin/services/snapshot/__init__.py +2 -2
  55. digitalkin/services/snapshot/default_snapshot.py +1 -1
  56. digitalkin/services/snapshot/snapshot_strategy.py +3 -4
  57. digitalkin/services/storage/__init__.py +4 -3
  58. digitalkin/services/storage/default_storage.py +184 -57
  59. digitalkin/services/storage/grpc_storage.py +76 -170
  60. digitalkin/services/storage/storage_strategy.py +195 -24
  61. digitalkin/utils/arg_parser.py +16 -17
  62. {digitalkin-0.1.1.dist-info → digitalkin-0.2.0.dist-info}/METADATA +8 -7
  63. digitalkin-0.2.0.dist-info/RECORD +78 -0
  64. {digitalkin-0.1.1.dist-info → digitalkin-0.2.0.dist-info}/WHEEL +1 -1
  65. digitalkin-0.2.0.dist-info/top_level.txt +3 -0
  66. modules/__init__.py +0 -0
  67. modules/minimal_llm_module.py +162 -0
  68. modules/storage_module.py +187 -0
  69. modules/text_transform_module.py +201 -0
  70. digitalkin/services/default_service.py +0 -13
  71. digitalkin/services/development_service.py +0 -10
  72. digitalkin/services/service_provider.py +0 -27
  73. digitalkin-0.1.1.dist-info/RECORD +0 -59
  74. digitalkin-0.1.1.dist-info/top_level.txt +0 -1
  75. /digitalkin/{grpc → grpc_servers}/utils/exceptions.py +0 -0
  76. /digitalkin/{grpc → grpc_servers}/utils/types.py +0 -0
  77. {digitalkin-0.1.1.dist-info → digitalkin-0.2.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,222 @@
1
+ """This module contains the abstract base class for setup strategies."""
2
+
3
+ import logging
4
+ import secrets
5
+ import string
6
+ from typing import Any
7
+
8
+ from pydantic import ValidationError
9
+
10
+ from digitalkin.services.setup.grpc_setup import SetupData, SetupVersionData
11
+ from digitalkin.services.setup.setup_strategy import SetupServiceError, SetupStrategy
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ class DefaultSetup(SetupStrategy):
17
+ """Abstract base class for setup strategies."""
18
+
19
+ setups: dict[str, SetupData]
20
+ setup_versions: dict[str, dict[str, SetupVersionData]]
21
+
22
+ def __init__(self) -> None:
23
+ """Initialize the default setup strategy."""
24
+ super().__init__()
25
+ self.setups = {}
26
+ self.setup_versions = {}
27
+
28
+ def create_setup(self, setup_dict: dict[str, Any]) -> str:
29
+ """Create a new setup with comprehensive validation.
30
+
31
+ Args:
32
+ setup_dict: Dictionary containing setup details.
33
+
34
+ Returns:
35
+ bool: Success status of setup creation.
36
+
37
+ Raises:
38
+ ValidationError: If setup data is invalid.
39
+ GrpcOperationError: If gRPC operation fails.
40
+ """
41
+ try:
42
+ valid_data = SetupData.model_validate(setup_dict["data"]) # Revalidates instance
43
+ except ValidationError:
44
+ logger.exception("Validation failed for model SetupData")
45
+ return ""
46
+
47
+ setup_id = setup_dict.get(
48
+ "setup_id", "".join(secrets.choice(string.ascii_letters + string.digits) for _ in range(16))
49
+ )
50
+ valid_data.id = setup_id
51
+ self.setups[setup_id] = valid_data
52
+ logger.info("CREATE SETUP DATA %s:%s succesfull", setup_id, valid_data)
53
+ return setup_id
54
+
55
+ def get_setup(self, setup_dict: dict[str, Any]) -> SetupData:
56
+ """Retrieve a setup by its unique identifier.
57
+
58
+ Args:
59
+ setup_dict: Dictionary with 'name' and optional 'version'.
60
+
61
+ Raises:
62
+ SetupServiceError: setup_id does not exist.
63
+
64
+ Returns:
65
+ Dict[str, Any]: Setup details including optional setup version.
66
+ """
67
+ logger.info("GET setup_id = %s", setup_dict["setup_id"])
68
+ if setup_dict["setup_id"] not in self.setups:
69
+ msg = f"GET setup_id = {setup_dict['setup_id']}: setup_id DOESN'T EXIST"
70
+ logger.error(msg)
71
+ raise SetupServiceError(msg)
72
+ return self.setups[setup_dict["setup_id"]]
73
+
74
+ def update_setup(self, setup_dict: dict[str, Any]) -> bool:
75
+ """Update an existing setup.
76
+
77
+ Args:
78
+ setup_dict: Dictionary with setup update details.
79
+
80
+ Raises:
81
+ ValidationError: setup object failed validation.
82
+
83
+ Returns:
84
+ bool: Success status of the update operation.
85
+ """
86
+ if setup_dict["setup_id"] not in self.setups:
87
+ logger.info("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_dict["setup_id"])
88
+ return False
89
+
90
+ try:
91
+ valid_data = SetupData.model_validate(setup_dict["data"]) # Revalidates instance
92
+ except ValidationError:
93
+ logger.exception("Validation failed for model SetupData")
94
+ return False
95
+
96
+ self.setups[setup_dict["update_id"]] = valid_data
97
+ return True
98
+
99
+ def delete_setup(self, setup_dict: dict[str, Any]) -> bool:
100
+ """Delete a setup by its unique identifier.
101
+
102
+ Args:
103
+ setup_dict: Dictionary with the setup 'name'.
104
+
105
+ Returns:
106
+ bool: Success status of deletion.
107
+ """
108
+ if setup_dict["setup_id"] not in self.setups:
109
+ logger.info("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_dict["setup_id"])
110
+ return False
111
+ del self.setups[setup_dict["setup_id"]]
112
+ return True
113
+
114
+ def create_setup_version(self, setup_version_dict: dict[str, Any]) -> str:
115
+ """Create a new setup version.
116
+
117
+ Args:
118
+ setup_version_dict: Dictionary with setup version details.
119
+
120
+ Raises:
121
+ SetupServiceError: setup object failed validation.
122
+
123
+ Returns:
124
+ str: version of setup version creation.
125
+ """
126
+ try:
127
+ valid_data = SetupVersionData.model_validate(setup_version_dict["data"]) # Revalidates instance
128
+ except ValidationError:
129
+ msg = "Validation failed for model SetupVersionData"
130
+ logger.exception(msg)
131
+ raise SetupServiceError(msg)
132
+
133
+ if setup_version_dict["setup_id"] not in self.setup_versions:
134
+ self.setup_versions[setup_version_dict["setup_id"]] = {}
135
+ self.setup_versions[setup_version_dict["setup_id"]][valid_data.version] = valid_data
136
+ logger.info("CREATE SETUP VERSION DATA %s:%s succesfull", setup_version_dict["setup_id"], valid_data)
137
+ return valid_data.version
138
+
139
+ def get_setup_version(self, setup_version_dict: dict[str, Any]) -> SetupVersionData:
140
+ """Retrieve a setup version by its unique identifier.
141
+
142
+ Args:
143
+ setup_version_dict: Dictionary with the setup version 'name'.
144
+
145
+ Raises:
146
+ SetupServiceError: setup_id does not exist.
147
+
148
+ Returns:
149
+ Dict[str, Any]: Setup version details.
150
+ """
151
+ logger.info("GET setup_id = %s: version = %s", setup_version_dict["setup_id"], setup_version_dict["version"])
152
+ if setup_version_dict["setup_id"] not in self.setup_versions:
153
+ msg = f"GET setup_id = {setup_version_dict['setup_id']}: setup_id DOESN'T EXIST"
154
+ logger.error(msg)
155
+ raise SetupServiceError(msg)
156
+
157
+ return self.setup_versions[setup_version_dict["setup_id"]][setup_version_dict["version"]]
158
+
159
+ def search_setup_versions(self, setup_version_dict: dict[str, Any]) -> list[SetupVersionData]:
160
+ """Search for setup versions based on filters.
161
+
162
+ Args:
163
+ setup_version_dict: Dictionary with optional 'name' or 'query_versions' filters.
164
+
165
+ Raises:
166
+ SetupServiceError: setup_id does not exist.
167
+
168
+ Returns:
169
+ List[SetupVersionData]: A list of matching setup version details.
170
+ """
171
+ if setup_version_dict["setup_id"] not in self.setup_versions:
172
+ msg = f"GET setup_id = {setup_version_dict['setup_id']}: setup_id DOESN'T EXIST"
173
+ logger.error(msg)
174
+ raise SetupServiceError(msg)
175
+
176
+ return [
177
+ value
178
+ for value in setup_version_dict["setup_id"].values()
179
+ if setup_version_dict["query_versions"] in value.version or setup_version_dict["name"] in value.name
180
+ ]
181
+
182
+ def update_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
183
+ """Update an existing setup version.
184
+
185
+ Args:
186
+ setup_version_dict: Dictionary with setup version update details.
187
+
188
+ Returns:
189
+ bool: Success status of the update operation.
190
+ """
191
+ if setup_version_dict["setup_id"] not in self.setup_versions:
192
+ logger.info("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_version_dict["setup_id"])
193
+ return False
194
+
195
+ if setup_version_dict["version"] not in self.setup_versions["setup_id"]:
196
+ logger.info("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_version_dict["setup_id"])
197
+ return False
198
+
199
+ try:
200
+ valid_data = SetupVersionData.model_validate(setup_version_dict["data"])
201
+ except ValidationError:
202
+ logger.exception("Validation failed for model SetupVersionData")
203
+ return False
204
+
205
+ self.setup_versions[setup_version_dict["setup_id"]][setup_version_dict["version"]] = valid_data
206
+ return True
207
+
208
+ def delete_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
209
+ """Delete a setup version by its unique identifier.
210
+
211
+ Args:
212
+ setup_version_dict: Dictionary with the setup version 'name'.
213
+
214
+ Returns:
215
+ bool: Success status of version deletion.
216
+ """
217
+ if setup_version_dict["setup_id"] not in self.setup_versions:
218
+ logger.info("UPDATE setup_id = %s: setup_id DOESN'T EXIST", setup_version_dict["setup_id"])
219
+ return False
220
+
221
+ del self.setup_versions[setup_version_dict["setup_id"]][setup_version_dict["version"]]
222
+ return True
@@ -0,0 +1,307 @@
1
+ """Digital Kin Setup Service gRPC Client."""
2
+
3
+ import logging
4
+ from collections.abc import Generator
5
+ from contextlib import contextmanager
6
+ from typing import Any
7
+
8
+ import grpc
9
+ from digitalkin_proto.digitalkin.setup.v2 import (
10
+ setup_pb2,
11
+ setup_service_pb2_grpc,
12
+ )
13
+ from google.protobuf import json_format
14
+ from google.protobuf.struct_pb2 import Struct
15
+ from pydantic import ValidationError
16
+
17
+ from digitalkin.grpc_servers.utils.exceptions import ServerError
18
+ from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
19
+ from digitalkin.grpc_servers.utils.models import ServerConfig
20
+ from digitalkin.services.setup.setup_strategy import SetupData, SetupServiceError, SetupStrategy, SetupVersionData
21
+
22
+ logger = logging.getLogger(__name__)
23
+
24
+
25
+ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
26
+ """This class implements the gRPC setup service."""
27
+
28
+ def __post_init__(self, config: ServerConfig) -> None:
29
+ """Init the channel from a config file.
30
+
31
+ Need to be call if the user register a gRPC channel.
32
+ """
33
+ channel = self._init_channel(config)
34
+ self.stub = setup_service_pb2_grpc.SetupServiceStub(channel)
35
+ logger.info("Channel client 'setup' initialized succesfully")
36
+
37
+ @contextmanager
38
+ def _handle_grpc_errors(self, operation: str) -> Generator[Any, Any, Any]: # noqa: PLR6301
39
+ """Context manager for consistent gRPC error handling.
40
+
41
+ Yields:
42
+ Allow error handling in context.
43
+
44
+ Args:
45
+ operation: Description of the operation being performed.
46
+
47
+ Raises:
48
+ ValueError: Error wiht the model validation.
49
+ ServerError: from gRPC Client.
50
+ SetupServiceError: setup service internal.
51
+ """
52
+ try:
53
+ yield
54
+ except ValidationError as e:
55
+ msg = f"Invalid data for {operation}"
56
+ logger.exception(msg)
57
+ raise ValueError(msg) from e
58
+ except grpc.RpcError as e:
59
+ msg = f"gRPC {operation} failed: {e}"
60
+ logger.exception(msg)
61
+ raise ServerError(msg) from e
62
+ except Exception as e:
63
+ msg = f"Unexpected error in {operation}"
64
+ logger.exception(msg)
65
+ raise SetupServiceError(msg) from e
66
+
67
+ def create_setup(self, setup_dict: dict[str, Any]) -> str:
68
+ """Create a new setup with comprehensive validation.
69
+
70
+ Args:
71
+ setup_dict: Dictionary containing setup details.
72
+
73
+ Returns:
74
+ bool: Success status of setup creation.
75
+
76
+ Raises:
77
+ ValidationError: If setup data is invalid.
78
+ ServerError: If gRPC operation fails.
79
+ SetupServiceError: For any unexpected internal error.
80
+ """
81
+ with self._handle_grpc_errors("Setup Creation"):
82
+ valid_data = SetupData.model_validate(setup_dict)
83
+
84
+ request = setup_pb2.CreateSetupRequest(
85
+ name=valid_data.name,
86
+ organisation_id=valid_data.organisation_id,
87
+ owner_id=valid_data.owner_id,
88
+ module_id=valid_data.module_id,
89
+ current_setup_version=setup_pb2.SetupVersion(**valid_data.current_setup_version.model_dump()),
90
+ )
91
+ response = self.exec_grpc_query("CreateSetup", request)
92
+ logger.info("Setup '%s' query sent successfully", valid_data.name)
93
+ return response
94
+
95
+ def get_setup(self, setup_dict: dict[str, Any]) -> SetupData:
96
+ """Retrieve a setup by its unique identifier.
97
+
98
+ Args:
99
+ setup_dict: Dictionary with 'name' and optional 'version'.
100
+
101
+ Returns:
102
+ dict[str, Any]: Setup details including optional setup version.
103
+
104
+ Raises:
105
+ ValidationError: If the setup name is missing.
106
+ ServerError: If gRPC operation fails.
107
+ SetupServiceError: For any unexpected internal error.
108
+ """
109
+ with self._handle_grpc_errors("Get Setup"):
110
+ if "setup_id" not in setup_dict:
111
+ msg = "Setup name is required"
112
+ raise ValidationError(msg)
113
+ request = setup_pb2.GetSetupRequest(
114
+ setup_id=setup_dict["setup_id"],
115
+ version=setup_dict.get("version", ""),
116
+ )
117
+ response = self.exec_grpc_query("GetSetup", request)
118
+ response_data = json_format.MessageToDict(response, preserving_proto_field_name=True)
119
+ return SetupData(**response_data["setup"])
120
+
121
+ def update_setup(self, setup_dict: dict[str, Any]) -> bool:
122
+ """Update an existing setup.
123
+
124
+ Args:
125
+ setup_dict: Dictionary with setup update details.
126
+
127
+ Returns:
128
+ bool: Success status of the update operation.
129
+
130
+ Raises:
131
+ ValidationError: If setup data is invalid.
132
+ ServerError: If gRPC operation fails.
133
+ SetupServiceError: For any unexpected internal error.
134
+ """
135
+ current_setup_version = None
136
+
137
+ with self._handle_grpc_errors("Setup Update"):
138
+ valid_data = SetupData.model_validate(setup_dict)
139
+
140
+ if valid_data.current_setup_version is not None:
141
+ current_setup_version = setup_pb2.SetupVersion(**valid_data.current_setup_version.model_dump())
142
+
143
+ request = setup_pb2.UpdateSetupRequest(
144
+ name=valid_data.name,
145
+ owner_id=valid_data.owner_id or "",
146
+ current_setup_version=current_setup_version,
147
+ )
148
+ response = self.exec_grpc_query("UpdateSetup", request)
149
+ logger.info("Setup '%s' query sent successfully", valid_data.name)
150
+ return getattr(response, "success", False)
151
+
152
+ def delete_setup(self, setup_dict: dict[str, Any]) -> bool:
153
+ """Delete a setup by its unique identifier.
154
+
155
+ Args:
156
+ setup_dict: Dictionary with the setup 'setup_id'.
157
+
158
+ Returns:
159
+ bool: Success status of deletion.
160
+
161
+ Raises:
162
+ ValidationError: If the setup setup_id is missing.
163
+ ServerError: If gRPC operation fails.
164
+ SetupServiceError: For any unexpected internal error.
165
+ """
166
+ with self._handle_grpc_errors("Setup Deletion"):
167
+ setup_id = setup_dict.get("setup_id")
168
+ if not setup_id:
169
+ msg = "Setup name is required for deletion"
170
+ raise ValidationError(msg)
171
+ request = setup_pb2.DeleteSetupRequest(setup_id=setup_id)
172
+ response = self.exec_grpc_query("DeleteSetup", request)
173
+ logger.info("Setup '%s' query sent successfully", setup_id)
174
+ return getattr(response, "success", False)
175
+
176
+ def create_setup_version(self, setup_version_dict: dict[str, Any]) -> str:
177
+ """Create a new setup version.
178
+
179
+ Args:
180
+ setup_version_dict: Dictionary with setup version details.
181
+
182
+ Returns:
183
+ str: version of setup version creation.
184
+
185
+ Raises:
186
+ ValidationError: If setup version data is invalid.
187
+ ServerError: If gRPC operation fails.
188
+ SetupServiceError: For any unexpected internal error.
189
+ """
190
+ with self._handle_grpc_errors("Setup Version Creation"):
191
+ valid_data = SetupVersionData.model_validate(setup_version_dict)
192
+ content_struct = Struct()
193
+ content_struct.update(valid_data.content)
194
+ request = setup_pb2.CreateSetupVersionRequest(
195
+ setup_id=valid_data.setup_id,
196
+ version=valid_data.version,
197
+ content=content_struct,
198
+ )
199
+ logger.info(
200
+ "Setup Version '%s' for setup '%s' query sent successfully",
201
+ valid_data.version,
202
+ valid_data.setup_id,
203
+ )
204
+ return self.exec_grpc_query("CreateSetupVersion", request)
205
+
206
+ def get_setup_version(self, setup_version_dict: dict[str, Any]) -> SetupVersionData:
207
+ """Retrieve a setup version by its unique identifier.
208
+
209
+ Args:
210
+ setup_version_dict: Dictionary with the setup version 'setup_version_id'.
211
+
212
+ Returns:
213
+ dict[str, Any]: Setup version details.
214
+
215
+ Raises:
216
+ ValidationError: If the setup version id is missing.
217
+ ServerError: If gRPC operation fails.
218
+ SetupServiceError: For any unexpected internal error.
219
+ """
220
+ with self._handle_grpc_errors("Get Setup Version"):
221
+ setup_version_id = setup_version_dict.get("setup_version_id")
222
+ if not setup_version_id:
223
+ msg = "Setup version id is required"
224
+ raise ValidationError(msg)
225
+ request = setup_pb2.GetSetupVersionRequest(setup_version_id=setup_version_id)
226
+ response = self.exec_grpc_query("GetSetupVersion", request)
227
+ return SetupVersionData(**json_format.MessageToDict(response.setup_version))
228
+
229
+ def search_setup_versions(self, setup_version_dict: dict[str, Any]) -> list[SetupVersionData]:
230
+ """Search for setup versions based on filters.
231
+
232
+ Args:
233
+ setup_version_dict: Dictionary with optional 'name' and 'version' filters.
234
+
235
+ Returns:
236
+ list[dict[str, Any]]: A list of matching setup version details.
237
+
238
+ Raises:
239
+ ServerError: If gRPC operation fails.
240
+ SetupServiceError: For any unexpected internal error.
241
+ ValidationError: If both name and version are not provided.
242
+ """
243
+ with self._handle_grpc_errors("Search Setup Versions"):
244
+ if "name" not in setup_version_dict and "version" not in setup_version_dict:
245
+ msg = "Either name or version must be provided"
246
+ raise ValidationError(msg)
247
+ request = setup_pb2.SearchSetupVersionsRequest(
248
+ setup_id=setup_version_dict.get("setup_id", ""),
249
+ version=setup_version_dict.get("version", ""),
250
+ )
251
+ response = self.exec_grpc_query("SearchSetupVersions", request)
252
+ return [SetupVersionData(**json_format.MessageToDict(sv)) for sv in response.setup_versions]
253
+
254
+ def update_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
255
+ """Update an existing setup version.
256
+
257
+ Args:
258
+ setup_version_dict: Dictionary with setup version update details.
259
+
260
+ Returns:
261
+ bool: Success status of the update operation.
262
+
263
+ Raises:
264
+ ValidationError: If setup version data is invalid.
265
+ ServerError: If gRPC operation fails.
266
+ SetupServiceError: For any unexpected internal error.
267
+ """
268
+ with self._handle_grpc_errors("Setup Version Update"):
269
+ valid_data = SetupVersionData.model_validate(setup_version_dict)
270
+ content_struct = Struct()
271
+ content_struct.update(valid_data.content)
272
+ request = setup_pb2.UpdateSetupVersionRequest(
273
+ setup_version_id=valid_data.id,
274
+ version=valid_data.version,
275
+ content=content_struct,
276
+ )
277
+ response = self.exec_grpc_query("UpdateSetupVersion", request)
278
+ logger.info(
279
+ "Setup Version '%s' for setup '%s' query sent successfully",
280
+ valid_data.id,
281
+ valid_data.setup_id,
282
+ )
283
+ return getattr(response, "success", False)
284
+
285
+ def delete_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
286
+ """Delete a setup version by its unique identifier.
287
+
288
+ Args:
289
+ setup_version_dict: Dictionary with the setup version 'name'.
290
+
291
+ Returns:
292
+ bool: Success status of version deletion.
293
+
294
+ Raises:
295
+ ValidationError: If the setup version name is missing.
296
+ ServerError: If gRPC operation fails.
297
+ SetupServiceError: For any unexpected internal error.
298
+ """
299
+ with self._handle_grpc_errors("Setup Version Deletion"):
300
+ setup_version_id = setup_version_dict.get("setup_version_id")
301
+ if not setup_version_id:
302
+ msg = "Setup version id is required for deletion"
303
+ raise ValidationError(msg)
304
+ request = setup_pb2.DeleteSetupVersionRequest(setup_version_id=setup_version_id)
305
+ response = self.exec_grpc_query("DeleteSetupVersion", request)
306
+ logger.info("Setup Version '%s' query sent successfully", setup_version_id)
307
+ return getattr(response, "success", False)
@@ -0,0 +1,145 @@
1
+ """This module contains the abstract base class for setup strategies."""
2
+
3
+ import datetime
4
+ from abc import ABC, abstractmethod
5
+ from typing import Any
6
+
7
+ from pydantic import BaseModel
8
+
9
+
10
+ class SetupServiceError(Exception):
11
+ """Base exception for Setup service errors."""
12
+
13
+
14
+ class SetupVersionData(BaseModel):
15
+ """Pydantic model for SetupVersion data validation."""
16
+
17
+ id: str
18
+ setup_id: str
19
+ version: str
20
+ content: dict[str, Any]
21
+ creation_date: datetime.datetime
22
+
23
+
24
+ class SetupData(BaseModel):
25
+ """Pydantic model for Setup data validation."""
26
+
27
+ id: str
28
+ name: str
29
+ organisation_id: str
30
+ owner_id: str
31
+ module_id: str
32
+ current_setup_version: SetupVersionData
33
+
34
+
35
+ class SetupStrategy(ABC):
36
+ """Abstract base class for setup strategies."""
37
+
38
+ def __init__(self) -> None:
39
+ """Initialize the setup strategy."""
40
+
41
+ def __post_init__(self, *args, **kwargs) -> None: # noqa: ANN002, ANN003
42
+ """Initialize the setup strategy."""
43
+
44
+ @abstractmethod
45
+ def create_setup(self, setup_dict: dict[str, Any]) -> str:
46
+ """Create a new setup with comprehensive validation.
47
+
48
+ Args:
49
+ setup_dict: Dictionary containing setup details.
50
+
51
+ Returns:
52
+ bool: Success status of setup creation.
53
+
54
+ Raises:
55
+ ValidationError: If setup data is invalid.
56
+ GrpcOperationError: If gRPC operation fails.
57
+ """
58
+
59
+ @abstractmethod
60
+ def get_setup(self, setup_dict: dict[str, Any]) -> SetupData:
61
+ """Retrieve a setup by its unique identifier.
62
+
63
+ Args:
64
+ setup_dict: Dictionary with 'name' and optional 'version'.
65
+
66
+ Returns:
67
+ Dict[str, Any]: Setup details including optional setup version.
68
+ """
69
+
70
+ @abstractmethod
71
+ def update_setup(self, setup_dict: dict[str, Any]) -> bool:
72
+ """Update an existing setup.
73
+
74
+ Args:
75
+ setup_dict: Dictionary with setup update details.
76
+
77
+ Returns:
78
+ bool: Success status of the update operation.
79
+ """
80
+
81
+ @abstractmethod
82
+ def delete_setup(self, setup_dict: dict[str, Any]) -> bool:
83
+ """Delete a setup by its unique identifier.
84
+
85
+ Args:
86
+ setup_dict: Dictionary with the setup 'name'.
87
+
88
+ Returns:
89
+ bool: Success status of deletion.
90
+ """
91
+
92
+ @abstractmethod
93
+ def create_setup_version(self, setup_version_dict: dict[str, Any]) -> str:
94
+ """Create a new setup version.
95
+
96
+ Args:
97
+ setup_version_dict: Dictionary with setup version details.
98
+
99
+ Returns:
100
+ str: name of setup version creation.
101
+ """
102
+
103
+ @abstractmethod
104
+ def get_setup_version(self, setup_version_dict: dict[str, Any]) -> SetupVersionData:
105
+ """Retrieve a setup version by its unique identifier.
106
+
107
+ Args:
108
+ setup_version_dict: Dictionary with the setup version 'name'.
109
+
110
+ Returns:
111
+ Dict[str, Any]: Setup version details.
112
+ """
113
+
114
+ @abstractmethod
115
+ def search_setup_versions(self, setup_version_dict: dict[str, Any]) -> list[SetupVersionData]:
116
+ """Search for setup versions based on filters.
117
+
118
+ Args:
119
+ setup_version_dict: Dictionary with optional 'name' and 'version' filters.
120
+
121
+ Returns:
122
+ List[Dict[str, Any]]: A list of matching setup version details.
123
+ """
124
+
125
+ @abstractmethod
126
+ def update_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
127
+ """Update an existing setup version.
128
+
129
+ Args:
130
+ setup_version_dict: Dictionary with setup version update details.
131
+
132
+ Returns:
133
+ bool: Success status of the update operation.
134
+ """
135
+
136
+ @abstractmethod
137
+ def delete_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
138
+ """Delete a setup version by its unique identifier.
139
+
140
+ Args:
141
+ setup_version_dict: Dictionary with the setup version 'name'.
142
+
143
+ Returns:
144
+ bool: Success status of version deletion.
145
+ """
@@ -1,6 +1,6 @@
1
1
  """This module is responsible for handling the snapshot service."""
2
2
 
3
- from .default_snapshot import DefaultSnapshot
4
- from .snapshot_strategy import SnapshotStrategy
3
+ from digitalkin.services.snapshot.default_snapshot import DefaultSnapshot
4
+ from digitalkin.services.snapshot.snapshot_strategy import SnapshotStrategy
5
5
 
6
6
  __all__ = ["DefaultSnapshot", "SnapshotStrategy"]
@@ -2,7 +2,7 @@
2
2
 
3
3
  from typing import Any
4
4
 
5
- from .snapshot_strategy import SnapshotStrategy
5
+ from digitalkin.services.snapshot.snapshot_strategy import SnapshotStrategy
6
6
 
7
7
 
8
8
  class DefaultSnapshot(SnapshotStrategy):