durabletask 0.0.0.dev22__tar.gz → 0.0.0.dev23__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.
Files changed (32) hide show
  1. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/PKG-INFO +1 -1
  2. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/client.py +4 -6
  3. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/entities/durable_entity.py +1 -5
  4. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/entities/entity_context.py +1 -2
  5. durabletask-0.0.0.dev23/durabletask/entities/entity_instance_id.py +42 -0
  6. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/entities/entity_metadata.py +1 -1
  7. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/task.py +7 -15
  8. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/worker.py +24 -22
  9. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask.egg-info/PKG-INFO +1 -1
  10. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/pyproject.toml +1 -1
  11. durabletask-0.0.0.dev22/durabletask/entities/entity_instance_id.py +0 -89
  12. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/LICENSE +0 -0
  13. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/README.md +0 -0
  14. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/__init__.py +0 -0
  15. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/entities/__init__.py +0 -0
  16. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/entities/entity_lock.py +0 -0
  17. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/entity_state_shim.py +0 -0
  18. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/exceptions.py +0 -0
  19. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/grpc_interceptor.py +0 -0
  20. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/helpers.py +0 -0
  21. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/orchestration_entity_context.py +0 -0
  22. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/orchestrator_service_pb2.py +0 -0
  23. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/orchestrator_service_pb2.pyi +0 -0
  24. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/orchestrator_service_pb2_grpc.py +0 -0
  25. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/proto_task_hub_sidecar_service_stub.py +0 -0
  26. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/internal/shared.py +0 -0
  27. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask/py.typed +0 -0
  28. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask.egg-info/SOURCES.txt +0 -0
  29. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask.egg-info/dependency_links.txt +0 -0
  30. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask.egg-info/requires.txt +0 -0
  31. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/durabletask.egg-info/top_level.txt +0 -0
  32. {durabletask-0.0.0.dev22 → durabletask-0.0.0.dev23}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: durabletask
3
- Version: 0.0.0.dev22
3
+ Version: 0.0.0.dev23
4
4
  Summary: A Durable Task Client SDK for Python
5
5
  License: MIT License
6
6
 
@@ -11,7 +11,8 @@ from typing import Any, Optional, Sequence, TypeVar, Union
11
11
  import grpc
12
12
  from google.protobuf import wrappers_pb2
13
13
 
14
- from durabletask.entities import EntityInstanceId, EntityMetadata
14
+ from durabletask.entities import EntityInstanceId
15
+ from durabletask.entities.entity_metadata import EntityMetadata
15
16
  import durabletask.internal.helpers as helpers
16
17
  import durabletask.internal.orchestrator_service_pb2 as pb
17
18
  import durabletask.internal.orchestrator_service_pb2_grpc as stubs
@@ -229,10 +230,7 @@ class TaskHubGrpcClient:
229
230
  self._logger.info(f"Purging instance '{instance_id}'.")
230
231
  self._stub.PurgeInstances(req)
231
232
 
