durabletask 0.0.0.dev60__tar.gz → 0.0.0.dev62__tar.gz
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.
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/PKG-INFO +1 -1
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/client.py +11 -191
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/entities/__init__.py +1 -3
- durabletask-0.0.0.dev62/durabletask/entities/entity_instance_id.py +42 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/entities/entity_metadata.py +5 -9
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/helpers.py +0 -7
- durabletask-0.0.0.dev62/durabletask/internal/orchestrator_service_pb2.py +270 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/orchestrator_service_pb2.pyi +22 -186
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/orchestrator_service_pb2_grpc.py +0 -132
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/proto_task_hub_sidecar_service_stub.py +0 -3
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/task.py +2 -1
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/worker.py +20 -57
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask.egg-info/PKG-INFO +1 -1
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask.egg-info/SOURCES.txt +0 -2
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/pyproject.toml +1 -1
- durabletask-0.0.0.dev60/durabletask/entities/entity_instance_id.py +0 -84
- durabletask-0.0.0.dev60/durabletask/entities/entity_operation_failed_exception.py +0 -15
- durabletask-0.0.0.dev60/durabletask/internal/json_encode_output_exception.py +0 -12
- durabletask-0.0.0.dev60/durabletask/internal/orchestrator_service_pb2.py +0 -312
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/LICENSE +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/README.md +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/__init__.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/entities/durable_entity.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/entities/entity_context.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/entities/entity_lock.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/entity_state_shim.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/exceptions.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/grpc_interceptor.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/orchestration_entity_context.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/internal/shared.py +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask/py.typed +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask.egg-info/dependency_links.txt +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask.egg-info/requires.txt +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/durabletask.egg-info/top_level.txt +0 -0
- {durabletask-0.0.0.dev60 → durabletask-0.0.0.dev62}/setup.cfg +0 -0
|
@@ -6,9 +6,10 @@ import uuid
|
|
|
6
6
|
from dataclasses import dataclass
|
|
7
7
|
from datetime import datetime, timezone
|
|
8
8
|
from enum import Enum
|
|
9
|
-
from typing import Any,
|
|
9
|
+
from typing import Any, Optional, Sequence, TypeVar, Union
|
|
10
10
|
|
|
11
11
|
import grpc
|
|
12
|
+
from google.protobuf import wrappers_pb2
|
|
12
13
|
|
|
13
14
|
from durabletask.entities import EntityInstanceId
|
|
14
15
|
from durabletask.entities.entity_metadata import EntityMetadata
|
|
@@ -56,39 +57,6 @@ class OrchestrationState:
|
|
|
56
57
|
self.failure_details)
|
|
57
58
|
|
|
58
59
|
|
|
59
|
-
@dataclass
|
|
60
|
-
class OrchestrationQuery:
|
|
61
|
-
created_time_from: Optional[datetime] = None
|
|
62
|
-
created_time_to: Optional[datetime] = None
|
|
63
|
-
runtime_status: Optional[List[OrchestrationStatus]] = None
|
|
64
|
-
# Some backends don't respond well with max_instance_count = None, so we use the integer limit for non-paginated
|
|
65
|
-
# results instead.
|
|
66
|
-
max_instance_count: Optional[int] = (1 << 31) - 1
|
|
67
|
-
fetch_inputs_and_outputs: bool = False
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
@dataclass
|
|
71
|
-
class EntityQuery:
|
|
72
|
-
instance_id_starts_with: Optional[str] = None
|
|
73
|
-
last_modified_from: Optional[datetime] = None
|
|
74
|
-
last_modified_to: Optional[datetime] = None
|
|
75
|
-
include_state: bool = True
|
|
76
|
-
include_transient: bool = False
|
|
77
|
-
page_size: Optional[int] = None
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
@dataclass
|
|
81
|
-
class PurgeInstancesResult:
|
|
82
|
-
deleted_instance_count: int
|
|
83
|
-
is_complete: bool
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
@dataclass
|
|
87
|
-
class CleanEntityStorageResult:
|
|
88
|
-
empty_entities_removed: int
|
|
89
|
-
orphaned_locks_released: int
|
|
90
|
-
|
|
91
|
-
|
|
92
60
|
class OrchestrationFailedError(Exception):
|
|
93
61
|
def __init__(self, message: str, failure_details: task.FailureDetails):
|
|
94
62
|
super().__init__(message)
|
|
@@ -105,12 +73,6 @@ def new_orchestration_state(instance_id: str, res: pb.GetInstanceResponse) -> Op
|
|
|
105
73
|
|
|
106
74
|
state = res.orchestrationState
|
|
107
75
|
|
|
108
|
-
new_state = parse_orchestration_state(state)
|
|
109
|
-
new_state.instance_id = instance_id # Override instance_id with the one from the request, to match old behavior
|
|
110
|
-
return new_state
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
def parse_orchestration_state(state: pb.OrchestrationState) -> OrchestrationState:
|
|
114
76
|
failure_details = None
|
|
115
77
|
if state.failureDetails.errorMessage != '' or state.failureDetails.errorType != '':
|
|
116
78
|
failure_details = task.FailureDetails(
|
|
@@ -119,7 +81,7 @@ def parse_orchestration_state(state: pb.OrchestrationState) -> OrchestrationStat
|
|
|
119
81
|
state.failureDetails.stackTrace.value if not helpers.is_empty(state.failureDetails.stackTrace) else None)
|
|
120
82
|
|
|
121
83
|
return OrchestrationState(
|
|
122
|
-
|
|
84
|
+
instance_id,
|
|
123
85
|
state.name,
|
|
124
86
|
OrchestrationStatus(state.orchestrationStatus),
|
|
125
87
|
state.createdTimestamp.ToDatetime(),
|
|
@@ -131,6 +93,7 @@ def parse_orchestration_state(state: pb.OrchestrationState) -> OrchestrationStat
|
|
|
131
93
|
|
|
132
94
|
|
|
133
95
|
class TaskHubGrpcClient:
|
|
96
|
+
|
|
134
97
|
def __init__(self, *,
|
|
135
98
|
host_address: Optional[str] = None,
|
|
136
99
|
metadata: Optional[list[tuple[str, str]]] = None,
|
|
@@ -173,7 +136,7 @@ class TaskHubGrpcClient:
|
|
|
173
136
|
req = pb.CreateInstanceRequest(
|
|
174
137
|
name=name,
|
|
175
138
|
instanceId=instance_id if instance_id else uuid.uuid4().hex,
|
|
176
|
-
input=
|
|
139
|
+
input=wrappers_pb2.StringValue(value=shared.to_json(input)) if input is not None else None,
|
|
177
140
|
scheduledStartTimestamp=helpers.new_timestamp(start_at) if start_at else None,
|
|
178
141
|
version=helpers.get_string_value(version if version else self.default_version),
|
|
179
142
|
orchestrationIdReusePolicy=reuse_id_policy,
|
|
@@ -189,42 +152,6 @@ class TaskHubGrpcClient:
|
|
|
189
152
|
res: pb.GetInstanceResponse = self._stub.GetInstance(req)
|
|
190
153
|
return new_orchestration_state(req.instanceId, res)
|
|
191
154
|
|
|
192
|
-
def get_all_orchestration_states(self,
|
|
193
|
-
orchestration_query: Optional[OrchestrationQuery] = None
|
|
194
|
-
) -> List[OrchestrationState]:
|
|
195
|
-
if orchestration_query is None:
|
|
196
|
-
orchestration_query = OrchestrationQuery()
|
|
197
|
-
_continuation_token = None
|
|
198
|
-
|
|
199
|
-
self._logger.info(f"Querying orchestration instances with query: {orchestration_query}")
|
|
200
|
-
|
|
201
|
-
states = []
|
|
202
|
-
|
|
203
|
-
while True:
|
|
204
|
-
req = pb.QueryInstancesRequest(
|
|
205
|
-
query=pb.InstanceQuery(
|
|
206
|
-
runtimeStatus=[status.value for status in orchestration_query.runtime_status] if orchestration_query.runtime_status else None,
|
|
207
|
-
createdTimeFrom=helpers.new_timestamp(orchestration_query.created_time_from) if orchestration_query.created_time_from else None,
|
|
208
|
-
createdTimeTo=helpers.new_timestamp(orchestration_query.created_time_to) if orchestration_query.created_time_to else None,
|
|
209
|
-
maxInstanceCount=orchestration_query.max_instance_count,
|
|
210
|
-
fetchInputsAndOutputs=orchestration_query.fetch_inputs_and_outputs,
|
|
211
|
-
continuationToken=_continuation_token
|
|
212
|
-
)
|
|
213
|
-
)
|
|
214
|
-
resp: pb.QueryInstancesResponse = self._stub.QueryInstances(req)
|
|
215
|
-
states += [parse_orchestration_state(res) for res in resp.orchestrationState]
|
|
216
|
-
# Check the value for continuationToken - none or "0" indicates that there are no more results.
|
|
217
|
-
if resp.continuationToken and resp.continuationToken.value and resp.continuationToken.value != "0":
|
|
218
|
-
self._logger.info(f"Received continuation token with value {resp.continuationToken.value}, fetching next list of instances...")
|
|
219
|
-
if _continuation_token and _continuation_token.value and _continuation_token.value == resp.continuationToken.value:
|
|
220
|
-
self._logger.warning(f"Received the same continuation token value {resp.continuationToken.value} again, stopping to avoid infinite loop.")
|
|
221
|
-
break
|
|
222
|
-
_continuation_token = resp.continuationToken
|
|
223
|
-
else:
|
|
224
|
-
break
|
|
225
|
-
|
|
226
|
-
return states
|
|
227
|
-
|
|
228
155
|
def wait_for_orchestration_start(self, instance_id: str, *,
|
|
229
156
|
fetch_payloads: bool = False,
|
|
230
157
|
timeout: int = 60) -> Optional[OrchestrationState]:
|
|
@@ -272,8 +199,7 @@ class TaskHubGrpcClient:
|
|
|
272
199
|
req = pb.RaiseEventRequest(
|
|
273
200
|
instanceId=instance_id,
|
|
274
201
|
name=event_name,
|
|
275
|
-
input=
|
|
276
|
-
)
|
|
202
|
+
input=wrappers_pb2.StringValue(value=shared.to_json(data)) if data else None)
|
|
277
203
|
|
|
278
204
|
self._logger.info(f"Raising event '{event_name}' for instance '{instance_id}'.")
|
|
279
205
|
self._stub.RaiseEvent(req)
|
|
@@ -283,7 +209,7 @@ class TaskHubGrpcClient:
|
|
|
283
209
|
recursive: bool = True):
|
|
284
210
|
req = pb.TerminateRequest(
|
|
285
211
|
instanceId=instance_id,
|
|
286
|
-
output=
|
|
212
|
+
output=wrappers_pb2.StringValue(value=shared.to_json(output)) if output else None,
|
|
287
213
|
recursive=recursive)
|
|
288
214
|
|
|
289
215
|
self._logger.info(f"Terminating instance '{instance_id}'.")
|
|
@@ -299,51 +225,10 @@ class TaskHubGrpcClient:
|
|
|
299
225
|
self._logger.info(f"Resuming instance '{instance_id}'.")
|
|
300
226
|
self._stub.ResumeInstance(req)
|
|
301
227
|
|
|
302
|
-
def
|
|
303
|
-
restart_with_new_instance_id: bool = False) -> str:
|
|
304
|
-
"""Restarts an existing orchestration instance.
|
|
305
|
-
|
|
306
|
-
Args:
|
|
307
|
-
instance_id: The ID of the orchestration instance to restart.
|
|
308
|
-
restart_with_new_instance_id: If True, the restarted orchestration will use a new instance ID.
|
|
309
|
-
If False (default), the restarted orchestration will reuse the same instance ID.
|
|
310
|
-
|
|
311
|
-
Returns:
|
|
312
|
-
The instance ID of the restarted orchestration.
|
|
313
|
-
"""
|
|
314
|
-
req = pb.RestartInstanceRequest(
|
|
315
|
-
instanceId=instance_id,
|
|
316
|
-
restartWithNewInstanceId=restart_with_new_instance_id)
|
|
317
|
-
|
|
318
|
-
self._logger.info(f"Restarting instance '{instance_id}'.")
|
|
319
|
-
res: pb.RestartInstanceResponse = self._stub.RestartInstance(req)
|
|
320
|
-
return res.instanceId
|
|
321
|
-
|
|
322
|
-
def purge_orchestration(self, instance_id: str, recursive: bool = True) -> PurgeInstancesResult:
|
|
228
|
+
def purge_orchestration(self, instance_id: str, recursive: bool = True):
|
|
323
229
|
req = pb.PurgeInstancesRequest(instanceId=instance_id, recursive=recursive)
|
|
324
230
|
self._logger.info(f"Purging instance '{instance_id}'.")
|
|
325
|
-
|
|
326
|
-
return PurgeInstancesResult(resp.deletedInstanceCount, resp.isComplete.value)
|
|
327
|
-
|
|
328
|
-
def purge_orchestrations_by(self,
|
|
329
|
-
created_time_from: Optional[datetime] = None,
|
|
330
|
-
created_time_to: Optional[datetime] = None,
|
|
331
|
-
runtime_status: Optional[List[OrchestrationStatus]] = None,
|
|
332
|
-
recursive: bool = False) -> PurgeInstancesResult:
|
|
333
|
-
self._logger.info("Purging orchestrations by filter: "
|
|
334
|
-
f"created_time_from={created_time_from}, "
|
|
335
|
-
f"created_time_to={created_time_to}, "
|
|
336
|
-
f"runtime_status={[str(status) for status in runtime_status] if runtime_status else None}, "
|
|
337
|
-
f"recursive={recursive}")
|
|
338
|
-
resp: pb.PurgeInstancesResponse = self._stub.PurgeInstances(pb.PurgeInstancesRequest(
|
|
339
|
-
purgeInstanceFilter=pb.PurgeInstanceFilter(
|
|
340
|
-
createdTimeFrom=helpers.new_timestamp(created_time_from) if created_time_from else None,
|
|
341
|
-
createdTimeTo=helpers.new_timestamp(created_time_to) if created_time_to else None,
|
|
342
|
-
runtimeStatus=[status.value for status in runtime_status] if runtime_status else None
|
|
343
|
-
),
|
|
344
|
-
recursive=recursive
|
|
345
|
-
))
|
|
346
|
-
return PurgeInstancesResult(resp.deletedInstanceCount, resp.isComplete.value)
|
|
231
|
+
self._stub.PurgeInstances(req)
|
|
347
232
|
|
|
348
233
|
def signal_entity(self,
|
|
349
234
|
entity_instance_id: EntityInstanceId,
|
|
@@ -352,7 +237,7 @@ class TaskHubGrpcClient:
|
|
|
352
237
|
req = pb.SignalEntityRequest(
|
|
353
238
|
instanceId=str(entity_instance_id),
|
|
354
239
|
name=operation_name,
|
|
355
|
-
input=
|
|
240
|
+
input=wrappers_pb2.StringValue(value=shared.to_json(input)) if input else None,
|
|
356
241
|
requestId=str(uuid.uuid4()),
|
|
357
242
|
scheduledTime=None,
|
|
358
243
|
parentTraceContext=None,
|
|
@@ -371,69 +256,4 @@ class TaskHubGrpcClient:
|
|
|
371
256
|
if not res.exists:
|
|
372
257
|
return None
|
|
373
258
|
|
|
374
|
-
return EntityMetadata.
|
|
375
|
-
|
|
376
|
-
def get_all_entities(self,
|
|
377
|
-
entity_query: Optional[EntityQuery] = None) -> List[EntityMetadata]:
|
|
378
|
-
if entity_query is None:
|
|
379
|
-
entity_query = EntityQuery()
|
|
380
|
-
_continuation_token = None
|
|
381
|
-
|
|
382
|
-
self._logger.info(f"Retrieving entities by filter: {entity_query}")
|
|
383
|
-
|
|
384
|
-
entities = []
|
|
385
|
-
|
|
386
|
-
while True:
|
|
387
|
-
query_request = pb.QueryEntitiesRequest(
|
|
388
|
-
query=pb.EntityQuery(
|
|
389
|
-
instanceIdStartsWith=helpers.get_string_value(entity_query.instance_id_starts_with),
|
|
390
|
-
lastModifiedFrom=helpers.new_timestamp(entity_query.last_modified_from) if entity_query.last_modified_from else None,
|
|
391
|
-
lastModifiedTo=helpers.new_timestamp(entity_query.last_modified_to) if entity_query.last_modified_to else None,
|
|
392
|
-
includeState=entity_query.include_state,
|
|
393
|
-
includeTransient=entity_query.include_transient,
|
|
394
|
-
pageSize=helpers.get_int_value(entity_query.page_size),
|
|
395
|
-
continuationToken=_continuation_token
|
|
396
|
-
)
|
|
397
|
-
)
|
|
398
|
-
resp: pb.QueryEntitiesResponse = self._stub.QueryEntities(query_request)
|
|
399
|
-
entities += [EntityMetadata.from_entity_metadata(entity, query_request.query.includeState) for entity in resp.entities]
|
|
400
|
-
if resp.continuationToken and resp.continuationToken.value and resp.continuationToken.value != "0":
|
|
401
|
-
self._logger.info(f"Received continuation token with value {resp.continuationToken.value}, fetching next page of entities...")
|
|
402
|
-
if _continuation_token and _continuation_token.value and _continuation_token.value == resp.continuationToken.value:
|
|
403
|
-
self._logger.warning(f"Received the same continuation token value {resp.continuationToken.value} again, stopping to avoid infinite loop.")
|
|
404
|
-
break
|
|
405
|
-
_continuation_token = resp.continuationToken
|
|
406
|
-
else:
|
|
407
|
-
break
|
|
408
|
-
return entities
|
|
409
|
-
|
|
410
|
-
def clean_entity_storage(self,
|
|
411
|
-
remove_empty_entities: bool = True,
|
|
412
|
-
release_orphaned_locks: bool = True
|
|
413
|
-
) -> CleanEntityStorageResult:
|
|
414
|
-
self._logger.info("Cleaning entity storage")
|
|
415
|
-
|
|
416
|
-
empty_entities_removed = 0
|
|
417
|
-
orphaned_locks_released = 0
|
|
418
|
-
_continuation_token = None
|
|
419
|
-
|
|
420
|
-
while True:
|
|
421
|
-
req = pb.CleanEntityStorageRequest(
|
|
422
|
-
removeEmptyEntities=remove_empty_entities,
|
|
423
|
-
releaseOrphanedLocks=release_orphaned_locks,
|
|
424
|
-
continuationToken=_continuation_token
|
|
425
|
-
)
|
|
426
|
-
resp: pb.CleanEntityStorageResponse = self._stub.CleanEntityStorage(req)
|
|
427
|
-
empty_entities_removed += resp.emptyEntitiesRemoved
|
|
428
|
-
orphaned_locks_released += resp.orphanedLocksReleased
|
|
429
|
-
|
|
430
|
-
if resp.continuationToken and resp.continuationToken.value and resp.continuationToken.value != "0":
|
|
431
|
-
self._logger.info(f"Received continuation token with value {resp.continuationToken.value}, cleaning next page...")
|
|
432
|
-
if _continuation_token and _continuation_token.value and _continuation_token.value == resp.continuationToken.value:
|
|
433
|
-
self._logger.warning(f"Received the same continuation token value {resp.continuationToken.value} again, stopping to avoid infinite loop.")
|
|
434
|
-
break
|
|
435
|
-
_continuation_token = resp.continuationToken
|
|
436
|
-
else:
|
|
437
|
-
break
|
|
438
|
-
|
|
439
|
-
return CleanEntityStorageResult(empty_entities_removed, orphaned_locks_released)
|
|
259
|
+
return EntityMetadata.from_entity_response(res, include_state)
|
|
@@ -8,9 +8,7 @@ from durabletask.entities.durable_entity import DurableEntity
|
|
|
8
8
|
from durabletask.entities.entity_lock import EntityLock
|
|
9
9
|
from durabletask.entities.entity_context import EntityContext
|
|
10
10
|
from durabletask.entities.entity_metadata import EntityMetadata
|
|
11
|
-
from durabletask.entities.entity_operation_failed_exception import EntityOperationFailedException
|
|
12
11
|
|
|
13
|
-
__all__ = ["EntityInstanceId", "DurableEntity", "EntityLock", "EntityContext", "EntityMetadata"
|
|
14
|
-
"EntityOperationFailedException"]
|
|
12
|
+
__all__ = ["EntityInstanceId", "DurableEntity", "EntityLock", "EntityContext", "EntityMetadata"]
|
|
15
13
|
|
|
16
14
|
PACKAGE_NAME = "durabletask.entities"
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
class EntityInstanceId:
|
|
2
|
+
def __init__(self, entity: str, key: str):
|
|
3
|
+
self.entity = entity
|
|
4
|
+
self.key = key
|
|
5
|
+
|
|
6
|
+
def __str__(self) -> str:
|
|
7
|
+
return f"@{self.entity}@{self.key}"
|
|
8
|
+
|
|
9
|
+
def __eq__(self, other):
|
|
10
|
+
if not isinstance(other, EntityInstanceId):
|
|
11
|
+
return False
|
|
12
|
+
return self.entity == other.entity and self.key == other.key
|
|
13
|
+
|
|
14
|
+
def __lt__(self, other):
|
|
15
|
+
if not isinstance(other, EntityInstanceId):
|
|
16
|
+
return self < other
|
|
17
|
+
return str(self) < str(other)
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def parse(entity_id: str) -> "EntityInstanceId":
|
|
21
|
+
"""Parse a string representation of an entity ID into an EntityInstanceId object.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
entity_id : str
|
|
26
|
+
The string representation of the entity ID, in the format '@entity@key'.
|
|
27
|
+
|
|
28
|
+
Returns
|
|
29
|
+
-------
|
|
30
|
+
EntityInstanceId
|
|
31
|
+
The parsed EntityInstanceId object.
|
|
32
|
+
|
|
33
|
+
Raises
|
|
34
|
+
------
|
|
35
|
+
ValueError
|
|
36
|
+
If the input string is not in the correct format.
|
|
37
|
+
"""
|
|
38
|
+
try:
|
|
39
|
+
_, entity, key = entity_id.split("@", 2)
|
|
40
|
+
return EntityInstanceId(entity=entity, key=key)
|
|
41
|
+
except ValueError as ex:
|
|
42
|
+
raise ValueError(f"Invalid entity ID format: {entity_id}", ex)
|
|
@@ -44,22 +44,18 @@ class EntityMetadata:
|
|
|
44
44
|
|
|
45
45
|
@staticmethod
|
|
46
46
|
def from_entity_response(entity_response: pb.GetEntityResponse, includes_state: bool):
|
|
47
|
-
return EntityMetadata.from_entity_metadata(entity_response.entity, includes_state)
|
|
48
|
-
|
|
49
|
-
@staticmethod
|
|
50
|
-
def from_entity_metadata(entity: pb.EntityMetadata, includes_state: bool):
|
|
51
47
|
try:
|
|
52
|
-
entity_id = EntityInstanceId.parse(entity.instanceId)
|
|
48
|
+
entity_id = EntityInstanceId.parse(entity_response.entity.instanceId)
|
|
53
49
|
except ValueError:
|
|
54
50
|
raise ValueError("Invalid entity instance ID in entity response.")
|
|
55
51
|
entity_state = None
|
|
56
52
|
if includes_state:
|
|
57
|
-
entity_state = entity.serializedState.value
|
|
53
|
+
entity_state = entity_response.entity.serializedState.value
|
|
58
54
|
return EntityMetadata(
|
|
59
55
|
id=entity_id,
|
|
60
|
-
last_modified=entity.lastModifiedTime.ToDatetime(timezone.utc),
|
|
61
|
-
backlog_queue_size=entity.backlogQueueSize,
|
|
62
|
-
locked_by=entity.lockedBy.value,
|
|
56
|
+
last_modified=entity_response.entity.lastModifiedTime.ToDatetime(timezone.utc),
|
|
57
|
+
backlog_queue_size=entity_response.entity.backlogQueueSize,
|
|
58
|
+
locked_by=entity_response.entity.lockedBy.value,
|
|
63
59
|
includes_state=includes_state,
|
|
64
60
|
state=entity_state
|
|
65
61
|
)
|
|
@@ -184,13 +184,6 @@ def get_string_value(val: Optional[str]) -> Optional[wrappers_pb2.StringValue]:
|
|
|
184
184
|
return wrappers_pb2.StringValue(value=val)
|
|
185
185
|
|
|
186
186
|
|
|
187
|
-
def get_int_value(val: Optional[int]) -> Optional[wrappers_pb2.Int32Value]:
|
|
188
|
-
if val is None:
|
|
189
|
-
return None
|
|
190
|
-
else:
|
|
191
|
-
return wrappers_pb2.Int32Value(value=val)
|
|
192
|
-
|
|
193
|
-
|
|
194
187
|
def get_string_value_or_empty(val: Optional[str]) -> wrappers_pb2.StringValue:
|
|
195
188
|
if val is None:
|
|
196
189
|
return wrappers_pb2.StringValue(value="")
|