azure-functions-durable 1.2.8__py3-none-any.whl → 1.2.10__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 (101) hide show
  1. azure/durable_functions/__init__.py +81 -81
  2. azure/durable_functions/constants.py +9 -9
  3. azure/durable_functions/decorators/__init__.py +3 -3
  4. azure/durable_functions/decorators/durable_app.py +249 -249
  5. azure/durable_functions/decorators/metadata.py +109 -109
  6. azure/durable_functions/entity.py +125 -125
  7. azure/durable_functions/models/DurableEntityContext.py +201 -201
  8. azure/durable_functions/models/DurableHttpRequest.py +58 -58
  9. azure/durable_functions/models/DurableOrchestrationBindings.py +66 -66
  10. azure/durable_functions/models/DurableOrchestrationClient.py +781 -711
  11. azure/durable_functions/models/DurableOrchestrationContext.py +722 -707
  12. azure/durable_functions/models/DurableOrchestrationStatus.py +156 -156
  13. azure/durable_functions/models/EntityStateResponse.py +23 -23
  14. azure/durable_functions/models/FunctionContext.py +7 -7
  15. azure/durable_functions/models/OrchestrationRuntimeStatus.py +32 -29
  16. azure/durable_functions/models/OrchestratorState.py +117 -116
  17. azure/durable_functions/models/PurgeHistoryResult.py +33 -33
  18. azure/durable_functions/models/ReplaySchema.py +8 -8
  19. azure/durable_functions/models/RetryOptions.py +69 -69
  20. azure/durable_functions/models/RpcManagementOptions.py +86 -86
  21. azure/durable_functions/models/Task.py +426 -426
  22. azure/durable_functions/models/TaskOrchestrationExecutor.py +346 -333
  23. azure/durable_functions/models/TokenSource.py +56 -56
  24. azure/durable_functions/models/__init__.py +24 -24
  25. azure/durable_functions/models/actions/Action.py +23 -23
  26. azure/durable_functions/models/actions/ActionType.py +18 -18
  27. azure/durable_functions/models/actions/CallActivityAction.py +41 -41
  28. azure/durable_functions/models/actions/CallActivityWithRetryAction.py +45 -45
  29. azure/durable_functions/models/actions/CallEntityAction.py +46 -46
  30. azure/durable_functions/models/actions/CallHttpAction.py +35 -35
  31. azure/durable_functions/models/actions/CallSubOrchestratorAction.py +40 -40
  32. azure/durable_functions/models/actions/CallSubOrchestratorWithRetryAction.py +44 -44
  33. azure/durable_functions/models/actions/CompoundAction.py +35 -35
  34. azure/durable_functions/models/actions/ContinueAsNewAction.py +36 -36
  35. azure/durable_functions/models/actions/CreateTimerAction.py +48 -48
  36. azure/durable_functions/models/actions/NoOpAction.py +35 -35
  37. azure/durable_functions/models/actions/SignalEntityAction.py +47 -47
  38. azure/durable_functions/models/actions/WaitForExternalEventAction.py +63 -63
  39. azure/durable_functions/models/actions/WhenAllAction.py +14 -14
  40. azure/durable_functions/models/actions/WhenAnyAction.py +14 -14
  41. azure/durable_functions/models/actions/__init__.py +24 -24
  42. azure/durable_functions/models/entities/EntityState.py +74 -74
  43. azure/durable_functions/models/entities/OperationResult.py +76 -76
  44. azure/durable_functions/models/entities/RequestMessage.py +53 -53
  45. azure/durable_functions/models/entities/ResponseMessage.py +48 -48
  46. azure/durable_functions/models/entities/Signal.py +62 -62
  47. azure/durable_functions/models/entities/__init__.py +17 -17
  48. azure/durable_functions/models/history/HistoryEvent.py +92 -92
  49. azure/durable_functions/models/history/HistoryEventType.py +27 -25
  50. azure/durable_functions/models/history/__init__.py +8 -8
  51. azure/durable_functions/models/utils/__init__.py +7 -7
  52. azure/durable_functions/models/utils/entity_utils.py +103 -91
  53. azure/durable_functions/models/utils/http_utils.py +69 -69
  54. azure/durable_functions/models/utils/json_utils.py +56 -56
  55. azure/durable_functions/orchestrator.py +71 -71
  56. {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/LICENSE +21 -21
  57. {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/METADATA +58 -58
  58. azure_functions_durable-1.2.10.dist-info/RECORD +100 -0
  59. {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/WHEEL +1 -1
  60. tests/models/test_DecoratorMetadata.py +135 -135
  61. tests/models/test_Decorators.py +107 -107
  62. tests/models/test_DurableOrchestrationBindings.py +68 -56
  63. tests/models/test_DurableOrchestrationClient.py +730 -612
  64. tests/models/test_DurableOrchestrationContext.py +102 -102
  65. tests/models/test_DurableOrchestrationStatus.py +59 -59
  66. tests/models/test_OrchestrationState.py +28 -28
  67. tests/models/test_RpcManagementOptions.py +79 -79
  68. tests/models/test_TokenSource.py +10 -10
  69. tests/orchestrator/models/OrchestrationInstance.py +18 -18
  70. tests/orchestrator/orchestrator_test_utils.py +130 -130
  71. tests/orchestrator/schemas/OrchetrationStateSchema.py +66 -66
  72. tests/orchestrator/test_call_http.py +235 -176
  73. tests/orchestrator/test_continue_as_new.py +67 -67
  74. tests/orchestrator/test_create_timer.py +126 -126
  75. tests/orchestrator/test_entity.py +395 -395
  76. tests/orchestrator/test_external_event.py +53 -53
  77. tests/orchestrator/test_fan_out_fan_in.py +175 -175
  78. tests/orchestrator/test_is_replaying_flag.py +101 -101
  79. tests/orchestrator/test_retries.py +308 -308
  80. tests/orchestrator/test_sequential_orchestrator.py +841 -801
  81. tests/orchestrator/test_sequential_orchestrator_custom_status.py +119 -119
  82. tests/orchestrator/test_sequential_orchestrator_with_retry.py +465 -465
  83. tests/orchestrator/test_serialization.py +30 -30
  84. tests/orchestrator/test_sub_orchestrator.py +95 -95
  85. tests/orchestrator/test_sub_orchestrator_with_retry.py +129 -129
  86. tests/orchestrator/test_task_any.py +60 -60
  87. tests/tasks/tasks_test_utils.py +17 -17
  88. tests/tasks/test_new_uuid.py +34 -34
  89. tests/test_utils/ContextBuilder.py +174 -174
  90. tests/test_utils/EntityContextBuilder.py +56 -56
  91. tests/test_utils/constants.py +1 -1
  92. tests/test_utils/json_utils.py +30 -30
  93. tests/test_utils/testClasses.py +56 -56
  94. tests/utils/__init__.py +1 -0
  95. tests/utils/test_entity_utils.py +24 -0
  96. azure_functions_durable-1.2.8.data/data/_manifest/bsi.json +0 -1
  97. azure_functions_durable-1.2.8.data/data/_manifest/manifest.cat +0 -0
  98. azure_functions_durable-1.2.8.data/data/_manifest/manifest.spdx.json +0 -12845
  99. azure_functions_durable-1.2.8.data/data/_manifest/manifest.spdx.json.sha256 +0 -1
  100. azure_functions_durable-1.2.8.dist-info/RECORD +0 -102
  101. {azure_functions_durable-1.2.8.dist-info → azure_functions_durable-1.2.10.dist-info}/top_level.txt +0 -0
@@ -1,109 +1,109 @@
1
- # Copyright (c) Microsoft Corporation. All rights reserved.
2
- # Licensed under the MIT License.
3
- from typing import Optional
4
-
5
- from azure.durable_functions.constants import ORCHESTRATION_TRIGGER, \
6
- ACTIVITY_TRIGGER, ENTITY_TRIGGER, DURABLE_CLIENT
7
- from azure.functions.decorators.core import Trigger, InputBinding
8
-
9
-
10
- class OrchestrationTrigger(Trigger):
11
- """OrchestrationTrigger.
12
-
13
- Trigger representing an Orchestration Function.
14
- """
15
-
16
- @staticmethod
17
- def get_binding_name() -> str:
18
- """Get the name of this trigger, as a string.
19
-
20
- Returns
21
- -------
22
- str
23
- The string representation of this trigger.
24
- """
25
- return ORCHESTRATION_TRIGGER
26
-
27
- def __init__(self,
28
- name: str,
29
- orchestration: Optional[str] = None,
30
- ) -> None:
31
- self.orchestration = orchestration
32
- super().__init__(name=name)
33
-
34
-
35
- class ActivityTrigger(Trigger):
36
- """ActivityTrigger.
37
-
38
- Trigger representing a Durable Functions Activity.
39
- """
40
-
41
- @staticmethod
42
- def get_binding_name() -> str:
43
- """Get the name of this trigger, as a string.
44
-
45
- Returns
46
- -------
47
- str
48
- The string representation of this trigger.
49
- """
50
- return ACTIVITY_TRIGGER
51
-
52
- def __init__(self,
53
- name: str,
54
- activity: Optional[str] = None,
55
- ) -> None:
56
- self.activity = activity
57
- super().__init__(name=name)
58
-
59
-
60
- class EntityTrigger(Trigger):
61
- """EntityTrigger.
62
-
63
- Trigger representing an Entity Function.
64
- """
65
-
66
- @staticmethod
67
- def get_binding_name() -> str:
68
- """Get the name of this trigger, as a string.
69
-
70
- Returns
71
- -------
72
- str
73
- The string representation of this trigger.
74
- """
75
- return ENTITY_TRIGGER
76
-
77
- def __init__(self,
78
- name: str,
79
- entity_name: Optional[str] = None,
80
- ) -> None:
81
- self.entity_name = entity_name
82
- super().__init__(name=name)
83
-
84
-
85
- class DurableClient(InputBinding):
86
- """DurableClient.
87
-
88
- Binding representing a Durable-client object.
89
- """
90
-
91
- @staticmethod
92
- def get_binding_name() -> str:
93
- """Get the name of this Binding, as a string.
94
-
95
- Returns
96
- -------
97
- str
98
- The string representation of this binding.
99
- """
100
- return DURABLE_CLIENT
101
-
102
- def __init__(self,
103
- name: str,
104
- task_hub: Optional[str] = None,
105
- connection_name: Optional[str] = None
106
- ) -> None:
107
- self.task_hub = task_hub
108
- self.connection_name = connection_name
109
- super().__init__(name=name)
1
+ # Copyright (c) Microsoft Corporation. All rights reserved.
2
+ # Licensed under the MIT License.
3
+ from typing import Optional
4
+
5
+ from azure.durable_functions.constants import ORCHESTRATION_TRIGGER, \
6
+ ACTIVITY_TRIGGER, ENTITY_TRIGGER, DURABLE_CLIENT
7
+ from azure.functions.decorators.core import Trigger, InputBinding
8
+
9
+
10
+ class OrchestrationTrigger(Trigger):
11
+ """OrchestrationTrigger.
12
+
13
+ Trigger representing an Orchestration Function.
14
+ """
15
+
16
+ @staticmethod
17
+ def get_binding_name() -> str:
18
+ """Get the name of this trigger, as a string.
19
+
20
+ Returns
21
+ -------
22
+ str
23
+ The string representation of this trigger.
24
+ """
25
+ return ORCHESTRATION_TRIGGER
26
+
27
+ def __init__(self,
28
+ name: str,
29
+ orchestration: Optional[str] = None,
30
+ ) -> None:
31
+ self.orchestration = orchestration
32
+ super().__init__(name=name)
33
+
34
+
35
+ class ActivityTrigger(Trigger):
36
+ """ActivityTrigger.
37
+
38
+ Trigger representing a Durable Functions Activity.
39
+ """
40
+
41
+ @staticmethod
42
+ def get_binding_name() -> str:
43
+ """Get the name of this trigger, as a string.
44
+
45
+ Returns
46
+ -------
47
+ str
48
+ The string representation of this trigger.
49
+ """
50
+ return ACTIVITY_TRIGGER
51
+
52
+ def __init__(self,
53
+ name: str,
54
+ activity: Optional[str] = None,
55
+ ) -> None:
56
+ self.activity = activity
57
+ super().__init__(name=name)
58
+
59
+
60
+ class EntityTrigger(Trigger):
61
+ """EntityTrigger.
62
+
63
+ Trigger representing an Entity Function.
64
+ """
65
+
66
+ @staticmethod
67
+ def get_binding_name() -> str:
68
+ """Get the name of this trigger, as a string.
69
+
70
+ Returns
71
+ -------
72
+ str
73
+ The string representation of this trigger.
74
+ """
75
+ return ENTITY_TRIGGER
76
+
77
+ def __init__(self,
78
+ name: str,
79
+ entity_name: Optional[str] = None,
80
+ ) -> None:
81
+ self.entity_name = entity_name
82
+ super().__init__(name=name)
83
+
84
+
85
+ class DurableClient(InputBinding):
86
+ """DurableClient.
87
+
88
+ Binding representing a Durable-client object.
89
+ """
90
+
91
+ @staticmethod
92
+ def get_binding_name() -> str:
93
+ """Get the name of this Binding, as a string.
94
+
95
+ Returns
96
+ -------
97
+ str
98
+ The string representation of this binding.
99
+ """
100
+ return DURABLE_CLIENT
101
+
102
+ def __init__(self,
103
+ name: str,
104
+ task_hub: Optional[str] = None,
105
+ connection_name: Optional[str] = None
106
+ ) -> None:
107
+ self.task_hub = task_hub
108
+ self.connection_name = connection_name
109
+ super().__init__(name=name)
@@ -1,125 +1,125 @@
1
- from .models import DurableEntityContext
2
- from .models.entities import OperationResult, EntityState
3
- from datetime import datetime
4
- from typing import Callable, Any, List, Dict
5
-
6
-
7
- class InternalEntityException(Exception):
8
- """Framework-internal Exception class (for internal use only)."""
9
-
10
- pass
11
-
12
-
13
- class Entity:
14
- """Durable Entity Class.
15
-
16
- Responsible for executing the user-defined entity function.
17
- """
18
-
19
- def __init__(self, entity_func: Callable[[DurableEntityContext], None]):
20
- """Create a new entity for the user-defined entity.
21
-
22
- Responsible for executing the user-defined entity function
23
-
24
- Parameters
25
- ----------
26
- entity_func: Callable[[DurableEntityContext], Generator[Any, Any, Any]]
27
- The user defined entity function
28
- """
29
- self.fn: Callable[[DurableEntityContext], None] = entity_func
30
-
31
- def handle(self, context: DurableEntityContext, batch: List[Dict[str, Any]]) -> str:
32
- """Handle the execution of the user-defined entity function.
33
-
34
- Loops over the batch, which serves to specify inputs to the entity,
35
- and collects results and generates a final state, which are returned.
36
-
37
- Parameters
38
- ----------
39
- context: DurableEntityContext
40
- The entity context of the entity, which the user interacts with as their Durable API
41
-
42
- Returns
43
- -------
44
- str
45
- A JSON-formatted string representing the output state, results, and exceptions for the
46
- entity execution.
47
- """
48
- response = EntityState(results=[], signals=[])
49
- for operation_data in batch:
50
- result: Any = None
51
- is_error: bool = False
52
- start_time: datetime = datetime.now()
53
-
54
- try:
55
- # populate context
56
- operation = operation_data["name"]
57
- if operation is None:
58
- message = "Durable Functions Internal Error:"\
59
- "Entity operation was missing a name field"
60
- raise InternalEntityException(message)
61
- context._operation = operation
62
- context._input = operation_data["input"]
63
- self.fn(context)
64
- result = context._result
65
-
66
- except InternalEntityException as e:
67
- raise e
68
-
69
- except Exception as e:
70
- is_error = True
71
- result = str(e)
72
-
73
- duration: int = self._elapsed_milliseconds_since(start_time)
74
- operation_result = OperationResult(
75
- is_error=is_error,
76
- duration=duration,
77
- result=result
78
- )
79
- response.results.append(operation_result)
80
-
81
- response.state = context._state
82
- response.entity_exists = context._exists
83
- return response.to_json_string()
84
-
85
- @classmethod
86
- def create(cls, fn: Callable[[DurableEntityContext], None]) -> Callable[[Any], str]:
87
- """Create an instance of the entity class.
88
-
89
- Parameters
90
- ----------
91
- fn (Callable[[DurableEntityContext], None]): [description]
92
-
93
- Returns
94
- -------
95
- Callable[[Any], str]
96
- Handle function of the newly created entity client
97
- """
98
- def handle(context) -> str:
99
- # It is not clear when the context JSON would be found
100
- # inside a "body"-key, but this pattern matches the
101
- # orchestrator implementation, so we keep it for safety.
102
- context_body = getattr(context, "body", None)
103
- if context_body is None:
104
- context_body = context
105
- ctx, batch = DurableEntityContext.from_json(context_body)
106
- return Entity(fn).handle(ctx, batch)
107
- return handle
108
-
109
- def _elapsed_milliseconds_since(self, start_time: datetime) -> int:
110
- """Calculate the elapsed time, in milliseconds, from the start_time to the present.
111
-
112
- Parameters
113
- ----------
114
- start_time: datetime
115
- The timestamp of when the entity began processing a batched request.
116
-
117
- Returns
118
- -------
119
- int
120
- The time, in millseconds, from start_time to now
121
- """
122
- end_time = datetime.now()
123
- time_diff = end_time - start_time
124
- elapsed_time = int(time_diff.total_seconds() * 1000)
125
- return elapsed_time
1
+ from .models import DurableEntityContext
2
+ from .models.entities import OperationResult, EntityState
3
+ from datetime import datetime
4
+ from typing import Callable, Any, List, Dict
5
+
6
+
7
+ class InternalEntityException(Exception):
8
+ """Framework-internal Exception class (for internal use only)."""
9
+
10
+ pass
11
+
12
+
13
+ class Entity:
14
+ """Durable Entity Class.
15
+
16
+ Responsible for executing the user-defined entity function.
17
+ """
18
+
19
+ def __init__(self, entity_func: Callable[[DurableEntityContext], None]):
20
+ """Create a new entity for the user-defined entity.
21
+
22
+ Responsible for executing the user-defined entity function
23
+
24
+ Parameters
25
+ ----------
26
+ entity_func: Callable[[DurableEntityContext], Generator[Any, Any, Any]]
27
+ The user defined entity function
28
+ """
29
+ self.fn: Callable[[DurableEntityContext], None] = entity_func
30
+
31
+ def handle(self, context: DurableEntityContext, batch: List[Dict[str, Any]]) -> str:
32
+ """Handle the execution of the user-defined entity function.
33
+
34
+ Loops over the batch, which serves to specify inputs to the entity,
35
+ and collects results and generates a final state, which are returned.
36
+
37
+ Parameters
38
+ ----------
39
+ context: DurableEntityContext
40
+ The entity context of the entity, which the user interacts with as their Durable API
41
+
42
+ Returns
43
+ -------
44
+ str
45
+ A JSON-formatted string representing the output state, results, and exceptions for the
46
+ entity execution.
47
+ """
48
+ response = EntityState(results=[], signals=[])
49
+ for operation_data in batch:
50
+ result: Any = None
51
+ is_error: bool = False
52
+ start_time: datetime = datetime.now()
53
+
54
+ try:
55
+ # populate context
56
+ operation = operation_data["name"]
57
+ if operation is None:
58
+ message = "Durable Functions Internal Error:"\
59
+ "Entity operation was missing a name field"
60
+ raise InternalEntityException(message)
61
+ context._operation = operation
62
+ context._input = operation_data["input"]
63
+ self.fn(context)
64
+ result = context._result
65
+
66
+ except InternalEntityException as e:
67
+ raise e
68
+
69
+ except Exception as e:
70
+ is_error = True
71
+ result = str(e)
72
+
73
+ duration: int = self._elapsed_milliseconds_since(start_time)
74
+ operation_result = OperationResult(
75
+ is_error=is_error,
76
+ duration=duration,
77
+ result=result
78
+ )
79
+ response.results.append(operation_result)
80
+
81
+ response.state = context._state
82
+ response.entity_exists = context._exists
83
+ return response.to_json_string()
84
+
85
+ @classmethod
86
+ def create(cls, fn: Callable[[DurableEntityContext], None]) -> Callable[[Any], str]:
87
+ """Create an instance of the entity class.
88
+
89
+ Parameters
90
+ ----------
91
+ fn (Callable[[DurableEntityContext], None]): [description]
92
+
93
+ Returns
94
+ -------
95
+ Callable[[Any], str]
96
+ Handle function of the newly created entity client
97
+ """
98
+ def handle(context) -> str:
99
+ # It is not clear when the context JSON would be found
100
+ # inside a "body"-key, but this pattern matches the
101
+ # orchestrator implementation, so we keep it for safety.
102
+ context_body = getattr(context, "body", None)
103
+ if context_body is None:
104
+ context_body = context
105
+ ctx, batch = DurableEntityContext.from_json(context_body)
106
+ return Entity(fn).handle(ctx, batch)
107
+ return handle
108
+
109
+ def _elapsed_milliseconds_since(self, start_time: datetime) -> int:
110
+ """Calculate the elapsed time, in milliseconds, from the start_time to the present.
111
+
112
+ Parameters
113
+ ----------
114
+ start_time: datetime
115
+ The timestamp of when the entity began processing a batched request.
116
+
117
+ Returns
118
+ -------
119
+ int
120
+ The time, in millseconds, from start_time to now
121
+ """
122
+ end_time = datetime.now()
123
+ time_diff = end_time - start_time
124
+ elapsed_time = int(time_diff.total_seconds() * 1000)
125
+ return elapsed_time