232
- def signal_entity(self,
233
- entity_instance_id: EntityInstanceId[TInput, TOutput],
234
- operation_name: str,
235
- input: Optional[TInput] = None):
233
+ def signal_entity(self, entity_instance_id: EntityInstanceId, operation_name: str, input: Optional[Any] = None):
236
234
  req = pb.SignalEntityRequest(
237
235
  instanceId=str(entity_instance_id),
238
236
  name=operation_name,
@@ -246,7 +244,7 @@ class TaskHubGrpcClient:
246
244
  self._stub.SignalEntity(req, None) # TODO: Cancellation timeout?
247
245
 
248
246
  def get_entity(self,
249
- entity_instance_id: EntityInstanceId[Any, Any],
247
+ entity_instance_id: EntityInstanceId,
250
248
  include_state: bool = True
251
249
  ) -> Optional[EntityMetadata]:
252
250
  req = pb.GetEntityRequest(instanceId=str(entity_instance_id), includeState=include_state)
@@ -4,7 +4,6 @@ from durabletask.entities.entity_context import EntityContext
4
4
  from durabletask.entities.entity_instance_id import EntityInstanceId
5
5
 
6
6
  TState = TypeVar("TState")
7
- TInput = TypeVar("TInput")
8
7
 
9
8
 
10
9
  class DurableEntity:
@@ -50,10 +49,7 @@ class DurableEntity:
50
49
  """
51
50
  self.entity_context.set_state(state)
52
51
 
53
- def signal_entity(self,
54
- entity_instance_id: EntityInstanceId[TInput, Any],
55
- operation: str,
56
- input: Optional[TInput] = None) -> None:
52
+ def signal_entity(self, entity_instance_id: EntityInstanceId, operation: str, input: Optional[Any] = None) -> None:
57
53
  """Signal another entity to perform an operation.
58
54
 
59
55
  Parameters
@@ -7,7 +7,6 @@ from durabletask.internal.entity_state_shim import StateShim
7
7
  import durabletask.internal.orchestrator_service_pb2 as pb
8
8
 
9
9
  TState = TypeVar("TState")
10
- TInput = TypeVar("TInput")
11
10
 
12
11
 
13
12
  class EntityContext:
@@ -82,7 +81,7 @@ class EntityContext:
82
81
  """
83
82
  self._state.set_state(new_state)
84
83
 
85
- def signal_entity(self, entity_instance_id: EntityInstanceId[TInput, Any], operation: str, input: Optional[TInput] = None) -> None:
84
+ def signal_entity(self, entity_instance_id: EntityInstanceId, operation: str, input: Optional[Any] = None) -> None:
86
85
  """Signal another entity to perform an operation.
87
86
 
88
87
  Parameters
@@ -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)
@@ -24,7 +24,7 @@ class EntityMetadata:
24
24
  """
25
25
 
26
26
  def __init__(self,
27
- id: EntityInstanceId[Any, Any],
27
+ id: EntityInstanceId,
28
28
  last_modified: datetime,
29
29
  backlog_queue_size: int,
30
30
  locked_by: str,
@@ -140,14 +140,14 @@ class OrchestrationContext(ABC):
140
140
 
141
141
  @abstractmethod
142
142
  def call_entity(self,
143
- entity: EntityInstanceId[TInput, TOutput],
143
+ entity: EntityInstanceId,
144
144
  operation: str,
145
- input: Optional[TInput] = None) -> CompletableTask[TOutput]:
145
+ input: Optional[TInput] = None) -> CompletableTask:
146
146
  """Schedule entity function for execution.
147
147
 
148
148
  Parameters
149
149
  ----------
150
- entity: EntityInstanceId[TInput, TOutput]
150
+ entity: EntityInstanceId
151
151
  The ID of the entity instance to call.
152
152
  operation: str
153
153
  The name of the operation to invoke on the entity.
@@ -164,7 +164,7 @@ class OrchestrationContext(ABC):
164
164
  @abstractmethod
165
165
  def signal_entity(
166
166
  self,
167
- entity_id: EntityInstanceId[TInput, TOutput],
167
+ entity_id: EntityInstanceId,
168
168
  operation_name: str,
169
169
  input: Optional[TInput] = None
170
170
  ) -> None:
@@ -172,7 +172,7 @@ class OrchestrationContext(ABC):
172
172
 
173
173
  Parameters
174
174
  ----------
175
- entity_id: EntityInstanceId[TInput, TOutput]
175
+ entity_id: EntityInstanceId
176
176
  The ID of the entity instance to signal.
177
177
  operation_name: str
178
178
  The name of the operation to invoke on the entity.
@@ -182,7 +182,7 @@ class OrchestrationContext(ABC):
182
182
  pass
183
183
 
184
184
  @abstractmethod
