nexo-schemas 0.0.16__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.
- nexo/schemas/__init__.py +0 -0
- nexo/schemas/application.py +292 -0
- nexo/schemas/connection.py +134 -0
- nexo/schemas/data.py +27 -0
- nexo/schemas/document.py +237 -0
- nexo/schemas/error/__init__.py +476 -0
- nexo/schemas/error/constants.py +50 -0
- nexo/schemas/error/descriptor.py +354 -0
- nexo/schemas/error/enums.py +40 -0
- nexo/schemas/error/metadata.py +15 -0
- nexo/schemas/error/spec.py +312 -0
- nexo/schemas/exception/__init__.py +0 -0
- nexo/schemas/exception/exc.py +911 -0
- nexo/schemas/exception/factory.py +1928 -0
- nexo/schemas/exception/handlers.py +110 -0
- nexo/schemas/google.py +14 -0
- nexo/schemas/key/__init__.py +0 -0
- nexo/schemas/key/rsa.py +131 -0
- nexo/schemas/metadata.py +21 -0
- nexo/schemas/mixins/__init__.py +0 -0
- nexo/schemas/mixins/filter.py +140 -0
- nexo/schemas/mixins/general.py +65 -0
- nexo/schemas/mixins/hierarchy.py +19 -0
- nexo/schemas/mixins/identity.py +387 -0
- nexo/schemas/mixins/parameter.py +50 -0
- nexo/schemas/mixins/service.py +40 -0
- nexo/schemas/mixins/sort.py +111 -0
- nexo/schemas/mixins/timestamp.py +192 -0
- nexo/schemas/model.py +240 -0
- nexo/schemas/operation/__init__.py +0 -0
- nexo/schemas/operation/action/__init__.py +9 -0
- nexo/schemas/operation/action/base.py +14 -0
- nexo/schemas/operation/action/resource.py +371 -0
- nexo/schemas/operation/action/status.py +8 -0
- nexo/schemas/operation/action/system.py +6 -0
- nexo/schemas/operation/action/websocket.py +6 -0
- nexo/schemas/operation/base.py +289 -0
- nexo/schemas/operation/constants.py +18 -0
- nexo/schemas/operation/context.py +68 -0
- nexo/schemas/operation/dependency.py +26 -0
- nexo/schemas/operation/enums.py +168 -0
- nexo/schemas/operation/extractor.py +36 -0
- nexo/schemas/operation/mixins.py +53 -0
- nexo/schemas/operation/request.py +1066 -0
- nexo/schemas/operation/resource.py +839 -0
- nexo/schemas/operation/system.py +55 -0
- nexo/schemas/operation/websocket.py +55 -0
- nexo/schemas/pagination.py +67 -0
- nexo/schemas/parameter.py +60 -0
- nexo/schemas/payload.py +116 -0
- nexo/schemas/resource.py +64 -0
- nexo/schemas/response.py +1041 -0
- nexo/schemas/security/__init__.py +0 -0
- nexo/schemas/security/api_key.py +63 -0
- nexo/schemas/security/authentication.py +848 -0
- nexo/schemas/security/authorization.py +922 -0
- nexo/schemas/security/enums.py +32 -0
- nexo/schemas/security/impersonation.py +179 -0
- nexo/schemas/security/token.py +402 -0
- nexo/schemas/security/types.py +17 -0
- nexo/schemas/success/__init__.py +0 -0
- nexo/schemas/success/descriptor.py +100 -0
- nexo/schemas/success/enums.py +23 -0
- nexo/schemas/user_agent.py +46 -0
- nexo_schemas-0.0.16.dist-info/METADATA +87 -0
- nexo_schemas-0.0.16.dist-info/RECORD +69 -0
- nexo_schemas-0.0.16.dist-info/WHEEL +5 -0
- nexo_schemas-0.0.16.dist-info/licenses/LICENSE +21 -0
- nexo_schemas-0.0.16.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,911 @@
|
|
|
1
|
+
import traceback as tb
|
|
2
|
+
from fastapi.responses import JSONResponse
|
|
3
|
+
from google.cloud.pubsub_v1.publisher.futures import Future
|
|
4
|
+
from logging import Logger
|
|
5
|
+
from typing import Any, Generic, Literal, Type, overload
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
from nexo.logging.enums import LogLevel
|
|
8
|
+
from nexo.types.boolean import OptBool
|
|
9
|
+
from nexo.types.dict import OptStrToStrDict
|
|
10
|
+
from nexo.types.string import ListOfStrs, OptStr
|
|
11
|
+
from nexo.types.uuid import OptUUID
|
|
12
|
+
from ..application import ApplicationContext, OptApplicationContext
|
|
13
|
+
from ..connection import ConnectionContext, OptConnectionContext
|
|
14
|
+
from ..error.enums import ErrorCode
|
|
15
|
+
from ..error.metadata import ErrorMetadata
|
|
16
|
+
from ..error import (
|
|
17
|
+
BadRequestError,
|
|
18
|
+
UnauthorizedError,
|
|
19
|
+
ForbiddenError,
|
|
20
|
+
NotFoundError,
|
|
21
|
+
MethodNotAllowedError,
|
|
22
|
+
ConflictError,
|
|
23
|
+
UnprocessableEntityError,
|
|
24
|
+
TooManyRequestsError,
|
|
25
|
+
InternalServerError as InternalServerErrorSchema,
|
|
26
|
+
NotImplementedError,
|
|
27
|
+
BadGatewayError,
|
|
28
|
+
ServiceUnavailableError,
|
|
29
|
+
AnyErrorT,
|
|
30
|
+
)
|
|
31
|
+
from ..google import ListOfPublisherHandlers
|
|
32
|
+
from ..operation.action.resource import (
|
|
33
|
+
ResourceOperationActions,
|
|
34
|
+
AnyResourceOperationAction,
|
|
35
|
+
)
|
|
36
|
+
from ..operation.action.system import SystemOperationAction
|
|
37
|
+
from ..operation.action.websocket import WebSocketOperationAction
|
|
38
|
+
from ..operation.context import Context
|
|
39
|
+
from ..operation.enums import OperationType
|
|
40
|
+
from ..operation.mixins import Timestamp, OptTimestamp
|
|
41
|
+
from ..operation.request import (
|
|
42
|
+
CreateFailedRequestOperation,
|
|
43
|
+
ReadFailedRequestOperation,
|
|
44
|
+
UpdateFailedRequestOperation,
|
|
45
|
+
DeleteFailedRequestOperation,
|
|
46
|
+
FailedRequestOperationFactory,
|
|
47
|
+
)
|
|
48
|
+
from ..operation.resource import (
|
|
49
|
+
CreateFailedResourceOperation,
|
|
50
|
+
ReadFailedResourceOperation,
|
|
51
|
+
UpdateFailedResourceOperation,
|
|
52
|
+
DeleteFailedResourceOperation,
|
|
53
|
+
FailedResourceOperationFactory,
|
|
54
|
+
)
|
|
55
|
+
from ..operation.system import FailedSystemOperation
|
|
56
|
+
from ..operation.websocket import FailedWebSocketOperation
|
|
57
|
+
from ..resource import Resource, OptResource
|
|
58
|
+
from ..response import (
|
|
59
|
+
BadRequestResponse,
|
|
60
|
+
UnauthorizedResponse,
|
|
61
|
+
ForbiddenResponse,
|
|
62
|
+
NotFoundResponse,
|
|
63
|
+
MethodNotAllowedResponse,
|
|
64
|
+
ConflictResponse,
|
|
65
|
+
UnprocessableEntityResponse,
|
|
66
|
+
TooManyRequestsResponse,
|
|
67
|
+
InternalServerErrorResponse,
|
|
68
|
+
NotImplementedResponse,
|
|
69
|
+
BadGatewayResponse,
|
|
70
|
+
ServiceUnavailableResponse,
|
|
71
|
+
OptAnyErrorResponse,
|
|
72
|
+
ErrorResponseT,
|
|
73
|
+
ResponseContext,
|
|
74
|
+
)
|
|
75
|
+
from ..security.authentication import OptAnyAuthentication
|
|
76
|
+
from ..security.authorization import OptAnyAuthorization
|
|
77
|
+
from ..security.impersonation import OptImpersonation
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class MaleoException(
|
|
81
|
+
Exception,
|
|
82
|
+
Generic[
|
|
83
|
+
AnyErrorT,
|
|
84
|
+
ErrorResponseT,
|
|
85
|
+
],
|
|
86
|
+
):
|
|
87
|
+
error_cls: Type[AnyErrorT]
|
|
88
|
+
response_cls: Type[ErrorResponseT]
|
|
89
|
+
|
|
90
|
+
@overload
|
|
91
|
+
def __init__(
|
|
92
|
+
self,
|
|
93
|
+
*args: object,
|
|
94
|
+
details: Any = None,
|
|
95
|
+
operation_type: Literal[OperationType.REQUEST],
|
|
96
|
+
application_context: OptApplicationContext = None,
|
|
97
|
+
operation_id: OptUUID = None,
|
|
98
|
+
operation_context: Context,
|
|
99
|
+
operation_action: AnyResourceOperationAction,
|
|
100
|
+
operation_timestamp: OptTimestamp = None,
|
|
101
|
+
operation_summary: OptStr = None,
|
|
102
|
+
connection_context: ConnectionContext,
|
|
103
|
+
authentication: OptAnyAuthentication = None,
|
|
104
|
+
authorization: OptAnyAuthorization = None,
|
|
105
|
+
impersonation: OptImpersonation = None,
|
|
106
|
+
response: OptAnyErrorResponse = None,
|
|
107
|
+
) -> None: ...
|
|
108
|
+
@overload
|
|
109
|
+
def __init__(
|
|
110
|
+
self,
|
|
111
|
+
*args: object,
|
|
112
|
+
details: Any = None,
|
|
113
|
+
operation_type: Literal[OperationType.RESOURCE],
|
|
114
|
+
application_context: OptApplicationContext = None,
|
|
115
|
+
operation_id: OptUUID = None,
|
|
116
|
+
operation_context: Context,
|
|
117
|
+
operation_action: AnyResourceOperationAction,
|
|
118
|
+
resource: Resource,
|
|
119
|
+
operation_timestamp: OptTimestamp = None,
|
|
120
|
+
operation_summary: OptStr = None,
|
|
121
|
+
connection_context: OptConnectionContext = None,
|
|
122
|
+
authentication: OptAnyAuthentication = None,
|
|
123
|
+
authorization: OptAnyAuthorization = None,
|
|
124
|
+
impersonation: OptImpersonation = None,
|
|
125
|
+
response: OptAnyErrorResponse = None,
|
|
126
|
+
) -> None: ...
|
|
127
|
+
@overload
|
|
128
|
+
def __init__(
|
|
129
|
+
self,
|
|
130
|
+
*args: object,
|
|
131
|
+
details: Any = None,
|
|
132
|
+
operation_type: Literal[OperationType.REQUEST, OperationType.RESOURCE],
|
|
133
|
+
application_context: OptApplicationContext = None,
|
|
134
|
+
operation_id: OptUUID = None,
|
|
135
|
+
operation_context: Context,
|
|
136
|
+
operation_action: AnyResourceOperationAction,
|
|
137
|
+
resource: OptResource = None,
|
|
138
|
+
operation_timestamp: OptTimestamp = None,
|
|
139
|
+
operation_summary: OptStr = None,
|
|
140
|
+
connection_context: OptConnectionContext = None,
|
|
141
|
+
authentication: OptAnyAuthentication = None,
|
|
142
|
+
authorization: OptAnyAuthorization = None,
|
|
143
|
+
impersonation: OptImpersonation = None,
|
|
144
|
+
response: OptAnyErrorResponse = None,
|
|
145
|
+
) -> None: ...
|
|
146
|
+
@overload
|
|
147
|
+
def __init__(
|
|
148
|
+
self,
|
|
149
|
+
*args: object,
|
|
150
|
+
details: Any = None,
|
|
151
|
+
operation_type: Literal[OperationType.SYSTEM],
|
|
152
|
+
application_context: OptApplicationContext = None,
|
|
153
|
+
operation_id: OptUUID = None,
|
|
154
|
+
operation_context: Context,
|
|
155
|
+
operation_action: SystemOperationAction,
|
|
156
|
+
operation_timestamp: OptTimestamp = None,
|
|
157
|
+
operation_summary: OptStr = None,
|
|
158
|
+
connection_context: OptConnectionContext = None,
|
|
159
|
+
authentication: OptAnyAuthentication = None,
|
|
160
|
+
authorization: OptAnyAuthorization = None,
|
|
161
|
+
impersonation: OptImpersonation = None,
|
|
162
|
+
response: OptAnyErrorResponse = None,
|
|
163
|
+
) -> None: ...
|
|
164
|
+
@overload
|
|
165
|
+
def __init__(
|
|
166
|
+
self,
|
|
167
|
+
*args: object,
|
|
168
|
+
details: Any = None,
|
|
169
|
+
operation_type: Literal[OperationType.WEBSOCKET],
|
|
170
|
+
application_context: OptApplicationContext = None,
|
|
171
|
+
operation_id: OptUUID = None,
|
|
172
|
+
operation_context: Context,
|
|
173
|
+
operation_action: WebSocketOperationAction,
|
|
174
|
+
operation_timestamp: OptTimestamp = None,
|
|
175
|
+
operation_summary: OptStr = None,
|
|
176
|
+
connection_context: OptConnectionContext = None,
|
|
177
|
+
authentication: OptAnyAuthentication = None,
|
|
178
|
+
authorization: OptAnyAuthorization = None,
|
|
179
|
+
impersonation: OptImpersonation = None,
|
|
180
|
+
response: OptAnyErrorResponse = None,
|
|
181
|
+
) -> None: ...
|
|
182
|
+
@overload
|
|
183
|
+
def __init__(
|
|
184
|
+
self,
|
|
185
|
+
*args: object,
|
|
186
|
+
details: Any = None,
|
|
187
|
+
operation_type: OperationType,
|
|
188
|
+
application_context: OptApplicationContext = None,
|
|
189
|
+
operation_id: OptUUID = None,
|
|
190
|
+
operation_context: Context,
|
|
191
|
+
operation_action: (
|
|
192
|
+
AnyResourceOperationAction
|
|
193
|
+
| SystemOperationAction
|
|
194
|
+
| WebSocketOperationAction
|
|
195
|
+
),
|
|
196
|
+
resource: OptResource = None,
|
|
197
|
+
operation_timestamp: OptTimestamp = None,
|
|
198
|
+
operation_summary: OptStr = None,
|
|
199
|
+
connection_context: OptConnectionContext = None,
|
|
200
|
+
authentication: OptAnyAuthentication = None,
|
|
201
|
+
authorization: OptAnyAuthorization = None,
|
|
202
|
+
impersonation: OptImpersonation = None,
|
|
203
|
+
response: OptAnyErrorResponse = None,
|
|
204
|
+
) -> None: ...
|
|
205
|
+
def __init__(
|
|
206
|
+
self,
|
|
207
|
+
*args: object,
|
|
208
|
+
details: Any = None,
|
|
209
|
+
operation_type: OperationType,
|
|
210
|
+
application_context: OptApplicationContext = None,
|
|
211
|
+
operation_id: OptUUID = None,
|
|
212
|
+
operation_context: Context,
|
|
213
|
+
operation_action: (
|
|
214
|
+
AnyResourceOperationAction
|
|
215
|
+
| SystemOperationAction
|
|
216
|
+
| WebSocketOperationAction
|
|
217
|
+
),
|
|
218
|
+
resource: OptResource = None,
|
|
219
|
+
operation_timestamp: OptTimestamp = None,
|
|
220
|
+
operation_summary: OptStr = None,
|
|
221
|
+
connection_context: OptConnectionContext = None,
|
|
222
|
+
authentication: OptAnyAuthentication = None,
|
|
223
|
+
authorization: OptAnyAuthorization = None,
|
|
224
|
+
impersonation: OptImpersonation = None,
|
|
225
|
+
response: OptAnyErrorResponse = None,
|
|
226
|
+
) -> None:
|
|
227
|
+
super().__init__(*args)
|
|
228
|
+
self.details = details
|
|
229
|
+
self.operation_type = operation_type
|
|
230
|
+
|
|
231
|
+
self.application_context = (
|
|
232
|
+
application_context
|
|
233
|
+
if application_context is not None
|
|
234
|
+
else ApplicationContext.new()
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
self.operation_id = operation_id if operation_id is not None else uuid4()
|
|
238
|
+
self.operation_context = operation_context
|
|
239
|
+
self.operation_action = operation_action
|
|
240
|
+
self.resource = resource
|
|
241
|
+
|
|
242
|
+
self.operation_timestamp = (
|
|
243
|
+
operation_timestamp if operation_timestamp is not None else Timestamp.now()
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
self.operation_summary = (
|
|
247
|
+
operation_summary
|
|
248
|
+
if operation_summary is not None
|
|
249
|
+
else f"{self.operation_type.capitalize()} operation failed due to exception being raised"
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
self.connection_context = connection_context
|
|
253
|
+
self.authentication = authentication
|
|
254
|
+
self.authorization = authorization
|
|
255
|
+
self.impersonation = impersonation
|
|
256
|
+
self._logged: bool = False
|
|
257
|
+
self._published: bool = False
|
|
258
|
+
self._futures: list[Future] = []
|
|
259
|
+
|
|
260
|
+
if response is not None:
|
|
261
|
+
self.response: ErrorResponseT = self.response_cls.model_validate(
|
|
262
|
+
response.model_dump()
|
|
263
|
+
)
|
|
264
|
+
if self.response.other is None and self.details is not None:
|
|
265
|
+
self.response.other = self.details
|
|
266
|
+
else:
|
|
267
|
+
self.response: ErrorResponseT = self.response_cls(other=self.details)
|
|
268
|
+
|
|
269
|
+
self.error: AnyErrorT = self.error_cls(
|
|
270
|
+
metadata=ErrorMetadata(details=self.details, traceback=self.traceback)
|
|
271
|
+
)
|
|
272
|
+
|
|
273
|
+
@property
|
|
274
|
+
def traceback(self) -> ListOfStrs:
|
|
275
|
+
return tb.format_exception(self)
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def operation(self) -> (
|
|
279
|
+
CreateFailedRequestOperation[
|
|
280
|
+
AnyErrorT,
|
|
281
|
+
ErrorResponseT,
|
|
282
|
+
]
|
|
283
|
+
| ReadFailedRequestOperation[
|
|
284
|
+
AnyErrorT,
|
|
285
|
+
ErrorResponseT,
|
|
286
|
+
]
|
|
287
|
+
| UpdateFailedRequestOperation[
|
|
288
|
+
AnyErrorT,
|
|
289
|
+
ErrorResponseT,
|
|
290
|
+
]
|
|
291
|
+
| DeleteFailedRequestOperation[
|
|
292
|
+
AnyErrorT,
|
|
293
|
+
ErrorResponseT,
|
|
294
|
+
]
|
|
295
|
+
| CreateFailedResourceOperation[
|
|
296
|
+
AnyErrorT,
|
|
297
|
+
ErrorResponseT,
|
|
298
|
+
]
|
|
299
|
+
| ReadFailedResourceOperation[
|
|
300
|
+
AnyErrorT,
|
|
301
|
+
ErrorResponseT,
|
|
302
|
+
]
|
|
303
|
+
| UpdateFailedResourceOperation[
|
|
304
|
+
AnyErrorT,
|
|
305
|
+
ErrorResponseT,
|
|
306
|
+
]
|
|
307
|
+
| DeleteFailedResourceOperation[
|
|
308
|
+
AnyErrorT,
|
|
309
|
+
ErrorResponseT,
|
|
310
|
+
]
|
|
311
|
+
| FailedSystemOperation[
|
|
312
|
+
AnyErrorT,
|
|
313
|
+
ErrorResponseT,
|
|
314
|
+
]
|
|
315
|
+
| FailedWebSocketOperation[
|
|
316
|
+
AnyErrorT,
|
|
317
|
+
ErrorResponseT,
|
|
318
|
+
]
|
|
319
|
+
):
|
|
320
|
+
if self.operation_type is OperationType.REQUEST:
|
|
321
|
+
if not isinstance(self.operation_action, ResourceOperationActions):
|
|
322
|
+
raise ValueError(
|
|
323
|
+
ErrorCode.BAD_REQUEST,
|
|
324
|
+
f"Invalid operation_action to generate request operation: {type(self.operation_action)}",
|
|
325
|
+
)
|
|
326
|
+
if self.connection_context is None:
|
|
327
|
+
raise ValueError(
|
|
328
|
+
ErrorCode.BAD_REQUEST,
|
|
329
|
+
"Failed generating request operation from MaleoException. Request context is not given",
|
|
330
|
+
)
|
|
331
|
+
response = JSONResponse(
|
|
332
|
+
content=self.response.model_dump(mode="json"),
|
|
333
|
+
status_code=self.error.spec.status_code,
|
|
334
|
+
)
|
|
335
|
+
response_context = ResponseContext(
|
|
336
|
+
status_code=response.status_code,
|
|
337
|
+
media_type=response.media_type,
|
|
338
|
+
headers=response.headers.items(),
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
return FailedRequestOperationFactory[
|
|
342
|
+
AnyErrorT,
|
|
343
|
+
ErrorResponseT,
|
|
344
|
+
].generate(
|
|
345
|
+
self.operation_action,
|
|
346
|
+
application_context=self.application_context,
|
|
347
|
+
id=self.operation_id,
|
|
348
|
+
context=self.operation_context,
|
|
349
|
+
timestamp=self.operation_timestamp,
|
|
350
|
+
summary=self.operation_summary,
|
|
351
|
+
error=self.error,
|
|
352
|
+
connection_context=self.connection_context,
|
|
353
|
+
authentication=self.authentication,
|
|
354
|
+
authorization=self.authorization,
|
|
355
|
+
impersonation=self.impersonation,
|
|
356
|
+
response=self.response,
|
|
357
|
+
response_context=response_context,
|
|
358
|
+
)
|
|
359
|
+
elif self.operation_type is OperationType.RESOURCE:
|
|
360
|
+
if not isinstance(self.operation_action, ResourceOperationActions):
|
|
361
|
+
raise ValueError(
|
|
362
|
+
ErrorCode.BAD_REQUEST,
|
|
363
|
+
f"Invalid operation_action to generate resource operation: {type(self.operation_action)}",
|
|
364
|
+
)
|
|
365
|
+
if self.resource is None:
|
|
366
|
+
raise ValueError(
|
|
367
|
+
ErrorCode.BAD_REQUEST,
|
|
368
|
+
"Failed generating resource operation from MaleoException. Resource is not given",
|
|
369
|
+
)
|
|
370
|
+
return FailedResourceOperationFactory[
|
|
371
|
+
AnyErrorT,
|
|
372
|
+
ErrorResponseT,
|
|
373
|
+
].generate(
|
|
374
|
+
self.operation_action,
|
|
375
|
+
application_context=self.application_context,
|
|
376
|
+
id=self.operation_id,
|
|
377
|
+
context=self.operation_context,
|
|
378
|
+
timestamp=self.operation_timestamp,
|
|
379
|
+
summary=self.operation_summary,
|
|
380
|
+
error=self.error,
|
|
381
|
+
connection_context=self.connection_context,
|
|
382
|
+
authentication=self.authentication,
|
|
383
|
+
authorization=self.authorization,
|
|
384
|
+
impersonation=self.impersonation,
|
|
385
|
+
resource=self.resource,
|
|
386
|
+
response=self.response,
|
|
387
|
+
)
|
|
388
|
+
elif self.operation_type is OperationType.SYSTEM:
|
|
389
|
+
if not isinstance(self.operation_action, SystemOperationAction):
|
|
390
|
+
raise ValueError(
|
|
391
|
+
ErrorCode.BAD_REQUEST,
|
|
392
|
+
f"Invalid operation_action to generate system operation: {type(self.operation_action)}",
|
|
393
|
+
)
|
|
394
|
+
return FailedSystemOperation[
|
|
395
|
+
AnyErrorT,
|
|
396
|
+
ErrorResponseT,
|
|
397
|
+
](
|
|
398
|
+
application_context=self.application_context,
|
|
399
|
+
id=self.operation_id,
|
|
400
|
+
context=self.operation_context,
|
|
401
|
+
action=self.operation_action,
|
|
402
|
+
timestamp=self.operation_timestamp,
|
|
403
|
+
summary=self.operation_summary,
|
|
404
|
+
error=self.error,
|
|
405
|
+
connection_context=self.connection_context,
|
|
406
|
+
authentication=self.authentication,
|
|
407
|
+
authorization=self.authorization,
|
|
408
|
+
impersonation=self.impersonation,
|
|
409
|
+
response=self.response,
|
|
410
|
+
)
|
|
411
|
+
elif self.operation_type is OperationType.WEBSOCKET:
|
|
412
|
+
if not isinstance(self.operation_action, WebSocketOperationAction):
|
|
413
|
+
raise ValueError(
|
|
414
|
+
ErrorCode.BAD_REQUEST,
|
|
415
|
+
f"Invalid operation_action to generate websocket operation: {type(self.operation_action)}",
|
|
416
|
+
)
|
|
417
|
+
return FailedWebSocketOperation[
|
|
418
|
+
AnyErrorT,
|
|
419
|
+
ErrorResponseT,
|
|
420
|
+
](
|
|
421
|
+
application_context=self.application_context,
|
|
422
|
+
id=self.operation_id,
|
|
423
|
+
context=self.operation_context,
|
|
424
|
+
action=self.operation_action,
|
|
425
|
+
timestamp=self.operation_timestamp,
|
|
426
|
+
summary=self.operation_summary,
|
|
427
|
+
error=self.error,
|
|
428
|
+
connection_context=self.connection_context,
|
|
429
|
+
authentication=self.authentication,
|
|
430
|
+
authorization=self.authorization,
|
|
431
|
+
impersonation=self.impersonation,
|
|
432
|
+
response=self.response,
|
|
433
|
+
)
|
|
434
|
+
|
|
435
|
+
raise ValueError(
|
|
436
|
+
ErrorCode.BAD_REQUEST,
|
|
437
|
+
f"Invalid operation_type to generate any operation from maleo exception: {self.operation_type}",
|
|
438
|
+
)
|
|
439
|
+
|
|
440
|
+
@overload
|
|
441
|
+
def generate_operation(
|
|
442
|
+
self,
|
|
443
|
+
operation_type: Literal[OperationType.REQUEST],
|
|
444
|
+
/,
|
|
445
|
+
) -> (
|
|
446
|
+
CreateFailedRequestOperation[
|
|
447
|
+
AnyErrorT,
|
|
448
|
+
ErrorResponseT,
|
|
449
|
+
]
|
|
450
|
+
| ReadFailedRequestOperation[
|
|
451
|
+
AnyErrorT,
|
|
452
|
+
ErrorResponseT,
|
|
453
|
+
]
|
|
454
|
+
| UpdateFailedRequestOperation[
|
|
455
|
+
AnyErrorT,
|
|
456
|
+
ErrorResponseT,
|
|
457
|
+
]
|
|
458
|
+
| DeleteFailedRequestOperation[
|
|
459
|
+
AnyErrorT,
|
|
460
|
+
ErrorResponseT,
|
|
461
|
+
]
|
|
462
|
+
): ...
|
|
463
|
+
@overload
|
|
464
|
+
def generate_operation(
|
|
465
|
+
self,
|
|
466
|
+
operation_type: Literal[OperationType.RESOURCE],
|
|
467
|
+
/,
|
|
468
|
+
) -> (
|
|
469
|
+
CreateFailedResourceOperation[
|
|
470
|
+
AnyErrorT,
|
|
471
|
+
ErrorResponseT,
|
|
472
|
+
]
|
|
473
|
+
| ReadFailedResourceOperation[
|
|
474
|
+
AnyErrorT,
|
|
475
|
+
ErrorResponseT,
|
|
476
|
+
]
|
|
477
|
+
| UpdateFailedResourceOperation[
|
|
478
|
+
AnyErrorT,
|
|
479
|
+
ErrorResponseT,
|
|
480
|
+
]
|
|
481
|
+
| DeleteFailedResourceOperation[
|
|
482
|
+
AnyErrorT,
|
|
483
|
+
ErrorResponseT,
|
|
484
|
+
]
|
|
485
|
+
): ...
|
|
486
|
+
@overload
|
|
487
|
+
def generate_operation(
|
|
488
|
+
self,
|
|
489
|
+
operation_type: Literal[OperationType.SYSTEM],
|
|
490
|
+
/,
|
|
491
|
+
) -> FailedSystemOperation[AnyErrorT, ErrorResponseT]: ...
|
|
492
|
+
@overload
|
|
493
|
+
def generate_operation(
|
|
494
|
+
self,
|
|
495
|
+
operation_type: Literal[OperationType.WEBSOCKET],
|
|
496
|
+
/,
|
|
497
|
+
) -> FailedWebSocketOperation[AnyErrorT, ErrorResponseT]: ...
|
|
498
|
+
def generate_operation(
|
|
499
|
+
self,
|
|
500
|
+
operation_type: OperationType,
|
|
501
|
+
/,
|
|
502
|
+
) -> (
|
|
503
|
+
CreateFailedRequestOperation[
|
|
504
|
+
AnyErrorT,
|
|
505
|
+
ErrorResponseT,
|
|
506
|
+
]
|
|
507
|
+
| ReadFailedRequestOperation[
|
|
508
|
+
AnyErrorT,
|
|
509
|
+
ErrorResponseT,
|
|
510
|
+
]
|
|
511
|
+
| UpdateFailedRequestOperation[
|
|
512
|
+
AnyErrorT,
|
|
513
|
+
ErrorResponseT,
|
|
514
|
+
]
|
|
515
|
+
| DeleteFailedRequestOperation[
|
|
516
|
+
AnyErrorT,
|
|
517
|
+
ErrorResponseT,
|
|
518
|
+
]
|
|
519
|
+
| CreateFailedResourceOperation[
|
|
520
|
+
AnyErrorT,
|
|
521
|
+
ErrorResponseT,
|
|
522
|
+
]
|
|
523
|
+
| ReadFailedResourceOperation[
|
|
524
|
+
AnyErrorT,
|
|
525
|
+
ErrorResponseT,
|
|
526
|
+
]
|
|
527
|
+
| UpdateFailedResourceOperation[
|
|
528
|
+
AnyErrorT,
|
|
529
|
+
ErrorResponseT,
|
|
530
|
+
]
|
|
531
|
+
| DeleteFailedResourceOperation[
|
|
532
|
+
AnyErrorT,
|
|
533
|
+
ErrorResponseT,
|
|
534
|
+
]
|
|
535
|
+
| FailedSystemOperation[
|
|
536
|
+
AnyErrorT,
|
|
537
|
+
ErrorResponseT,
|
|
538
|
+
]
|
|
539
|
+
| FailedWebSocketOperation[
|
|
540
|
+
AnyErrorT,
|
|
541
|
+
ErrorResponseT,
|
|
542
|
+
]
|
|
543
|
+
):
|
|
544
|
+
if operation_type != self.operation_type:
|
|
545
|
+
raise ValueError(
|
|
546
|
+
ErrorCode.INTERNAL_SERVER_ERROR,
|
|
547
|
+
(
|
|
548
|
+
"Failed generating operation for MaleoException ",
|
|
549
|
+
"due to mismatched operation_type. ",
|
|
550
|
+
f"Expected '{self.operation_type}' ",
|
|
551
|
+
f"but received {operation_type}",
|
|
552
|
+
),
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
if operation_type is OperationType.SYSTEM:
|
|
556
|
+
if not isinstance(self.operation_action, SystemOperationAction):
|
|
557
|
+
raise ValueError(
|
|
558
|
+
ErrorCode.BAD_REQUEST,
|
|
559
|
+
f"Invalid operation_action to generate system operation: {type(self.operation_action)}",
|
|
560
|
+
)
|
|
561
|
+
return FailedSystemOperation[
|
|
562
|
+
AnyErrorT,
|
|
563
|
+
ErrorResponseT,
|
|
564
|
+
](
|
|
565
|
+
application_context=self.application_context,
|
|
566
|
+
id=self.operation_id,
|
|
567
|
+
context=self.operation_context,
|
|
568
|
+
action=self.operation_action,
|
|
569
|
+
timestamp=self.operation_timestamp,
|
|
570
|
+
summary=self.operation_summary,
|
|
571
|
+
error=self.error,
|
|
572
|
+
connection_context=self.connection_context,
|
|
573
|
+
authentication=self.authentication,
|
|
574
|
+
authorization=self.authorization,
|
|
575
|
+
impersonation=self.impersonation,
|
|
576
|
+
response=self.response,
|
|
577
|
+
)
|
|
578
|
+
elif operation_type is OperationType.WEBSOCKET:
|
|
579
|
+
if not isinstance(self.operation_action, WebSocketOperationAction):
|
|
580
|
+
raise ValueError(
|
|
581
|
+
ErrorCode.BAD_REQUEST,
|
|
582
|
+
f"Invalid operation_action to generate websocket operation: {type(self.operation_action)}",
|
|
583
|
+
)
|
|
584
|
+
return FailedWebSocketOperation[
|
|
585
|
+
AnyErrorT,
|
|
586
|
+
ErrorResponseT,
|
|
587
|
+
](
|
|
588
|
+
application_context=self.application_context,
|
|
589
|
+
id=self.operation_id,
|
|
590
|
+
context=self.operation_context,
|
|
591
|
+
action=self.operation_action,
|
|
592
|
+
timestamp=self.operation_timestamp,
|
|
593
|
+
summary=self.operation_summary,
|
|
594
|
+
error=self.error,
|
|
595
|
+
connection_context=self.connection_context,
|
|
596
|
+
authentication=self.authentication,
|
|
597
|
+
authorization=self.authorization,
|
|
598
|
+
impersonation=self.impersonation,
|
|
599
|
+
response=self.response,
|
|
600
|
+
)
|
|
601
|
+
else:
|
|
602
|
+
if not isinstance(self.operation_action, ResourceOperationActions):
|
|
603
|
+
raise ValueError(
|
|
604
|
+
ErrorCode.BAD_REQUEST,
|
|
605
|
+
f"Invalid operation_action to generate {operation_type} operation: {type(self.operation_action)}",
|
|
606
|
+
)
|
|
607
|
+
|
|
608
|
+
if operation_type is OperationType.REQUEST:
|
|
609
|
+
if self.connection_context is None:
|
|
610
|
+
raise ValueError(
|
|
611
|
+
ErrorCode.BAD_REQUEST,
|
|
612
|
+
"Failed generating request operation from MaleoException. Request context is not given",
|
|
613
|
+
)
|
|
614
|
+
response = JSONResponse(
|
|
615
|
+
content=self.response.model_dump(mode="json"),
|
|
616
|
+
status_code=self.error.spec.status_code,
|
|
617
|
+
)
|
|
618
|
+
response_context = ResponseContext(
|
|
619
|
+
status_code=response.status_code,
|
|
620
|
+
media_type=response.media_type,
|
|
621
|
+
headers=response.headers.items(),
|
|
622
|
+
)
|
|
623
|
+
|
|
624
|
+
return FailedRequestOperationFactory[
|
|
625
|
+
AnyErrorT,
|
|
626
|
+
ErrorResponseT,
|
|
627
|
+
].generate(
|
|
628
|
+
self.operation_action,
|
|
629
|
+
application_context=self.application_context,
|
|
630
|
+
id=self.operation_id,
|
|
631
|
+
context=self.operation_context,
|
|
632
|
+
timestamp=self.operation_timestamp,
|
|
633
|
+
summary=self.operation_summary,
|
|
634
|
+
error=self.error,
|
|
635
|
+
connection_context=self.connection_context,
|
|
636
|
+
authentication=self.authentication,
|
|
637
|
+
authorization=self.authorization,
|
|
638
|
+
impersonation=self.impersonation,
|
|
639
|
+
response=self.response,
|
|
640
|
+
response_context=response_context,
|
|
641
|
+
)
|
|
642
|
+
elif operation_type is OperationType.RESOURCE:
|
|
643
|
+
if self.resource is None:
|
|
644
|
+
raise ValueError(
|
|
645
|
+
ErrorCode.BAD_REQUEST,
|
|
646
|
+
"Failed generating resource operation from MaleoException. Resource is not given",
|
|
647
|
+
)
|
|
648
|
+
return FailedResourceOperationFactory[
|
|
649
|
+
AnyErrorT,
|
|
650
|
+
ErrorResponseT,
|
|
651
|
+
].generate(
|
|
652
|
+
self.operation_action,
|
|
653
|
+
application_context=self.application_context,
|
|
654
|
+
id=self.operation_id,
|
|
655
|
+
context=self.operation_context,
|
|
656
|
+
timestamp=self.operation_timestamp,
|
|
657
|
+
summary=self.operation_summary,
|
|
658
|
+
error=self.error,
|
|
659
|
+
connection_context=self.connection_context,
|
|
660
|
+
authentication=self.authentication,
|
|
661
|
+
authorization=self.authorization,
|
|
662
|
+
impersonation=self.impersonation,
|
|
663
|
+
resource=self.resource,
|
|
664
|
+
response=self.response,
|
|
665
|
+
)
|
|
666
|
+
|
|
667
|
+
def log_operation(
|
|
668
|
+
self,
|
|
669
|
+
logger: Logger,
|
|
670
|
+
level: LogLevel = LogLevel.ERROR,
|
|
671
|
+
*,
|
|
672
|
+
exc_info: OptBool = None,
|
|
673
|
+
additional_extra: OptStrToStrDict = None,
|
|
674
|
+
override_extra: OptStrToStrDict = None,
|
|
675
|
+
additional_labels: OptStrToStrDict = None,
|
|
676
|
+
override_labels: OptStrToStrDict = None,
|
|
677
|
+
):
|
|
678
|
+
if not self._logged:
|
|
679
|
+
self.operation.log(
|
|
680
|
+
logger,
|
|
681
|
+
level,
|
|
682
|
+
exc_info=exc_info,
|
|
683
|
+
additional_extra=additional_extra,
|
|
684
|
+
override_extra=override_extra,
|
|
685
|
+
additional_labels=additional_labels,
|
|
686
|
+
override_labels=override_labels,
|
|
687
|
+
)
|
|
688
|
+
self._logged = True
|
|
689
|
+
|
|
690
|
+
def publish_operation(
|
|
691
|
+
self,
|
|
692
|
+
logger: Logger,
|
|
693
|
+
publishers: ListOfPublisherHandlers = [],
|
|
694
|
+
*,
|
|
695
|
+
additional_labels: OptStrToStrDict = None,
|
|
696
|
+
override_labels: OptStrToStrDict = None,
|
|
697
|
+
) -> list[Future]:
|
|
698
|
+
if not self._published:
|
|
699
|
+
futures = self.operation.publish(
|
|
700
|
+
logger,
|
|
701
|
+
publishers,
|
|
702
|
+
additional_labels=additional_labels,
|
|
703
|
+
override_labels=override_labels,
|
|
704
|
+
)
|
|
705
|
+
self._published = True
|
|
706
|
+
self._futures = futures
|
|
707
|
+
return self._futures
|
|
708
|
+
|
|
709
|
+
def log_and_publish_operation(
|
|
710
|
+
self,
|
|
711
|
+
logger: Logger,
|
|
712
|
+
publishers: ListOfPublisherHandlers = [],
|
|
713
|
+
level: LogLevel = LogLevel.ERROR,
|
|
714
|
+
*,
|
|
715
|
+
exc_info: OptBool = None,
|
|
716
|
+
additional_extra: OptStrToStrDict = None,
|
|
717
|
+
override_extra: OptStrToStrDict = None,
|
|
718
|
+
additional_labels: OptStrToStrDict = None,
|
|
719
|
+
override_labels: OptStrToStrDict = None,
|
|
720
|
+
) -> list[Future]:
|
|
721
|
+
self.log_operation(
|
|
722
|
+
logger,
|
|
723
|
+
level,
|
|
724
|
+
exc_info=exc_info,
|
|
725
|
+
additional_extra=additional_extra,
|
|
726
|
+
override_extra=override_extra,
|
|
727
|
+
additional_labels=additional_labels,
|
|
728
|
+
override_labels=override_labels,
|
|
729
|
+
)
|
|
730
|
+
return self.publish_operation(
|
|
731
|
+
logger,
|
|
732
|
+
publishers,
|
|
733
|
+
additional_labels=additional_labels,
|
|
734
|
+
override_labels=override_labels,
|
|
735
|
+
)
|
|
736
|
+
|
|
737
|
+
|
|
738
|
+
class ClientException(
|
|
739
|
+
MaleoException[
|
|
740
|
+
AnyErrorT,
|
|
741
|
+
ErrorResponseT,
|
|
742
|
+
],
|
|
743
|
+
Generic[
|
|
744
|
+
AnyErrorT,
|
|
745
|
+
ErrorResponseT,
|
|
746
|
+
],
|
|
747
|
+
):
|
|
748
|
+
"""Base class for all client error (HTTP 4xx) responses"""
|
|
749
|
+
|
|
750
|
+
|
|
751
|
+
class BadRequest(
|
|
752
|
+
ClientException[
|
|
753
|
+
BadRequestError,
|
|
754
|
+
BadRequestResponse,
|
|
755
|
+
]
|
|
756
|
+
):
|
|
757
|
+
error_cls = BadRequestError
|
|
758
|
+
response_cls = BadRequestResponse
|
|
759
|
+
|
|
760
|
+
|
|
761
|
+
class Unauthorized(
|
|
762
|
+
ClientException[
|
|
763
|
+
UnauthorizedError,
|
|
764
|
+
UnauthorizedResponse,
|
|
765
|
+
]
|
|
766
|
+
):
|
|
767
|
+
error_cls = UnauthorizedError
|
|
768
|
+
response_cls = UnauthorizedResponse
|
|
769
|
+
|
|
770
|
+
|
|
771
|
+
class Forbidden(
|
|
772
|
+
ClientException[
|
|
773
|
+
ForbiddenError,
|
|
774
|
+
ForbiddenResponse,
|
|
775
|
+
]
|
|
776
|
+
):
|
|
777
|
+
error_cls = ForbiddenError
|
|
778
|
+
response_cls = ForbiddenResponse
|
|
779
|
+
|
|
780
|
+
|
|
781
|
+
class NotFound(
|
|
782
|
+
ClientException[
|
|
783
|
+
NotFoundError,
|
|
784
|
+
NotFoundResponse,
|
|
785
|
+
]
|
|
786
|
+
):
|
|
787
|
+
error_cls = NotFoundError
|
|
788
|
+
response_cls = NotFoundResponse
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
class MethodNotAllowed(
|
|
792
|
+
ClientException[
|
|
793
|
+
MethodNotAllowedError,
|
|
794
|
+
MethodNotAllowedResponse,
|
|
795
|
+
]
|
|
796
|
+
):
|
|
797
|
+
error_cls = MethodNotAllowedError
|
|
798
|
+
response_cls = MethodNotAllowedResponse
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
class Conflict(
|
|
802
|
+
ClientException[
|
|
803
|
+
ConflictError,
|
|
804
|
+
ConflictResponse,
|
|
805
|
+
]
|
|
806
|
+
):
|
|
807
|
+
error_cls = ConflictError
|
|
808
|
+
response_cls = ConflictResponse
|
|
809
|
+
|
|
810
|
+
|
|
811
|
+
class UnprocessableEntity(
|
|
812
|
+
ClientException[
|
|
813
|
+
UnprocessableEntityError,
|
|
814
|
+
UnprocessableEntityResponse,
|
|
815
|
+
]
|
|
816
|
+
):
|
|
817
|
+
error_cls = UnprocessableEntityError
|
|
818
|
+
response_cls = UnprocessableEntityResponse
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
class TooManyRequests(
|
|
822
|
+
ClientException[
|
|
823
|
+
TooManyRequestsError,
|
|
824
|
+
TooManyRequestsResponse,
|
|
825
|
+
]
|
|
826
|
+
):
|
|
827
|
+
error_cls = TooManyRequestsError
|
|
828
|
+
response_cls = TooManyRequestsResponse
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
class ServerException(
|
|
832
|
+
MaleoException[
|
|
833
|
+
AnyErrorT,
|
|
834
|
+
ErrorResponseT,
|
|
835
|
+
],
|
|
836
|
+
Generic[
|
|
837
|
+
AnyErrorT,
|
|
838
|
+
ErrorResponseT,
|
|
839
|
+
],
|
|
840
|
+
):
|
|
841
|
+
"""Base class for all server error (HTTP 5xx) responses"""
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
class InternalServerError(
|
|
845
|
+
ServerException[
|
|
846
|
+
InternalServerErrorSchema,
|
|
847
|
+
InternalServerErrorResponse,
|
|
848
|
+
]
|
|
849
|
+
):
|
|
850
|
+
error_cls = InternalServerErrorSchema
|
|
851
|
+
response_cls = InternalServerErrorResponse
|
|
852
|
+
|
|
853
|
+
|
|
854
|
+
class NotImplemented(
|
|
855
|
+
ServerException[
|
|
856
|
+
NotImplementedError,
|
|
857
|
+
NotImplementedResponse,
|
|
858
|
+
]
|
|
859
|
+
):
|
|
860
|
+
error_cls = NotImplementedError
|
|
861
|
+
response_cls = NotImplementedResponse
|
|
862
|
+
|
|
863
|
+
|
|
864
|
+
class BadGateway(
|
|
865
|
+
ServerException[
|
|
866
|
+
BadGatewayError,
|
|
867
|
+
BadGatewayResponse,
|
|
868
|
+
]
|
|
869
|
+
):
|
|
870
|
+
error_cls = BadGatewayError
|
|
871
|
+
response_cls = BadGatewayResponse
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
class ServiceUnavailable(
|
|
875
|
+
ServerException[
|
|
876
|
+
ServiceUnavailableError,
|
|
877
|
+
ServiceUnavailableResponse,
|
|
878
|
+
]
|
|
879
|
+
):
|
|
880
|
+
error_cls = ServiceUnavailableError
|
|
881
|
+
response_cls = ServiceUnavailableResponse
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
AnyExceptionType = (
|
|
885
|
+
Type[BadRequest]
|
|
886
|
+
| Type[Unauthorized]
|
|
887
|
+
| Type[Forbidden]
|
|
888
|
+
| Type[NotFound]
|
|
889
|
+
| Type[MethodNotAllowed]
|
|
890
|
+
| Type[Conflict]
|
|
891
|
+
| Type[UnprocessableEntity]
|
|
892
|
+
| Type[TooManyRequests]
|
|
893
|
+
| Type[InternalServerError]
|
|
894
|
+
| Type[NotImplemented]
|
|
895
|
+
| Type[BadGateway]
|
|
896
|
+
| Type[ServiceUnavailable]
|
|
897
|
+
)
|
|
898
|
+
AnyException = (
|
|
899
|
+
BadRequest
|
|
900
|
+
| Unauthorized
|
|
901
|
+
| Forbidden
|
|
902
|
+
| NotFound
|
|
903
|
+
| MethodNotAllowed
|
|
904
|
+
| Conflict
|
|
905
|
+
| UnprocessableEntity
|
|
906
|
+
| TooManyRequests
|
|
907
|
+
| InternalServerError
|
|
908
|
+
| NotImplemented
|
|
909
|
+
| BadGateway
|
|
910
|
+
| ServiceUnavailable
|
|
911
|
+
)
|