digitalkin 0.2.25rc0__py3-none-any.whl → 0.3.2.dev14__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 (122) hide show
  1. base_server/server_async_insecure.py +6 -5
  2. base_server/server_async_secure.py +6 -5
  3. base_server/server_sync_insecure.py +5 -4
  4. base_server/server_sync_secure.py +5 -4
  5. digitalkin/__version__.py +1 -1
  6. digitalkin/core/__init__.py +1 -0
  7. digitalkin/core/common/__init__.py +9 -0
  8. digitalkin/core/common/factories.py +156 -0
  9. digitalkin/core/job_manager/__init__.py +1 -0
  10. digitalkin/{modules → core}/job_manager/base_job_manager.py +138 -32
  11. digitalkin/core/job_manager/single_job_manager.py +373 -0
  12. digitalkin/{modules → core}/job_manager/taskiq_broker.py +121 -26
  13. digitalkin/core/job_manager/taskiq_job_manager.py +541 -0
  14. digitalkin/core/task_manager/__init__.py +1 -0
  15. digitalkin/core/task_manager/base_task_manager.py +539 -0
  16. digitalkin/core/task_manager/local_task_manager.py +108 -0
  17. digitalkin/core/task_manager/remote_task_manager.py +87 -0
  18. digitalkin/core/task_manager/surrealdb_repository.py +266 -0
  19. digitalkin/core/task_manager/task_executor.py +249 -0
  20. digitalkin/core/task_manager/task_session.py +368 -0
  21. digitalkin/grpc_servers/__init__.py +1 -19
  22. digitalkin/grpc_servers/_base_server.py +3 -3
  23. digitalkin/grpc_servers/module_server.py +120 -195
  24. digitalkin/grpc_servers/module_servicer.py +81 -44
  25. digitalkin/grpc_servers/utils/__init__.py +1 -0
  26. digitalkin/grpc_servers/utils/exceptions.py +0 -8
  27. digitalkin/grpc_servers/utils/grpc_client_wrapper.py +25 -9
  28. digitalkin/grpc_servers/utils/grpc_error_handler.py +53 -0
  29. digitalkin/grpc_servers/utils/utility_schema_extender.py +100 -0
  30. digitalkin/logger.py +64 -27
  31. digitalkin/mixins/__init__.py +19 -0
  32. digitalkin/mixins/base_mixin.py +10 -0
  33. digitalkin/mixins/callback_mixin.py +24 -0
  34. digitalkin/mixins/chat_history_mixin.py +110 -0
  35. digitalkin/mixins/cost_mixin.py +76 -0
  36. digitalkin/mixins/file_history_mixin.py +93 -0
  37. digitalkin/mixins/filesystem_mixin.py +46 -0
  38. digitalkin/mixins/logger_mixin.py +51 -0
  39. digitalkin/mixins/storage_mixin.py +79 -0
  40. digitalkin/models/__init__.py +1 -1
  41. digitalkin/models/core/__init__.py +1 -0
  42. digitalkin/{modules/job_manager → models/core}/job_manager_models.py +3 -11
  43. digitalkin/models/core/task_monitor.py +74 -0
  44. digitalkin/models/grpc_servers/__init__.py +1 -0
  45. digitalkin/{grpc_servers/utils → models/grpc_servers}/models.py +92 -7
  46. digitalkin/models/module/__init__.py +18 -11
  47. digitalkin/models/module/base_types.py +61 -0
  48. digitalkin/models/module/module.py +9 -1
  49. digitalkin/models/module/module_context.py +282 -6
  50. digitalkin/models/module/module_types.py +29 -105
  51. digitalkin/models/module/setup_types.py +490 -0
  52. digitalkin/models/module/tool_cache.py +68 -0
  53. digitalkin/models/module/tool_reference.py +117 -0
  54. digitalkin/models/module/utility.py +167 -0
  55. digitalkin/models/services/__init__.py +9 -0
  56. digitalkin/models/services/cost.py +1 -0
  57. digitalkin/models/services/registry.py +35 -0
  58. digitalkin/models/services/storage.py +39 -5
  59. digitalkin/modules/__init__.py +5 -1
  60. digitalkin/modules/_base_module.py +265 -167
  61. digitalkin/modules/archetype_module.py +6 -1
  62. digitalkin/modules/tool_module.py +16 -3
  63. digitalkin/modules/trigger_handler.py +7 -6
  64. digitalkin/modules/triggers/__init__.py +8 -0
  65. digitalkin/modules/triggers/healthcheck_ping_trigger.py +45 -0
  66. digitalkin/modules/triggers/healthcheck_services_trigger.py +63 -0
  67. digitalkin/modules/triggers/healthcheck_status_trigger.py +52 -0
  68. digitalkin/services/__init__.py +4 -0
  69. digitalkin/services/communication/__init__.py +7 -0
  70. digitalkin/services/communication/communication_strategy.py +76 -0
  71. digitalkin/services/communication/default_communication.py +101 -0
  72. digitalkin/services/communication/grpc_communication.py +234 -0
  73. digitalkin/services/cost/__init__.py +9 -2
  74. digitalkin/services/cost/grpc_cost.py +9 -42
  75. digitalkin/services/filesystem/default_filesystem.py +0 -2
  76. digitalkin/services/filesystem/grpc_filesystem.py +10 -39
  77. digitalkin/services/registry/__init__.py +22 -1
  78. digitalkin/services/registry/default_registry.py +135 -4
  79. digitalkin/services/registry/exceptions.py +47 -0
  80. digitalkin/services/registry/grpc_registry.py +306 -0
  81. digitalkin/services/registry/registry_models.py +15 -0
  82. digitalkin/services/registry/registry_strategy.py +88 -4
  83. digitalkin/services/services_config.py +25 -3
  84. digitalkin/services/services_models.py +5 -1
  85. digitalkin/services/setup/default_setup.py +6 -7
  86. digitalkin/services/setup/grpc_setup.py +52 -15
  87. digitalkin/services/storage/grpc_storage.py +4 -4
  88. digitalkin/services/user_profile/__init__.py +12 -0
  89. digitalkin/services/user_profile/default_user_profile.py +55 -0
  90. digitalkin/services/user_profile/grpc_user_profile.py +69 -0
  91. digitalkin/services/user_profile/user_profile_strategy.py +25 -0
  92. digitalkin/utils/__init__.py +28 -0
  93. digitalkin/utils/arg_parser.py +1 -1
  94. digitalkin/utils/development_mode_action.py +2 -2
  95. digitalkin/utils/dynamic_schema.py +483 -0
  96. digitalkin/utils/package_discover.py +1 -2
  97. digitalkin/utils/schema_splitter.py +207 -0
  98. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/METADATA +11 -30
  99. digitalkin-0.3.2.dev14.dist-info/RECORD +143 -0
  100. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/top_level.txt +1 -0
  101. modules/archetype_with_tools_module.py +244 -0
  102. modules/cpu_intensive_module.py +1 -1
  103. modules/dynamic_setup_module.py +338 -0
  104. modules/minimal_llm_module.py +1 -1
  105. modules/text_transform_module.py +1 -1
  106. monitoring/digitalkin_observability/__init__.py +46 -0
  107. monitoring/digitalkin_observability/http_server.py +150 -0
  108. monitoring/digitalkin_observability/interceptors.py +176 -0
  109. monitoring/digitalkin_observability/metrics.py +201 -0
  110. monitoring/digitalkin_observability/prometheus.py +137 -0
  111. monitoring/tests/test_metrics.py +172 -0
  112. services/filesystem_module.py +7 -5
  113. services/storage_module.py +4 -2
  114. digitalkin/grpc_servers/registry_server.py +0 -65
  115. digitalkin/grpc_servers/registry_servicer.py +0 -456
  116. digitalkin/grpc_servers/utils/factory.py +0 -180
  117. digitalkin/modules/job_manager/single_job_manager.py +0 -294
  118. digitalkin/modules/job_manager/taskiq_job_manager.py +0 -290
  119. digitalkin-0.2.25rc0.dist-info/RECORD +0 -89
  120. /digitalkin/{grpc_servers/utils → models/grpc_servers}/types.py +0 -0
  121. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/WHEEL +0 -0
  122. {digitalkin-0.2.25rc0.dist-info → digitalkin-0.3.2.dev14.dist-info}/licenses/LICENSE +0 -0