185
- def lock_entities(self, entities: list[EntityInstanceId[Any, Any]]) -> CompletableTask[EntityLock]:
185
+ def lock_entities(self, entities: list[EntityInstanceId]) -> CompletableTask[EntityLock]:
186
186
  """Creates a Task object that locks the specified entity instances.
187
187
 
188
188
  The locks will be acquired the next time the orchestrator yields.
@@ -191,7 +191,7 @@ class OrchestrationContext(ABC):
191
191
 
192
192
  Parameters
193
193
  ----------
194
- entities: list[EntityInstanceId[Any, Any]]
194
+ entities: list[EntityInstanceId]
195
195
  The list of entity instance IDs to lock.
196
196
 
197
197
  Returns
@@ -615,14 +615,6 @@ class RetryPolicy:
615
615
  return self._retry_timeout
616
616
 
617
617
 
618
- def get_entity_name(fn: Entity) -> str:
619
- if hasattr(fn, "__durable_entity_name__"):
620
- return getattr(fn, "__durable_entity_name__")
621
- if isinstance(fn, type) and issubclass(fn, DurableEntity):
622
- return fn.__name__
623
- return get_name(fn)
624
-
625
-
626
618
  def get_name(fn: Callable) -> str:
627
619
  """Returns the name of the provided function"""
628
620
  name = fn.__name__
@@ -169,7 +169,7 @@ class _Registry:
169
169
  def get_orchestrator(self, name: str) -> Optional[task.Orchestrator[Any, Any]]:
170
170
  return self.orchestrators.get(name)
171
171
 
172
- def add_activity(self, fn: task.Activity) -> str:
172
+ def add_activity(self, fn: task.Activity[TInput, TOutput]) -> str:
173
173
  if fn is None:
174
174
  raise ValueError("An activity function argument is required.")
175
175
 
@@ -177,7 +177,7 @@ class _Registry:
177
177
  self.add_named_activity(name, fn)
178
178
  return name
179
179
 
180
- def add_named_activity(self, name: str, fn: task.Activity) -> None:
180
+ def add_named_activity(self, name: str, fn: task.Activity[TInput, TOutput]) -> None:
181
181
  if not name:
182
182
  raise ValueError("A non-empty activity name is required.")
183
183
  if name in self.activities:
@@ -185,16 +185,19 @@ class _Registry:
185
185
 
186
186
  self.activities[name] = fn
187
187
 
188
- def get_activity(self, name: str) -> Optional[task.Activity]:
188
+ def get_activity(self, name: str) -> Optional[task.Activity[Any, Any]]:
189
189
  return self.activities.get(name)
190
190
 
191
- def add_entity(self, fn: task.Entity, name: Optional[str] = None) -> str:
191
+ def add_entity(self, fn: task.Entity) -> str:
192
192
  if fn is None:
193
193
  raise ValueError("An entity function argument is required.")
194
194
 
195
- if name is None:
196
- name = task.get_entity_name(fn)
197
- self.add_named_entity(name, fn)
195
+ if isinstance(fn, type) and issubclass(fn, DurableEntity):
196
+ name = fn.__name__
197
+ self.add_named_entity(name, fn)
198
+ else:
199
+ name = task.get_name(fn)
200
+ self.add_named_entity(name, fn)
198
201
  return name
199
202
 
200
203
  def add_named_entity(self, name: str, fn: task.Entity) -> None:
@@ -204,7 +207,6 @@ class _Registry:
204
207
  raise ValueError(f"A '{name}' entity already exists.")
205
208
 
206
209
  self.entities[name] = fn
207
- setattr(fn, "__durable_entity_name__", name)
208
210
 
209
211
  def get_entity(self, name: str) -> Optional[task.Entity]:
210
212
  return self.entities.get(name)
@@ -376,13 +378,13 @@ class TaskHubGrpcWorker:
376
378
  )
377
379
  return self._registry.add_activity(fn)
378
380
 
379
- def add_entity(self, fn: task.Entity, name: Optional[str] = None) -> str:
381
+ def add_entity(self, fn: task.Entity) -> str:
380
382
  """Registers an entity function with the worker."""
381
383
  if self._is_running:
382
384
  raise RuntimeError(
383
385
  "Entities cannot be added while the worker is running."
384
386
  )
385
- return self._registry.add_entity(fn, name)
387
+ return self._registry.add_entity(fn)
386
388
 
387
389
  def use_versioning(self, version: VersioningOptions) -> None:
388
390
  """Initializes versioning options for sub-orchestrators and activities."""
@@ -1042,21 +1044,21 @@ class _RuntimeOrchestrationContext(task.OrchestrationContext):
1042
1044
 
1043
1045
  def call_entity(
1044
1046
  self,
1045
- entity: EntityInstanceId[TInput, TOutput],
1047
+ entity: EntityInstanceId,
1046
1048
  operation: str,
1047
1049
  input: Optional[TInput] = None,
1048
- ) -> task.CompletableTask[TOutput]:
1050
+ ) -> task.CompletableTask:
1049
1051
  id = self.next_sequence_number()
1050
1052
 
1051
1053
  self.call_entity_function_helper(
1052
1054
  id, entity, operation, input=input
1053
1055
  )
1054
1056
 
1055
- return self._pending_tasks.get(id, task.CompletableTask[TOutput]())
1057
+ return self._pending_tasks.get(id, task.CompletableTask())
1056
1058
 
1057
1059
  def signal_entity(
1058
1060
  self,
1059
- entity_id: EntityInstanceId[TInput, TOutput],
1061
+ entity_id: EntityInstanceId,
1060
1062
  operation_name: str,
1061
1063
  input: Optional[TInput] = None
1062
1064
  ) -> None:
@@ -1066,7 +1068,7 @@ class _RuntimeOrchestrationContext(task.OrchestrationContext):
1066
1068
  id, entity_id, operation_name, input
1067
1069
  )
1068
1070
 
1069
- def lock_entities(self, entities: list[EntityInstanceId[Any, Any]]) -> task.CompletableTask[EntityLock]:
1071
+ def lock_entities(self, entities: list[EntityInstanceId]) -> task.CompletableTask[EntityLock]:
1070
1072
  id = self.next_sequence_number()
1071
1073
 
1072
1074
  self.lock_entities_function_helper(
@@ -1156,11 +1158,11 @@ class _RuntimeOrchestrationContext(task.OrchestrationContext):
1156
1158
  def call_entity_function_helper(
1157
1159
  self,
1158
1160
  id: Optional[int],
1159
- entity_id: EntityInstanceId[TInput, TOutput],
1161
+ entity_id: EntityInstanceId,
1160
1162
  operation: str,
1161
1163
  *,
1162
1164
  input: Optional[TInput] = None,
1163
- ) -> None:
1165
+ ):
1164
1166
  if id is None:
1165
1167
  id = self.next_sequence_number()
1166
1168
 
@@ -1178,7 +1180,7 @@ class _RuntimeOrchestrationContext(task.OrchestrationContext):
1178
1180
  def signal_entity_function_helper(
1179
1181
  self,
1180
1182
  id: Optional[int],
1181
- entity_id: EntityInstanceId[TInput, TOutput],
1183
+ entity_id: EntityInstanceId,
1182
1184
  operation: str,
1183
1185
  input: Optional[TInput]
1184
1186
  ) -> None:
@@ -1195,7 +1197,7 @@ class _RuntimeOrchestrationContext(task.OrchestrationContext):
1195
1197
  action = ph.new_signal_entity_action(id, entity_id, operation, encoded_input, self.new_uuid())
1196
1198
  self._pending_actions[id] = action
1197
1199
 
1198
- def lock_entities_function_helper(self, id: int, entities: list[EntityInstanceId[Any, Any]]) -> None:
1200
+ def lock_entities_function_helper(self, id: int, entities: list[EntityInstanceId]) -> None:
1199
1201
  if id is None:
1200
1202
  id = self.next_sequence_number()
1201
1203
 
@@ -1790,7 +1792,7 @@ class _OrchestrationExecutor:
1790
1792
  # The orchestrator generator function completed
1791
1793
  ctx.set_complete(generatorStopped.value, pb.ORCHESTRATION_STATUS_COMPLETED)
1792
1794
 
1793
- def _parse_entity_event_sent_input(self, event: pb.HistoryEvent) -> Tuple[EntityInstanceId[Any, Any], str]:
1795
+ def _parse_entity_event_sent_input(self, event: pb.HistoryEvent) -> Tuple[EntityInstanceId, str]:
1794
1796
  try:
1795
1797
  entity_id = EntityInstanceId.parse(event.eventSent.instanceId)
1796
1798
  except ValueError:
@@ -1804,7 +1806,7 @@ class _OrchestrationExecutor:
1804
1806
  def _handle_entity_event_raised(self,
1805
1807
  ctx: _RuntimeOrchestrationContext,
1806
1808
  event: pb.HistoryEvent,
1807
- entity_id: Optional[EntityInstanceId[Any, Any]],
1809
+ entity_id: Optional[EntityInstanceId],
1808
1810
  task_id: Optional[int],
1809
1811
  is_lock_event: bool):
1810
1812
  # This eventRaised represents the result of an entity operation after being translated to the old
@@ -1917,7 +1919,7 @@ class _EntityExecutor:
1917
1919
  def execute(
1918
1920
  self,
1919
1921
  orchestration_id: str,
1920
- entity_id: EntityInstanceId[TInput, TOutput],
1922
+ entity_id: EntityInstanceId,
1921
1923
  operation: str,
1922
1924
  state: StateShim,
1923
1925
  encoded_input: Optional[str],
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: durabletask
3
- Version: 0.0.0.dev22
3
+ Version: 0.0.0.dev23
4
4
  Summary: A Durable Task Client SDK for Python
5
5
  License: MIT License
6
6
 
@@ -9,7 +9,7 @@ build-backend = "setuptools.build_meta"
9
9
 
10
10
  [project]
11
11
  name = "durabletask"
12
- version = "0.0.0.dev22"
12
+ version = "0.0.0.dev23"
13
13
  description = "A Durable Task Client SDK for Python"
14
14
  keywords = [
15
15
  "durable",
@@ -1,89 +0,0 @@
1
- from typing import Any, Callable, TypeVar, Union, overload, TYPE_CHECKING
2
-
3
- if TYPE_CHECKING:
4
- from durabletask import task
5
- from durabletask.entities.durable_entity import DurableEntity
6
- from durabletask.entities.entity_context import EntityContext
7
-
8
-
9
- TInput = TypeVar('TInput')
10
- TOutput = TypeVar('TOutput')
11
-
12
-
13
- class EntityInstanceId[TInput, TOutput]:
14
- @overload
15
- def __new__(
16
- cls,
17
- entity: Callable[[EntityContext, TInput], TOutput],
18
- key: str
19
- ) -> "EntityInstanceId[TInput, TOutput]": ...
20
-
21
- @overload
22
- def __new__(
23
- cls,
24
- entity: type[DurableEntity],
25
- key: str
26
- ) -> "EntityInstanceId[Any, Any]": ...
27
-
28
- @overload
29
- def __new__(
30
- cls,
31
- entity: str,
32
- key: str
33
- ) -> "EntityInstanceId[Any, Any]": ...
34
-
35
- def __new__(
36
- cls,
37
- entity: Union[task.Entity[TInput, TOutput], str],
38
- key: str
39
- ) -> "EntityInstanceId[Any, Any]":
40
- return super().__new__(cls)
41
-
42
- def __init__(
43
- self,
44
- entity: Union[task.Entity[TInput, TOutput], str],
45
- key: str
46
- ):
47
- if not isinstance(entity, str):
48
- from durabletask import task
49
- entity = task.get_entity_name(entity)
50
- self.entity: str = entity
51
- self.key: str = key
52
-
53
- def __str__(self) -> str:
54
- return f"@{self.entity}@{self.key}"
55
-
56
- def __eq__(self, other):
57
- if not isinstance(other, EntityInstanceId):
58
- return False
59
- return self.entity == other.entity and self.key == other.key
60
-
61
- def __lt__(self, other):
62
- if not isinstance(other, EntityInstanceId):
63
- return self < other
64
- return str(self) < str(other)
65
-
66
- @staticmethod
67
- def parse(entity_id: str) -> "EntityInstanceId[Any, Any]":
68
- """Parse a string representation of an entity ID into an EntityInstanceId object.
69
-
70
- Parameters
71
- ----------
72
- entity_id : str
73
- The string representation of the entity ID, in the format '@entity@key'.
74
-
75
- Returns
76
- -------
77
- EntityInstanceId
78
- The parsed EntityInstanceId object.
79
-
80
- Raises
81
- ------
82
- ValueError
83
- If the input string is not in the correct format.
84
- """
85
- try:
86
- _, entity, key = entity_id.split("@", 2)
87
- return EntityInstanceId(entity=entity, key=key)
88
- except ValueError as ex:
89
- raise ValueError(f"Invalid entity ID format: {entity_id}", ex)