async-durable-execution-runner 2.0.0a1__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.
- LICENSE +175 -0
- NOTICE +8 -0
- VERSION.py +5 -0
- async_durable_execution_runner/__about__.py +33 -0
- async_durable_execution_runner/__init__.py +23 -0
- async_durable_execution_runner/checkpoint/__init__.py +1 -0
- async_durable_execution_runner/checkpoint/processor.py +101 -0
- async_durable_execution_runner/checkpoint/processors/__init__.py +1 -0
- async_durable_execution_runner/checkpoint/processors/base.py +199 -0
- async_durable_execution_runner/checkpoint/processors/callback.py +89 -0
- async_durable_execution_runner/checkpoint/processors/context.py +59 -0
- async_durable_execution_runner/checkpoint/processors/execution.py +52 -0
- async_durable_execution_runner/checkpoint/processors/step.py +124 -0
- async_durable_execution_runner/checkpoint/processors/wait.py +95 -0
- async_durable_execution_runner/checkpoint/transformer.py +104 -0
- async_durable_execution_runner/checkpoint/validators/__init__.py +1 -0
- async_durable_execution_runner/checkpoint/validators/checkpoint.py +242 -0
- async_durable_execution_runner/checkpoint/validators/operations/__init__.py +1 -0
- async_durable_execution_runner/checkpoint/validators/operations/callback.py +45 -0
- async_durable_execution_runner/checkpoint/validators/operations/context.py +73 -0
- async_durable_execution_runner/checkpoint/validators/operations/execution.py +47 -0
- async_durable_execution_runner/checkpoint/validators/operations/invoke.py +56 -0
- async_durable_execution_runner/checkpoint/validators/operations/step.py +106 -0
- async_durable_execution_runner/checkpoint/validators/operations/wait.py +54 -0
- async_durable_execution_runner/checkpoint/validators/transitions.py +66 -0
- async_durable_execution_runner/cli.py +498 -0
- async_durable_execution_runner/client.py +50 -0
- async_durable_execution_runner/exceptions.py +288 -0
- async_durable_execution_runner/execution.py +444 -0
- async_durable_execution_runner/executor.py +1234 -0
- async_durable_execution_runner/invoker.py +340 -0
- async_durable_execution_runner/model.py +3296 -0
- async_durable_execution_runner/observer.py +144 -0
- async_durable_execution_runner/py.typed +1 -0
- async_durable_execution_runner/runner.py +1167 -0
- async_durable_execution_runner/scheduler.py +246 -0
- async_durable_execution_runner/stores/__init__.py +1 -0
- async_durable_execution_runner/stores/base.py +147 -0
- async_durable_execution_runner/stores/filesystem.py +79 -0
- async_durable_execution_runner/stores/memory.py +38 -0
- async_durable_execution_runner/stores/sqlite.py +273 -0
- async_durable_execution_runner/token.py +49 -0
- async_durable_execution_runner/web/__init__.py +1 -0
- async_durable_execution_runner/web/errors.py +8 -0
- async_durable_execution_runner/web/handlers.py +813 -0
- async_durable_execution_runner/web/models.py +266 -0
- async_durable_execution_runner/web/routes.py +692 -0
- async_durable_execution_runner/web/serialization.py +235 -0
- async_durable_execution_runner/web/server.py +243 -0
- async_durable_execution_runner-2.0.0a1.dist-info/METADATA +238 -0
- async_durable_execution_runner-2.0.0a1.dist-info/RECORD +55 -0
- async_durable_execution_runner-2.0.0a1.dist-info/WHEEL +4 -0
- async_durable_execution_runner-2.0.0a1.dist-info/entry_points.txt +2 -0
- async_durable_execution_runner-2.0.0a1.dist-info/licenses/LICENSE +175 -0
- async_durable_execution_runner-2.0.0a1.dist-info/licenses/NOTICE +1 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""Exceptions for the Durable Executions Testing Library.
|
|
2
|
+
|
|
3
|
+
This module provides AWS-compliant exceptions that serialize to the exact JSON format
|
|
4
|
+
expected by boto3 and AWS services. All exceptions follow Smithy model definitions
|
|
5
|
+
for field names and structure.
|
|
6
|
+
|
|
7
|
+
## AWS-Compliant Error Format
|
|
8
|
+
|
|
9
|
+
All AWS API exceptions inherit from `AwsApiException` and implement the `to_dict()` method
|
|
10
|
+
to serialize to AWS-compliant JSON format. The format varies by exception type based on
|
|
11
|
+
their Smithy model definitions:
|
|
12
|
+
|
|
13
|
+
### Standard Format (most exceptions):
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"Type": "ExceptionName",
|
|
17
|
+
"message": "Error message" // or "Message" depending on Smithy definition
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Special Cases:
|
|
22
|
+
- `ExecutionAlreadyStartedException`: No "Type" field, includes "DurableExecutionArn"
|
|
23
|
+
```json
|
|
24
|
+
{
|
|
25
|
+
"message": "Error message",
|
|
26
|
+
"DurableExecutionArn": "arn:aws:states:..."
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Field Name Conventions
|
|
31
|
+
|
|
32
|
+
Field names follow the exact Smithy model definitions:
|
|
33
|
+
- `InvalidParameterValueException`: uses lowercase "message"
|
|
34
|
+
- `CallbackTimeoutException`: uses lowercase "message"
|
|
35
|
+
- `ResourceNotFoundException`: uses capital "Message"
|
|
36
|
+
- `ServiceException`: uses capital "Message"
|
|
37
|
+
- `ExecutionAlreadyStartedException`: uses lowercase "message" + "DurableExecutionArn"
|
|
38
|
+
|
|
39
|
+
## HTTP Status Codes
|
|
40
|
+
|
|
41
|
+
Each exception maps to appropriate HTTP status codes:
|
|
42
|
+
- 400: InvalidParameterValueException (Bad Request)
|
|
43
|
+
- 404: ResourceNotFoundException (Not Found)
|
|
44
|
+
- 408: CallbackTimeoutException (Request Timeout)
|
|
45
|
+
- 409: ExecutionAlreadyStartedException (Conflict)
|
|
46
|
+
- 500: ServiceException (Internal Server Error)
|
|
47
|
+
|
|
48
|
+
## Usage Examples
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
# Create and serialize an exception
|
|
52
|
+
exception = InvalidParameterValueException("Invalid parameter value")
|
|
53
|
+
json_dict = exception.to_dict()
|
|
54
|
+
# Result: {"Type": "InvalidParameterValueException", "message": "Invalid parameter value"}
|
|
55
|
+
|
|
56
|
+
# HTTP response creation
|
|
57
|
+
from async_durable_execution_runner.web.models import HTTPResponse
|
|
58
|
+
|
|
59
|
+
response = HTTPResponse.create_error_from_exception(exception)
|
|
60
|
+
# Creates HTTP 400 response with AWS-compliant JSON body
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Boto3 Compatibility
|
|
64
|
+
|
|
65
|
+
All exceptions are designed to be compatible with boto3's error handling:
|
|
66
|
+
- JSON structure matches boto3 expectations
|
|
67
|
+
- Field names match Smithy model definitions
|
|
68
|
+
- Type field values match exception class names
|
|
69
|
+
- Can be deserialized by boto3's error factory
|
|
70
|
+
|
|
71
|
+
Avoid any non-stdlib references in this module, it is at the bottom of the dependency chain.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
from __future__ import annotations
|
|
75
|
+
|
|
76
|
+
from typing import Any
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# region Local Runner
|
|
80
|
+
class DurableFunctionsLocalRunnerError(Exception):
|
|
81
|
+
"""Base class for Durable Executions exceptions"""
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class UnknownRouteError(DurableFunctionsLocalRunnerError):
|
|
85
|
+
"""No route matches the requested path pattern."""
|
|
86
|
+
|
|
87
|
+
def __init__(self, method: str, path: str) -> None:
|
|
88
|
+
"""Initialize UnknownRouteError with method and path.
|
|
89
|
+
|
|
90
|
+
Args:
|
|
91
|
+
method: HTTP method (GET, POST, etc.)
|
|
92
|
+
path: Request path that couldn't be matched
|
|
93
|
+
"""
|
|
94
|
+
self.method = method
|
|
95
|
+
self.path = path
|
|
96
|
+
message = f"Unknown path pattern: {method} {path}"
|
|
97
|
+
super().__init__(message)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# endregion Local Runner
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class SerializationError(DurableFunctionsLocalRunnerError):
|
|
104
|
+
"""Exception for serialization errors."""
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
# region Testing
|
|
108
|
+
class DurableFunctionsTestError(Exception):
|
|
109
|
+
"""Base class for testing errors."""
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
# endregion Testing
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
# region AWS API Exceptions
|
|
116
|
+
class AwsApiException(DurableFunctionsLocalRunnerError): # noqa: N818
|
|
117
|
+
"""Base class for AWS API-style exceptions that can be serialized to AWS format."""
|
|
118
|
+
|
|
119
|
+
http_status_code: int = 500 # Default to server error
|
|
120
|
+
|
|
121
|
+
def to_dict(self) -> dict[str, Any]:
|
|
122
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
123
|
+
raise NotImplementedError
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# Smithy-Mapped Exceptions (defined in Smithy models)
|
|
127
|
+
class InvalidParameterValueException(AwsApiException):
|
|
128
|
+
"""Exception for invalid parameter values."""
|
|
129
|
+
|
|
130
|
+
http_status_code = 400
|
|
131
|
+
|
|
132
|
+
def __init__(self, message: str) -> None:
|
|
133
|
+
"""Initialize with message field (lowercase per Smithy definition)."""
|
|
134
|
+
self.message = message
|
|
135
|
+
super().__init__(message)
|
|
136
|
+
|
|
137
|
+
def to_dict(self) -> dict[str, Any]:
|
|
138
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
139
|
+
return {"Type": "InvalidParameterValueException", "message": self.message}
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class ResourceNotFoundException(AwsApiException):
|
|
143
|
+
"""Exception for resource not found errors."""
|
|
144
|
+
|
|
145
|
+
http_status_code = 404
|
|
146
|
+
|
|
147
|
+
def __init__(
|
|
148
|
+
self,
|
|
149
|
+
Message: str, # noqa: N803
|
|
150
|
+
) -> None: # Capital M per Smithy definition
|
|
151
|
+
"""Initialize with Message field (capital M per Smithy definition)."""
|
|
152
|
+
self.Message = Message
|
|
153
|
+
super().__init__(Message)
|
|
154
|
+
|
|
155
|
+
def to_dict(self) -> dict[str, Any]:
|
|
156
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
157
|
+
return {"Type": "ResourceNotFoundException", "Message": self.Message}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
class ServiceException(AwsApiException):
|
|
161
|
+
"""Exception for general service errors."""
|
|
162
|
+
|
|
163
|
+
http_status_code = 500
|
|
164
|
+
|
|
165
|
+
def __init__(
|
|
166
|
+
self,
|
|
167
|
+
Message: str, # noqa: N803
|
|
168
|
+
) -> None: # Capital M per Smithy definition
|
|
169
|
+
"""Initialize with Message field (capital M per Smithy definition)."""
|
|
170
|
+
self.Message = Message
|
|
171
|
+
super().__init__(Message)
|
|
172
|
+
|
|
173
|
+
def to_dict(self) -> dict[str, Any]:
|
|
174
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
175
|
+
return {"Type": "ServiceException", "Message": self.Message}
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class ExecutionAlreadyStartedException(AwsApiException):
|
|
179
|
+
"""Exception for execution already started errors."""
|
|
180
|
+
|
|
181
|
+
http_status_code = 409
|
|
182
|
+
|
|
183
|
+
def __init__(self, message: str, DurableExecutionArn: str) -> None: # noqa: N803
|
|
184
|
+
"""Initialize with message and DurableExecutionArn fields."""
|
|
185
|
+
self.message = message
|
|
186
|
+
self.DurableExecutionArn = DurableExecutionArn
|
|
187
|
+
super().__init__(message)
|
|
188
|
+
|
|
189
|
+
def to_dict(self) -> dict[str, Any]:
|
|
190
|
+
"""Serialize to AWS-compliant JSON structure (no Type field per Smithy definition)."""
|
|
191
|
+
return {
|
|
192
|
+
"message": self.message,
|
|
193
|
+
"DurableExecutionArn": self.DurableExecutionArn,
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class ExecutionConflictException(AwsApiException):
|
|
198
|
+
"""Exception for execution conflict errors."""
|
|
199
|
+
|
|
200
|
+
http_status_code = 409
|
|
201
|
+
|
|
202
|
+
def __init__(self, message: str) -> None:
|
|
203
|
+
"""Initialize with message field."""
|
|
204
|
+
self.message = message
|
|
205
|
+
super().__init__(message)
|
|
206
|
+
|
|
207
|
+
def to_dict(self) -> dict[str, Any]:
|
|
208
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
209
|
+
return {"Type": "ExecutionConflictException", "message": self.message}
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class CallbackTimeoutException(AwsApiException):
|
|
213
|
+
"""Exception for callback timeout errors."""
|
|
214
|
+
|
|
215
|
+
http_status_code = 408
|
|
216
|
+
|
|
217
|
+
def __init__(self, message: str) -> None:
|
|
218
|
+
"""Initialize with message field (lowercase per Smithy definition)."""
|
|
219
|
+
self.message = message
|
|
220
|
+
super().__init__(message)
|
|
221
|
+
|
|
222
|
+
def to_dict(self) -> dict[str, Any]:
|
|
223
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
224
|
+
return {"Type": "CallbackTimeoutException", "message": self.message}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
class TooManyRequestsException(AwsApiException):
|
|
228
|
+
"""Exception for too many requests errors."""
|
|
229
|
+
|
|
230
|
+
http_status_code = 429
|
|
231
|
+
|
|
232
|
+
def __init__(self, message: str) -> None:
|
|
233
|
+
"""Initialize with message field (lowercase per Smithy definition)."""
|
|
234
|
+
self.message = message
|
|
235
|
+
super().__init__(message)
|
|
236
|
+
|
|
237
|
+
def to_dict(self) -> dict[str, Any]:
|
|
238
|
+
"""Serialize to AWS-compliant JSON structure."""
|
|
239
|
+
return {"Type": "TooManyRequestsException", "message": self.message}
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
# Unmapped Exceptions (thrown by services but not in Smithy)
|
|
243
|
+
class IllegalStateException(AwsApiException):
|
|
244
|
+
"""IllegalStateException."""
|
|
245
|
+
|
|
246
|
+
http_status_code = 500
|
|
247
|
+
|
|
248
|
+
def __init__(self, message: str) -> None:
|
|
249
|
+
"""Initialize with message field."""
|
|
250
|
+
self.message = message
|
|
251
|
+
super().__init__(message)
|
|
252
|
+
|
|
253
|
+
def to_dict(self) -> dict[str, Any]:
|
|
254
|
+
"""Serialize to AWS-compliant JSON structure (maps to ServiceException)."""
|
|
255
|
+
return {"Type": "ServiceException", "Message": self.message}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
class RuntimeException(AwsApiException):
|
|
259
|
+
"""RuntimeException."""
|
|
260
|
+
|
|
261
|
+
http_status_code = 500
|
|
262
|
+
|
|
263
|
+
def __init__(self, message: str) -> None:
|
|
264
|
+
"""Initialize with message field."""
|
|
265
|
+
self.message = message
|
|
266
|
+
super().__init__(message)
|
|
267
|
+
|
|
268
|
+
def to_dict(self) -> dict[str, Any]:
|
|
269
|
+
"""Serialize to AWS-compliant JSON structure (maps to ServiceException)."""
|
|
270
|
+
return {"Type": "ServiceException", "Message": self.message}
|
|
271
|
+
|
|
272
|
+
|
|
273
|
+
class IllegalArgumentException(AwsApiException):
|
|
274
|
+
"""IllegalArgumentException."""
|
|
275
|
+
|
|
276
|
+
http_status_code = 400
|
|
277
|
+
|
|
278
|
+
def __init__(self, message: str) -> None:
|
|
279
|
+
"""Initialize with message field."""
|
|
280
|
+
self.message = message
|
|
281
|
+
super().__init__(message)
|
|
282
|
+
|
|
283
|
+
def to_dict(self) -> dict[str, Any]:
|
|
284
|
+
"""Serialize to AWS-compliant JSON structure (maps to InvalidParameterValueException)."""
|
|
285
|
+
return {"Type": "InvalidParameterValueException", "message": self.message}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# endregion AWS API Exceptions
|