@@ -5,7 +5,7 @@ from contextlib import contextmanager
5
5
  from typing import Any
6
6
 
7
7
  import grpc
8
- from digitalkin_proto.digitalkin.setup.v2 import (
8
+ from agentic_mesh_protocol.setup.v1 import (
9
9
  setup_pb2,
10
10
  setup_service_pb2_grpc,
11
11
  )
@@ -15,8 +15,8 @@ from pydantic import ValidationError
15
15
 
16
16
  from digitalkin.grpc_servers.utils.exceptions import ServerError
17
17
  from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
18
- from digitalkin.grpc_servers.utils.models import ClientConfig
19
18
  from digitalkin.logger import logger
19
+ from digitalkin.models.grpc_servers.models import ClientConfig
20
20
  from digitalkin.services.setup.setup_strategy import SetupData, SetupServiceError, SetupStrategy, SetupVersionData
21
21
 
22
22
 
@@ -30,10 +30,10 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
30
30
  """
31
31
  channel = self._init_channel(config)
32
32
  self.stub = setup_service_pb2_grpc.SetupServiceStub(channel)
33
- logger.debug("Channel client 'setup' initialized succesfully")
33
+ logger.debug("Channel client 'setup' initialized successfully")
34
34
 
35
35
  @contextmanager
36
- def _handle_grpc_errors(self, operation: str) -> Generator[Any, Any, Any]: # noqa: PLR6301
36
+ def handle_grpc_errors(self, operation: str) -> Generator[Any, Any, Any]: # noqa: PLR6301
37
37
  """Context manager for consistent gRPC error handling.
38
38
 
39
39
  Yields:
@@ -76,7 +76,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
76
76
  ServerError: If gRPC operation fails.
77
77
  SetupServiceError: For any unexpected internal error.
78
78
  """
79
- with self._handle_grpc_errors("Setup Creation"):
79
+ with self.handle_grpc_errors("Setup Creation"):
80
80
  valid_data = SetupData.model_validate(setup_dict)
81
81
 
82
82
  request = setup_pb2.CreateSetupRequest(
@@ -104,7 +104,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
104
104
  ServerError: If gRPC operation fails.
105
105
  SetupServiceError: For any unexpected internal error.
106
106
  """
107
- with self._handle_grpc_errors("Get Setup"):
107
+ with self.handle_grpc_errors("Get Setup"):
108
108
  if "setup_id" not in setup_dict:
109
109
  msg = "Setup name is required"
110
110
  raise ValidationError(msg)
@@ -132,7 +132,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
132
132
  """
133
133
  current_setup_version = None
134
134
 
135
- with self._handle_grpc_errors("Setup Update"):
135
+ with self.handle_grpc_errors("Setup Update"):
136
136
  valid_data = SetupData.model_validate(setup_dict)
137
137
 
138
138
  if valid_data.current_setup_version is not None:
@@ -162,7 +162,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
162
162
  ServerError: If gRPC operation fails.
163
163
  SetupServiceError: For any unexpected internal error.
164
164
  """
165
- with self._handle_grpc_errors("Setup Deletion"):
165
+ with self.handle_grpc_errors("Setup Deletion"):
166
166
  setup_id = setup_dict.get("setup_id")
167
167
  if not setup_id:
168
168
  msg = "Setup name is required for deletion"
@@ -186,7 +186,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
186
186
  ServerError: If gRPC operation fails.
187
187
  SetupServiceError: For any unexpected internal error.
188
188
  """
189
- with self._handle_grpc_errors("Setup Version Creation"):
189
+ with self.handle_grpc_errors("Setup Version Creation"):
190
190
  valid_data = SetupVersionData.model_validate(setup_version_dict)
191
191
  content_struct = Struct()
192
192
  content_struct.update(valid_data.content)
@@ -216,14 +216,16 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
216
216
  ServerError: If gRPC operation fails.
217
217
  SetupServiceError: For any unexpected internal error.
218
218
  """
219
- with self._handle_grpc_errors("Get Setup Version"):
219
+ with self.handle_grpc_errors("Get Setup Version"):
220
220
  setup_version_id = setup_version_dict.get("setup_version_id")
221
221
  if not setup_version_id:
222
222
  msg = "Setup version id is required"
223
223
  raise ValidationError(msg)
224
224
  request = setup_pb2.GetSetupVersionRequest(setup_version_id=setup_version_id)
225
225
  response = self.exec_grpc_query("GetSetupVersion", request)
226
- return SetupVersionData(**json_format.MessageToDict(response.setup_version))
226
+ return SetupVersionData(
227
+ **json_format.MessageToDict(response.setup_version, preserving_proto_field_name=True)
228
+ )
227
229
 
228
230
  def search_setup_versions(self, setup_version_dict: dict[str, Any]) -> list[SetupVersionData]:
229
231
  """Search for setup versions based on filters.
@@ -239,7 +241,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
239
241
  SetupServiceError: For any unexpected internal error.
240
242
  ValidationError: If both name and version are not provided.
241
243
  """
242
- with self._handle_grpc_errors("Search Setup Versions"):
244
+ with self.handle_grpc_errors("Search Setup Versions"):
243
245
  if "name" not in setup_version_dict and "version" not in setup_version_dict:
244
246
  msg = "Either name or version must be provided"
245
247
  raise ValidationError(msg)
@@ -248,7 +250,10 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
248
250
  version=setup_version_dict.get("version", ""),
249
251
  )
250
252
  response = self.exec_grpc_query("SearchSetupVersions", request)
251
- return [SetupVersionData(**json_format.MessageToDict(sv)) for sv in response.setup_versions]
253
+ return [
254
+ SetupVersionData(**json_format.MessageToDict(sv, preserving_proto_field_name=True))
255
+ for sv in response.setup_versions
256
+ ]
252
257
 
253
258
  def update_setup_version(self, setup_version_dict: dict[str, Any]) -> bool:
254
259
  """Update an existing setup version.
@@ -264,7 +269,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
264
269
  ServerError: If gRPC operation fails.
265
270
  SetupServiceError: For any unexpected internal error.
266
271
  """
267
- with self._handle_grpc_errors("Setup Version Update"):
272
+ with self.handle_grpc_errors("Setup Version Update"):
268
273
  valid_data = SetupVersionData.model_validate(setup_version_dict)
269
274
  content_struct = Struct()
270
275
  content_struct.update(valid_data.content)
@@ -295,7 +300,7 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
295
300
  ServerError: If gRPC operation fails.
296
301
  SetupServiceError: For any unexpected internal error.
297
302
  """
298
- with self._handle_grpc_errors("Setup Version Deletion"):
303
+ with self.handle_grpc_errors("Setup Version Deletion"):
299
304
  setup_version_id = setup_version_dict.get("setup_version_id")
300
305
  if not setup_version_id:
301
306
  msg = "Setup version id is required for deletion"
@@ -304,3 +309,35 @@ class GrpcSetup(SetupStrategy, GrpcClientWrapper):
304
309
  response = self.exec_grpc_query("DeleteSetupVersion", request)
305
310
  logger.debug("Setup Version '%s' query sent successfully", setup_version_id)
306
311
  return getattr(response, "success", False)
312
+
313
+ def list_setups(self, list_dict: dict[str, Any]) -> dict[str, Any]:
314
+ """List setups with optional filtering and pagination.
315
+
316
+ Args:
317
+ list_dict: Dictionary with optional filters:
318
+ - organisation_id: Filter by organisation
319
+ - owner_id: Filter by owner
320
+ - limit: Maximum number of results
321
+ - offset: Number of results to skip
322
+
323
+ Returns:
324
+ dict[str, Any]: Dictionary with 'setups' list and 'total_count'.
325
+
326
+ Raises:
327
+ ServerError: If gRPC operation fails.
328
+ SetupServiceError: For any unexpected internal error.
329
+ """
330
+ with self.handle_grpc_errors("List Setups"):
331
+ request = setup_pb2.ListSetupsRequest(
332
+ organisation_id=list_dict.get("organisation_id", ""),
333
+ owner_id=list_dict.get("owner_id", ""),
334
+ limit=list_dict.get("limit", 0),
335
+ offset=list_dict.get("offset", 0),
336
+ )
337
+ response = self.exec_grpc_query("ListSetups", request)
338
+ return {
339
+ "setups": [
340
+ json_format.MessageToDict(setup, preserving_proto_field_name=True) for setup in response.setups
341
+ ],
342
+ "total_count": response.total_count,
343
+ }
@@ -1,13 +1,13 @@
1
1
  """This module implements the default storage strategy."""
2
2
 
3
- from digitalkin_proto.digitalkin.storage.v2 import data_pb2, storage_service_pb2_grpc
3
+ from agentic_mesh_protocol.storage.v1 import data_pb2, storage_service_pb2_grpc
4
4
  from google.protobuf import json_format
5
5
  from google.protobuf.struct_pb2 import Struct
6
6
  from pydantic import BaseModel
7
7
 
8
8
  from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
9
- from digitalkin.grpc_servers.utils.models import ClientConfig
10
9
  from digitalkin.logger import logger
10
+ from digitalkin.models.grpc_servers.models import ClientConfig
11
11
  from digitalkin.services.storage.storage_strategy import (
12
12
  DataType,
13
13
  StorageRecord,
@@ -128,7 +128,7 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
128
128
  resp = self.exec_grpc_query("UpdateRecord", req)
129
129
  return self._build_record_from_proto(resp.stored_data)
130
130
  except Exception:
131
- logger.exception("gRPC UpdateRecord failed for %s:%s", collection, record_id)
131
+ logger.warning("gRPC UpdateRecord failed for %s:%s", collection, record_id)
132
132
  return None
133
133
 
134
134
  def _remove(self, collection: str, record_id: str) -> bool:
@@ -211,4 +211,4 @@ class GrpcStorage(StorageStrategy, GrpcClientWrapper):
211
211
 
212
212
  channel = self._init_channel(client_config)
213
213
  self.stub = storage_service_pb2_grpc.StorageServiceStub(channel)
214
- logger.debug("Channel client 'storage' initialized succesfully")
214
+ logger.debug("Channel client 'storage' initialized successfully")
@@ -0,0 +1,12 @@
1
+ """UserProfile service package."""
2
+
3
+ from digitalkin.services.user_profile.default_user_profile import DefaultUserProfile
4
+ from digitalkin.services.user_profile.grpc_user_profile import GrpcUserProfile
5
+ from digitalkin.services.user_profile.user_profile_strategy import UserProfileServiceError, UserProfileStrategy
6
+
7
+ __all__ = [
8
+ "DefaultUserProfile",
9
+ "GrpcUserProfile",
10
+ "UserProfileServiceError",
11
+ "UserProfileStrategy",
12
+ ]
@@ -0,0 +1,55 @@
1
+ """Default user profile implementation."""
2
+
3
+ from typing import Any
4
+
5
+ from digitalkin.logger import logger
6
+ from digitalkin.services.user_profile.user_profile_strategy import (
7
+ UserProfileServiceError,
8
+ UserProfileStrategy,
9
+ )
10
+
11
+
12
+ class DefaultUserProfile(UserProfileStrategy):
13
+ """Default user profile strategy with in-memory storage."""
14
+
15
+ def __init__(
16
+ self,
17
+ mission_id: str,
18
+ setup_id: str,
19
+ setup_version_id: str,
20
+ ) -> None:
21
+ """Initialize the strategy.
22
+
23
+ Args:
24
+ mission_id: The ID of the mission this strategy is associated with
25
+ setup_id: The ID of the setup
26
+ setup_version_id: The ID of the setup version
27
+ """
28
+ super().__init__(mission_id=mission_id, setup_id=setup_id, setup_version_id=setup_version_id)
29
+ self.db: dict[str, dict[str, Any]] = {}
30
+
31
+ def get_user_profile(self) -> dict[str, Any]:
32
+ """Get user profile from in-memory storage.
33
+
34
+ Returns:
35
+ dict[str, Any]: User profile data
36
+
37
+ Raises:
38
+ UserProfileServiceError: If the user profile is not found
39
+ """
40
+ if self.mission_id not in self.db:
41
+ msg = f"User profile for mission {self.mission_id} not found in the database."
42
+ logger.warning(msg)
43
+ raise UserProfileServiceError(msg)
44
+
45
+ logger.debug(f"Retrieved user profile for mission_id: {self.mission_id}")
46
+ return self.db[self.mission_id]
47
+
48
+ def add_user_profile(self, user_profile_data: dict[str, Any]) -> None:
49
+ """Add a user profile to the in-memory database (helper for testing).
50
+
51
+ Args:
52
+ user_profile_data: Dictionary containing user profile data
53
+ """
54
+ self.db[self.mission_id] = user_profile_data
55
+ logger.debug(f"Added user profile for mission_id: {self.mission_id}")
@@ -0,0 +1,69 @@
1
+ """Digital Kin UserProfile Service gRPC Client."""
2
+
3
+ from typing import Any
4
+
5
+ from agentic_mesh_protocol.user_profile.v1 import (
6
+ user_profile_pb2,
7
+ user_profile_service_pb2_grpc,
8
+ )
9
+ from google.protobuf import json_format
10
+
11
+ from digitalkin.grpc_servers.utils.grpc_client_wrapper import GrpcClientWrapper
12
+ from digitalkin.grpc_servers.utils.grpc_error_handler import GrpcErrorHandlerMixin
13
+ from digitalkin.logger import logger
14
+ from digitalkin.models.grpc_servers.models import ClientConfig
15
+ from digitalkin.services.user_profile.user_profile_strategy import UserProfileServiceError, UserProfileStrategy
16
+
17
+
18
+ class GrpcUserProfile(UserProfileStrategy, GrpcClientWrapper, GrpcErrorHandlerMixin):
19
+ """This class implements the gRPC user profile service."""
20
+
21
+ def __init__(
22
+ self,
23
+ mission_id: str,
24
+ setup_id: str,
25
+ setup_version_id: str,
26
+ client_config: ClientConfig,
27
+ ) -> None:
28
+ """Initialize the user profile service.
29
+
30
+ Args:
31
+ mission_id: The ID of the mission this strategy is associated with
32
+ setup_id: The ID of the setup
33
+ setup_version_id: The ID of the setup version
34
+ client_config: Client configuration for gRPC connection
35
+ """
36
+ super().__init__(mission_id=mission_id, setup_id=setup_id, setup_version_id=setup_version_id)
37
+ channel = self._init_channel(client_config)
38
+ self.stub = user_profile_service_pb2_grpc.UserProfileServiceStub(channel)
39
+ logger.debug("Channel client 'UserProfile' initialized successfully")
40
+
41
+ def get_user_profile(self) -> dict[str, Any]:
42
+ """Get user profile by mission_id (which maps to user_id).
43
+
44
+ Returns:
45
+ dict[str, Any]: User profile data
46
+
47
+ Raises:
48
+ UserProfileServiceError: If the user profile cannot be retrieved
49
+ ServerError: If gRPC operation fails
50
+ """
51
+ with self.handle_grpc_errors("GetUserProfile", UserProfileServiceError):
52
+ # mission_id typically contains user context
53
+ request = user_profile_pb2.GetUserProfileRequest(mission_id=self.mission_id)
54
+ response = self.exec_grpc_query("GetUserProfile", request)
55
+
56
+ if not response.success:
57
+ msg = f"Failed to get user profile for mission_id: {self.mission_id}"
58
+ logger.error(msg)
59
+ raise UserProfileServiceError(msg)
60
+
61
+ # Convert proto to dict
62
+ user_profile_dict = json_format.MessageToDict(
63
+ response.user_profile,
64
+ preserving_proto_field_name=True,
65
+ always_print_fields_with_no_presence=True,
66
+ )
67
+
68
+ logger.debug(f"Retrieved user profile for mission_id: {self.mission_id}")
69
+ return user_profile_dict
@@ -0,0 +1,25 @@
1
+ """This module contains the abstract base class for UserProfile strategies."""
2
+
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any
5
+
6
+ from digitalkin.services.base_strategy import BaseStrategy
7
+
8
+
9
+ class UserProfileServiceError(Exception):
10
+ """Base exception for UserProfile service errors."""
11
+
12
+
13
+ class UserProfileStrategy(BaseStrategy, ABC):
14
+ """Abstract base class for UserProfile strategies."""
15
+
16
+ @abstractmethod
17
+ def get_user_profile(self) -> dict[str, Any]:
18
+ """Get user profile data.
19
+
20
+ Returns:
21
+ dict[str, Any]: User profile data
22
+
23
+ Raises:
24
+ UserProfileServiceError: If the user profile cannot be retrieved
25
+ """
@@ -1 +1,29 @@
1
1
  """General utils folder."""
2
+
3
+ from digitalkin.utils.dynamic_schema import (
4
+ DEFAULT_TIMEOUT,
5
+ DynamicField,
6
+ Fetcher,
7
+ ResolveResult,
8
+ get_dynamic_metadata,
9
+ get_fetchers,
10
+ has_dynamic,
11
+ resolve,
12
+ resolve_safe,
13
+ )
14
+
15
+ # Alias for cleaner API: `Dynamic` is shorter than `DynamicField`
16
+ Dynamic = DynamicField
17
+
18
+ __all__ = [
19
+ "DEFAULT_TIMEOUT",
20
+ "Dynamic",
21
+ "DynamicField",
22
+ "Fetcher",
23
+ "ResolveResult",
24
+ "get_dynamic_metadata",
25
+ "get_fetchers",
26
+ "has_dynamic",
27
+ "resolve",
28
+ "resolve_safe",
29
+ ]
@@ -55,7 +55,7 @@ class ArgParser:
55
55
  """
56
56
 
57
57
  class HelpAction(_HelpAction):
58
- """."""
58
+ """Custom HelpAction to display subparsers helps too."""
59
59
 
60
60
  def __call__(
61
61
  self,
@@ -13,7 +13,7 @@ logger.setLevel(logging.INFO)
13
13
 
14
14
 
15
15
  class DevelopmentModeMappingAction(Action):
16
- """."""
16
+ """ArgParse Action to map an environment variable to a ServicesMode enum."""
17
17
 
18
18
  def __init__(
19
19
  self,
@@ -22,7 +22,7 @@ class DevelopmentModeMappingAction(Action):
22
22
  default: str | None = None,
23
23
  **kwargs: dict[str, Any],
24
24
  ) -> None:
25
- """."""
25
+ """Initialize the DevelopmentModeMappingAction."""
26
26
  default = ServicesMode(os.environ.get(env_var, default))
27
27
 
28
28
  if required and default: