maleo-foundation 0.3.55__py3-none-any.whl → 0.3.57__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.
- maleo_foundation/enums.py +58 -18
- maleo_foundation/managers/service.py +11 -9
- maleo_foundation/middlewares/authentication.py +2 -2
- maleo_foundation/models/responses.py +60 -14
- maleo_foundation/models/schemas/result.py +73 -8
- maleo_foundation/models/transfers/general/configurations/cache/redis.py +3 -0
- maleo_foundation/models/transfers/general/configurations/client/maleo.py +4 -0
- maleo_foundation/models/transfers/results/client/controllers/http.py +28 -24
- maleo_foundation/models/transfers/results/client/service.py +1 -8
- maleo_foundation/models/transfers/results/service/general.py +1 -8
- maleo_foundation/utils/__init__.py +0 -2
- maleo_foundation/utils/exceptions/__init__.py +0 -0
- maleo_foundation/utils/exceptions/client.py +221 -0
- maleo_foundation/utils/exceptions/request.py +38 -0
- maleo_foundation/utils/exceptions/service.py +221 -0
- {maleo_foundation-0.3.55.dist-info → maleo_foundation-0.3.57.dist-info}/METADATA +1 -1
- {maleo_foundation-0.3.55.dist-info → maleo_foundation-0.3.57.dist-info}/RECORD +19 -16
- maleo_foundation/utils/exceptions.py +0 -158
- {maleo_foundation-0.3.55.dist-info → maleo_foundation-0.3.57.dist-info}/WHEEL +0 -0
- {maleo_foundation-0.3.55.dist-info → maleo_foundation-0.3.57.dist-info}/top_level.txt +0 -0
maleo_foundation/enums.py
CHANGED
@@ -67,19 +67,69 @@ class BaseEnums:
|
|
67
67
|
REFRESH = "refresh"
|
68
68
|
ACCESS = "access"
|
69
69
|
|
70
|
-
class
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
70
|
+
class ExceptionType(StrEnum):
|
71
|
+
TIMEOUT = "timeout"
|
72
|
+
UNAUTHORIZED = "unauthorized"
|
73
|
+
FORBIDDEN = "forbidden"
|
74
|
+
NOT_FOUND = "not_found"
|
75
|
+
VALIDATION = "validation"
|
76
|
+
INTERNAL = "internal"
|
77
|
+
UNAVAILABLE = "unavailable"
|
78
|
+
|
79
|
+
class OperationOrigin(StrEnum):
|
80
|
+
SERVICE = "service"
|
81
|
+
CLIENT = "client"
|
75
82
|
|
76
|
-
class
|
77
|
-
|
78
|
-
|
83
|
+
class ServiceOperationLayer(StrEnum):
|
84
|
+
ROUTER = "router"
|
85
|
+
CONTROLLER = "controller"
|
86
|
+
SERVICE = "service"
|
87
|
+
REPOSITORY = "repository"
|
88
|
+
|
89
|
+
class ClientOperationLayer(StrEnum):
|
90
|
+
CONTROLLER = "controller"
|
91
|
+
SERVICE = "service"
|
92
|
+
|
93
|
+
class OperationLayer(StrEnum):
|
94
|
+
ROUTER = "router"
|
95
|
+
CONTROLLER = "controller"
|
96
|
+
SERVICE = "service"
|
97
|
+
REPOSITORY = "repository"
|
98
|
+
|
99
|
+
class ServiceOperationTarget(StrEnum):
|
100
|
+
CACHE = "cache"
|
101
|
+
DATABASE = "database"
|
102
|
+
MICROSERVICE = "microservice"
|
103
|
+
THIRD_PARTY = "third_party"
|
104
|
+
|
105
|
+
class ClientOperationTarget(StrEnum):
|
106
|
+
CACHE = "cache"
|
107
|
+
CONTROLLER = "controller"
|
108
|
+
|
109
|
+
class OperationTarget(StrEnum):
|
110
|
+
CACHE = "cache"
|
111
|
+
CONTROLLER = "controller"
|
112
|
+
DATABASE = "database"
|
113
|
+
MICROSERVICE = "microservice"
|
114
|
+
THIRD_PARTY = "third_party"
|
79
115
|
|
80
116
|
class OperationType(StrEnum):
|
81
117
|
CREATE = "create"
|
118
|
+
READ = "read"
|
82
119
|
UPDATE = "update"
|
120
|
+
DELETE = "delete"
|
121
|
+
|
122
|
+
class CreateType(StrEnum):
|
123
|
+
CREATE = "create"
|
124
|
+
RESTORE = "restore"
|
125
|
+
|
126
|
+
class UpdateType(StrEnum):
|
127
|
+
DATA = "data"
|
128
|
+
STATUS = "status"
|
129
|
+
|
130
|
+
class StatusUpdateType(StrEnum):
|
131
|
+
ACTIVATE = "activate"
|
132
|
+
DEACTIVATE = "deactivate"
|
83
133
|
RESTORE = "restore"
|
84
134
|
DELETE = "delete"
|
85
135
|
|
@@ -167,13 +217,3 @@ class BaseEnums:
|
|
167
217
|
EXP_1WK = int(1 * 7 * 24 * 60 * 60)
|
168
218
|
EXP_2WK = int(2 * 7 * 24 * 60 * 60)
|
169
219
|
EXP_1MO = int(1 * 30 * 24 * 60 * 60)
|
170
|
-
|
171
|
-
class ServiceDataSource(StrEnum):
|
172
|
-
CACHE = "cache"
|
173
|
-
DATABASE = "database"
|
174
|
-
MICROSERVICE = "microservice"
|
175
|
-
THIRD_PARTY = "third_party"
|
176
|
-
|
177
|
-
class ClientDataSource(StrEnum):
|
178
|
-
CACHE = "cache"
|
179
|
-
REQUEST = "request"
|
@@ -28,7 +28,7 @@ from maleo_foundation.managers.client.google.storage import GoogleCloudStorage
|
|
28
28
|
from maleo_foundation.managers.client.google.secret import GoogleSecretManager
|
29
29
|
from maleo_foundation.managers.middleware import MiddlewareManager
|
30
30
|
from maleo_foundation.types import BaseTypes
|
31
|
-
from maleo_foundation.utils.exceptions import
|
31
|
+
from maleo_foundation.utils.exceptions.request import BaseRequestExceptions
|
32
32
|
from maleo_foundation.utils.logging import (
|
33
33
|
SimpleConfig,
|
34
34
|
ApplicationLogger,
|
@@ -52,7 +52,7 @@ class ServiceManager:
|
|
52
52
|
self._db_metadata = db_metadata # * Declare DB Metadata
|
53
53
|
self._log_config = log_config # * Declare log config
|
54
54
|
self._settings = (
|
55
|
-
settings if settings is not None else Settings()
|
55
|
+
settings if settings is not None else Settings() # type: ignore
|
56
56
|
) # * Initialize settings
|
57
57
|
|
58
58
|
# * Disable google cloud logging if environment is local
|
@@ -244,13 +244,18 @@ class ServiceManager:
|
|
244
244
|
u_u=self.maleo_credentials.username,
|
245
245
|
u_e=self.maleo_credentials.email,
|
246
246
|
u_ut="service",
|
247
|
+
o_i=None,
|
248
|
+
o_uu=None,
|
249
|
+
o_k=None,
|
250
|
+
o_ot=None,
|
251
|
+
uor=None,
|
247
252
|
exp_in=1,
|
248
253
|
)
|
249
254
|
parameters = MaleoFoundationTokenParametersTransfers.Encode(
|
250
255
|
key=self._keys.private, password=self._keys.password, payload=payload
|
251
256
|
)
|
252
257
|
result = self._foundation.services.token.encode(parameters=parameters)
|
253
|
-
return result.data.token if result.success else None
|
258
|
+
return result.data.token if result.success and result.data is not None else None
|
254
259
|
|
255
260
|
def create_app(
|
256
261
|
self,
|
@@ -263,7 +268,7 @@ class ServiceManager:
|
|
263
268
|
self._app = FastAPI(
|
264
269
|
title=self.configurations.service.name,
|
265
270
|
version=version,
|
266
|
-
lifespan=lifespan,
|
271
|
+
lifespan=lifespan, # type: ignore
|
267
272
|
root_path=root_path,
|
268
273
|
)
|
269
274
|
self._loggers.application.info("FastAPI application created successfully")
|
@@ -284,11 +289,11 @@ class ServiceManager:
|
|
284
289
|
self._loggers.application.info("Adding exception handlers")
|
285
290
|
self._app.add_exception_handler(
|
286
291
|
exc_class_or_status_code=RequestValidationError,
|
287
|
-
handler=
|
292
|
+
handler=BaseRequestExceptions.validation_exception_handler, # type: ignore
|
288
293
|
)
|
289
294
|
self._app.add_exception_handler(
|
290
295
|
exc_class_or_status_code=HTTPException,
|
291
|
-
handler=
|
296
|
+
handler=BaseRequestExceptions.http_exception_handler, # type: ignore
|
292
297
|
)
|
293
298
|
self._loggers.application.info("Exception handlers added successfully")
|
294
299
|
|
@@ -307,10 +312,8 @@ class ServiceManager:
|
|
307
312
|
self._loggers.application.info("Disposing service manager")
|
308
313
|
if self._redis is not None:
|
309
314
|
await self._redis.close()
|
310
|
-
self._redis = None
|
311
315
|
if self._database is not None:
|
312
316
|
self._database.dispose()
|
313
|
-
self._database = None
|
314
317
|
self._loggers.application.info("Service manager disposed successfully")
|
315
318
|
if self._loggers is not None:
|
316
319
|
self._loggers.application.info("Disposing logger")
|
@@ -319,4 +322,3 @@ class ServiceManager:
|
|
319
322
|
self._loggers.database.dispose()
|
320
323
|
self._loggers.middleware.info("Disposing logger")
|
321
324
|
self._loggers.middleware.dispose()
|
322
|
-
self._loggers = None
|
@@ -10,7 +10,7 @@ from maleo_foundation.models.schemas import BaseGeneralSchemas
|
|
10
10
|
from maleo_foundation.models.transfers.parameters.token import (
|
11
11
|
MaleoFoundationTokenParametersTransfers,
|
12
12
|
)
|
13
|
-
from maleo_foundation.utils.exceptions import
|
13
|
+
from maleo_foundation.utils.exceptions.request import BaseRequestExceptions
|
14
14
|
|
15
15
|
|
16
16
|
class Backend(AuthenticationBackend):
|
@@ -100,5 +100,5 @@ def add_authentication_middleware(
|
|
100
100
|
app.add_middleware(
|
101
101
|
AuthenticationMiddleware,
|
102
102
|
backend=Backend(keys, maleo_foundation),
|
103
|
-
on_error=
|
103
|
+
on_error=BaseRequestExceptions.authentication_error_handler, # type: ignore
|
104
104
|
)
|
@@ -1,18 +1,48 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from fastapi import status
|
3
|
-
from pydantic import Field, model_validator
|
4
|
-
from typing import Dict, Type, Union
|
5
|
-
from maleo_foundation.models.schemas.result import BaseResultSchemas
|
3
|
+
from pydantic import BaseModel, Field, model_validator
|
4
|
+
from typing import Any, Dict, Optional, Type, Union
|
5
|
+
from maleo_foundation.models.schemas.result import BaseResultSchemas, ResultMetadata
|
6
6
|
from maleo_foundation.types import BaseTypes
|
7
7
|
|
8
8
|
|
9
9
|
class BaseResponses:
|
10
|
-
|
10
|
+
# * ----- ----- ----- Base ----- ----- ----- *#
|
11
|
+
class Base(BaseModel):
|
12
|
+
success: bool = Field(..., description="Success status")
|
13
|
+
code: BaseTypes.OptionalString = Field(None, description="Optional result code")
|
14
|
+
message: BaseTypes.OptionalString = Field(None, description="Optional message")
|
15
|
+
description: BaseTypes.OptionalString = Field(
|
16
|
+
None, description="Optional description"
|
17
|
+
)
|
18
|
+
data: Any = Field(..., description="Data")
|
19
|
+
metadata: Optional[ResultMetadata] = Field(
|
20
|
+
None, description="Optional metadata"
|
21
|
+
)
|
22
|
+
other: BaseTypes.OptionalAny = Field(
|
23
|
+
None, description="Optional other information"
|
24
|
+
)
|
25
|
+
|
26
|
+
# * ----- ----- ----- Intermediary ----- ----- ----- *#
|
27
|
+
class Fail(Base):
|
28
|
+
success: BaseTypes.LiteralFalse = Field(False, description="Success status") # type: ignore
|
29
|
+
code: str = "MAL-FAI-001" # type: ignore
|
30
|
+
message: str = "Fail result" # type: ignore
|
31
|
+
description: str = "Operation failed." # type: ignore
|
32
|
+
data: None = Field(None, description="No data")
|
11
33
|
other: BaseTypes.OptionalAny = Field(
|
12
34
|
"Please try again later or contact administrator.",
|
13
35
|
description="Response's other information",
|
14
36
|
)
|
15
37
|
|
38
|
+
class Success(Base):
|
39
|
+
success: BaseTypes.LiteralTrue = Field(True, description="Success status") # type: ignore
|
40
|
+
code: str = "MAL-SCS-001" # type: ignore
|
41
|
+
message: str = "Success result" # type: ignore
|
42
|
+
description: str = "Operation succeeded." # type: ignore
|
43
|
+
data: Any = Field(..., description="Data")
|
44
|
+
|
45
|
+
# * ----- ----- ----- Derived ----- ----- ----- *#
|
16
46
|
class BadRequest(Fail):
|
17
47
|
code: str = "MAL-BDR-001"
|
18
48
|
message: str = "Bad Request"
|
@@ -83,16 +113,32 @@ class BaseResponses:
|
|
83
113
|
message: str = "Resource not found"
|
84
114
|
description: str = "The requested resource can not be found."
|
85
115
|
|
86
|
-
class NoData(
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
class
|
93
|
-
|
94
|
-
|
95
|
-
|
116
|
+
class NoData(Success):
|
117
|
+
code: str = "MAL-NDT-001"
|
118
|
+
message: str = "No data found"
|
119
|
+
description: str = "No data found in the requested resource."
|
120
|
+
data: None = Field(None, description="No data")
|
121
|
+
|
122
|
+
class SingleData(Success):
|
123
|
+
code: str = "MAL-SGD-001"
|
124
|
+
message: str = "Single data found"
|
125
|
+
description: str = "Requested data found in database."
|
126
|
+
data: Any = Field(..., description="Fetched single data")
|
127
|
+
|
128
|
+
class UnpaginatedMultipleData(Success):
|
129
|
+
code: str = "MAL-MTD-001"
|
130
|
+
message: str = "Multiple unpaginated data found"
|
131
|
+
description: str = "Requested unpaginated data found in database."
|
132
|
+
data: BaseTypes.ListOfAny = Field(..., description="Unpaginated multiple data")
|
133
|
+
|
134
|
+
class PaginatedMultipleData(Success):
|
135
|
+
code: str = "MAL-MTD-002"
|
136
|
+
message: str = "Multiple paginated data found"
|
137
|
+
description: str = "Requested paginated data found in database."
|
138
|
+
total_data: int = Field(..., ge=0, description="Total data count")
|
139
|
+
pagination: BaseResultSchemas.ExtendedPagination = Field(
|
140
|
+
..., description="Pagination metadata"
|
141
|
+
)
|
96
142
|
page: int = Field(
|
97
143
|
1, ge=1, description="Page number, must be >= 1.", exclude=True
|
98
144
|
)
|
@@ -1,5 +1,7 @@
|
|
1
|
-
from
|
2
|
-
from
|
1
|
+
from datetime import datetime, timezone
|
2
|
+
from pydantic import BaseModel, Field, model_validator
|
3
|
+
from typing import Any, Dict, Optional, Self, Union
|
4
|
+
from maleo_foundation.enums import BaseEnums
|
3
5
|
from maleo_foundation.models.schemas.general import BaseGeneralSchemas
|
4
6
|
from maleo_foundation.types import BaseTypes
|
5
7
|
|
@@ -29,6 +31,29 @@ class BaseResultSchemas:
|
|
29
31
|
# * ----- ----- ----- Base ----- ----- ----- *#
|
30
32
|
class Base(BaseModel):
|
31
33
|
success: bool = Field(..., description="Success status")
|
34
|
+
exception: Optional[BaseEnums.ExceptionType] = Field(
|
35
|
+
None, description="Exception type (optional)"
|
36
|
+
)
|
37
|
+
timestamp: datetime = Field(datetime.now(timezone.utc), description="Timestamp")
|
38
|
+
origin: BaseEnums.OperationOrigin = Field(..., description="Operation origin")
|
39
|
+
layer: BaseEnums.OperationLayer = Field(..., description="Operation layer")
|
40
|
+
target: Optional[BaseEnums.OperationTarget] = Field(
|
41
|
+
None, description="Operation target (optional)"
|
42
|
+
)
|
43
|
+
environment: Optional[BaseEnums.EnvironmentType] = Field(
|
44
|
+
None, description="Operation target environment (optional)"
|
45
|
+
)
|
46
|
+
resource: str = Field(..., description="Resource name")
|
47
|
+
operation: BaseEnums.OperationType = Field(..., description="Operation type")
|
48
|
+
create_type: Optional[BaseEnums.CreateType] = Field(
|
49
|
+
None, description="Create type (optional)"
|
50
|
+
)
|
51
|
+
update_type: Optional[BaseEnums.UpdateType] = Field(
|
52
|
+
None, description="Update type (optional)"
|
53
|
+
)
|
54
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = Field(
|
55
|
+
None, description="Status update type (optional)"
|
56
|
+
)
|
32
57
|
code: BaseTypes.OptionalString = Field(None, description="Optional result code")
|
33
58
|
message: BaseTypes.OptionalString = Field(None, description="Optional message")
|
34
59
|
description: BaseTypes.OptionalString = Field(
|
@@ -42,9 +67,52 @@ class BaseResultSchemas:
|
|
42
67
|
None, description="Optional other information"
|
43
68
|
)
|
44
69
|
|
70
|
+
@model_validator(mode="after")
|
71
|
+
def verify_fields(self) -> Self:
|
72
|
+
"""Verify that the required fields are set."""
|
73
|
+
if self.origin is BaseEnums.OperationOrigin.SERVICE:
|
74
|
+
if self.layer not in BaseEnums.ServiceOperationLayer:
|
75
|
+
raise ValueError(
|
76
|
+
f"Invalid layer '{self.layer}' for service operation."
|
77
|
+
)
|
78
|
+
if self.target and self.target not in BaseEnums.ServiceOperationTarget:
|
79
|
+
raise ValueError(
|
80
|
+
f"Invalid target '{self.target}' for service operation."
|
81
|
+
)
|
82
|
+
elif self.origin is BaseEnums.OperationOrigin.CLIENT:
|
83
|
+
if self.layer not in BaseEnums.ClientOperationLayer:
|
84
|
+
raise ValueError(
|
85
|
+
f"Invalid layer '{self.layer}' for client operation."
|
86
|
+
)
|
87
|
+
if self.target and self.target not in BaseEnums.ClientOperationTarget:
|
88
|
+
raise ValueError(
|
89
|
+
f"Invalid target '{self.target}' for client operation."
|
90
|
+
)
|
91
|
+
else:
|
92
|
+
raise ValueError(
|
93
|
+
f"Invalid operation origin '{self.origin}'. Must be 'service' or 'client'."
|
94
|
+
)
|
95
|
+
|
96
|
+
if self.operation is BaseEnums.OperationType.CREATE:
|
97
|
+
if self.create_type is None:
|
98
|
+
raise ValueError("Create type must be set for create operations.")
|
99
|
+
elif self.operation is BaseEnums.OperationType.UPDATE:
|
100
|
+
if self.update_type is None:
|
101
|
+
raise ValueError("Update type must be set for update operations.")
|
102
|
+
if self.update_type is BaseEnums.UpdateType.STATUS:
|
103
|
+
if self.status_update_type is None:
|
104
|
+
raise ValueError(
|
105
|
+
"Status update type must be set for status update operations."
|
106
|
+
)
|
107
|
+
|
108
|
+
return self
|
109
|
+
|
45
110
|
# * ----- ----- ----- Intermediary ----- ----- ----- *#
|
46
111
|
class Fail(Base):
|
47
112
|
success: BaseTypes.LiteralFalse = Field(False, description="Success status") # type: ignore
|
113
|
+
exception: BaseEnums.ExceptionType = Field( # type: ignore
|
114
|
+
..., description="Exception type"
|
115
|
+
)
|
48
116
|
code: str = "MAL-FAI-001" # type: ignore
|
49
117
|
message: str = "Fail result" # type: ignore
|
50
118
|
description: str = "Operation failed." # type: ignore
|
@@ -60,9 +128,11 @@ class BaseResultSchemas:
|
|
60
128
|
# * ----- ----- ----- Derived ----- ----- ----- *#
|
61
129
|
class NotFound(Fail):
|
62
130
|
code: str = "MAL-NTF-001"
|
131
|
+
exception: BaseEnums.ExceptionType = Field(
|
132
|
+
BaseEnums.ExceptionType.NOT_FOUND, description="Exception type"
|
133
|
+
)
|
63
134
|
message: str = "Resource not found"
|
64
135
|
description: str = "The requested resource can not be found."
|
65
|
-
data: None = Field(None, description="No data")
|
66
136
|
|
67
137
|
class NoData(Success):
|
68
138
|
code: str = "MAL-NDT-001"
|
@@ -93,10 +163,5 @@ class BaseResultSchemas:
|
|
93
163
|
..., description="Pagination metadata"
|
94
164
|
)
|
95
165
|
|
96
|
-
class Get(BaseModel):
|
97
|
-
accessed_at: BaseTypes.OptionalDatetime = Field(
|
98
|
-
None, description="Accessed at timestamp"
|
99
|
-
)
|
100
|
-
|
101
166
|
|
102
167
|
BaseResultSchemas.PaginatedMultipleData.model_rebuild()
|
@@ -19,6 +19,9 @@ class RedisCacheNamespaces(BaseModel):
|
|
19
19
|
|
20
20
|
|
21
21
|
class RedisCacheConfigurations(BaseModel):
|
22
|
+
environment: BaseEnums.EnvironmentType = Field(
|
23
|
+
..., description="Redis cache's environment"
|
24
|
+
)
|
22
25
|
ttl: Union[int, float] = Field(
|
23
26
|
BaseEnums.Expiration.EXP_5MN, description="Default TTL"
|
24
27
|
)
|
@@ -1,8 +1,12 @@
|
|
1
1
|
from pydantic import BaseModel, ConfigDict, Field
|
2
2
|
from typing import Optional
|
3
|
+
from maleo_foundation.enums import BaseEnums
|
3
4
|
|
4
5
|
|
5
6
|
class MaleoClientConfigurations(BaseModel):
|
7
|
+
environment: BaseEnums.EnvironmentType = Field(
|
8
|
+
..., description="Client's environment"
|
9
|
+
)
|
6
10
|
key: str = Field(..., description="Client's key")
|
7
11
|
name: str = Field(..., description="Client's name")
|
8
12
|
url: str = Field(..., description="Client's URL")
|
@@ -1,37 +1,41 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from httpx import Response
|
3
3
|
from pydantic import BaseModel, ConfigDict, Field, model_validator
|
4
|
-
from typing import Any
|
4
|
+
from typing import Any, Self
|
5
5
|
|
6
6
|
|
7
7
|
class BaseClientHTTPControllerResults(BaseModel):
|
8
8
|
model_config = ConfigDict(arbitrary_types_allowed=True)
|
9
9
|
|
10
10
|
response: Response = Field(..., description="Client's HTTP Controller response")
|
11
|
-
status_code: int = Field(
|
12
|
-
..., description="Client's HTTP Controller response status code"
|
13
|
-
)
|
14
|
-
content: Any = Field(..., description="Client's HTTP Controller response content")
|
15
|
-
success: bool = Field(..., description="Client's HTTP Controller success status")
|
16
11
|
|
17
|
-
@model_validator(mode="
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
12
|
+
@model_validator(mode="after")
|
13
|
+
def verify_response(self) -> Self:
|
14
|
+
"""Verify that the response is an instance of httpx.Response."""
|
15
|
+
if not isinstance(self.response, Response):
|
16
|
+
raise TypeError("Response must be an instance of httpx.Response")
|
17
|
+
return self
|
22
18
|
|
23
|
-
|
24
|
-
|
25
|
-
|
19
|
+
@property
|
20
|
+
def status_code(self) -> int:
|
21
|
+
"""Get the status code of the response."""
|
22
|
+
return self.response.status_code
|
26
23
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
values["content"] = response.json()
|
32
|
-
elif "text/" in content_type or "application/xml" in content_type:
|
33
|
-
values["content"] = response.text
|
34
|
-
else:
|
35
|
-
values["content"] = response.content # * Raw bytes for unknown types
|
24
|
+
@property
|
25
|
+
def success(self) -> bool:
|
26
|
+
"""Get the success status of the response."""
|
27
|
+
return self.response.is_success
|
36
28
|
|
37
|
-
|
29
|
+
@property
|
30
|
+
def content(self) -> Any:
|
31
|
+
"""Get the content of the response."""
|
32
|
+
# * Determine content type and parse accordingly
|
33
|
+
content_type: str = self.response.headers.get("content-type", "")
|
34
|
+
content_type = content_type.lower()
|
35
|
+
if "application/json" in content_type:
|
36
|
+
content = self.response.json()
|
37
|
+
elif "text/" in content_type or "application/xml" in content_type:
|
38
|
+
content = self.response.text
|
39
|
+
else:
|
40
|
+
content = self.response.content # * Raw bytes for unknown types
|
41
|
+
return content
|
@@ -1,7 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from pydantic import
|
3
|
-
from typing import Optional
|
4
|
-
from maleo_foundation.enums import BaseEnums
|
2
|
+
from pydantic import model_validator
|
5
3
|
from maleo_foundation.models.schemas.result import BaseResultSchemas
|
6
4
|
|
7
5
|
|
@@ -35,8 +33,3 @@ class BaseClientServiceResultsTransfers:
|
|
35
33
|
values["total_data"] = pagination.total_data
|
36
34
|
|
37
35
|
return values
|
38
|
-
|
39
|
-
class Get(BaseResultSchemas.Get):
|
40
|
-
source: Optional[BaseEnums.ClientDataSource] = Field(
|
41
|
-
None, description="Data source"
|
42
|
-
)
|
@@ -1,7 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from pydantic import
|
3
|
-
from typing import Optional
|
4
|
-
from maleo_foundation.enums import BaseEnums
|
2
|
+
from pydantic import model_validator
|
5
3
|
from maleo_foundation.models.schemas.result import BaseResultSchemas
|
6
4
|
|
7
5
|
|
@@ -45,8 +43,3 @@ class BaseServiceGeneralResultsTransfers:
|
|
45
43
|
total_pages=total_pages,
|
46
44
|
)
|
47
45
|
return values
|
48
|
-
|
49
|
-
class Get(BaseResultSchemas.Get):
|
50
|
-
source: Optional[BaseEnums.ServiceDataSource] = Field(
|
51
|
-
None, description="Data source"
|
52
|
-
)
|
@@ -1,6 +1,5 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from .formatter import BaseFormatter
|
3
|
-
from .exceptions import BaseExceptions
|
4
3
|
from .loaders import BaseLoaders
|
5
4
|
from .controller import BaseControllerUtils
|
6
5
|
from .query import BaseQueryUtils
|
@@ -8,7 +7,6 @@ from .query import BaseQueryUtils
|
|
8
7
|
|
9
8
|
class BaseUtils:
|
10
9
|
Formatter = BaseFormatter
|
11
|
-
Exceptions = BaseExceptions
|
12
10
|
Loaders = BaseLoaders
|
13
11
|
Controller = BaseControllerUtils
|
14
12
|
Query = BaseQueryUtils
|
File without changes
|
@@ -0,0 +1,221 @@
|
|
1
|
+
from datetime import datetime, timezone
|
2
|
+
from functools import wraps
|
3
|
+
from httpx import RequestError
|
4
|
+
from pydantic import ValidationError
|
5
|
+
from typing import Optional
|
6
|
+
from maleo_foundation.enums import BaseEnums
|
7
|
+
from maleo_foundation.models.transfers.results.client.service import (
|
8
|
+
BaseClientServiceResultsTransfers,
|
9
|
+
)
|
10
|
+
from maleo_foundation.utils.logging import BaseLogger
|
11
|
+
|
12
|
+
|
13
|
+
class BaseClientExceptions:
|
14
|
+
@staticmethod
|
15
|
+
def _exception_handler(
|
16
|
+
layer: BaseEnums.OperationLayer,
|
17
|
+
resource: str,
|
18
|
+
operation: BaseEnums.OperationType,
|
19
|
+
summary: str,
|
20
|
+
e: Exception,
|
21
|
+
exception: BaseEnums.ExceptionType,
|
22
|
+
category: str,
|
23
|
+
description: str,
|
24
|
+
target: Optional[BaseEnums.OperationTarget] = None,
|
25
|
+
environment: Optional[BaseEnums.EnvironmentType] = None,
|
26
|
+
create_type: Optional[BaseEnums.CreateType] = None,
|
27
|
+
update_type: Optional[BaseEnums.UpdateType] = None,
|
28
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = None,
|
29
|
+
logger: Optional[BaseLogger] = None,
|
30
|
+
fail_result_class: type[
|
31
|
+
BaseClientServiceResultsTransfers.Fail
|
32
|
+
] = BaseClientServiceResultsTransfers.Fail,
|
33
|
+
) -> BaseClientServiceResultsTransfers.Fail:
|
34
|
+
if logger:
|
35
|
+
logger.error(
|
36
|
+
f"{category} occurred while {summary}: '{str(e)}'",
|
37
|
+
exc_info=True,
|
38
|
+
)
|
39
|
+
return fail_result_class(
|
40
|
+
success=False,
|
41
|
+
exception=exception,
|
42
|
+
timestamp=datetime.now(timezone.utc),
|
43
|
+
origin=BaseEnums.OperationOrigin.CLIENT,
|
44
|
+
layer=layer,
|
45
|
+
target=target,
|
46
|
+
environment=environment,
|
47
|
+
resource=resource,
|
48
|
+
operation=operation,
|
49
|
+
create_type=create_type,
|
50
|
+
update_type=update_type,
|
51
|
+
status_update_type=status_update_type,
|
52
|
+
message=f"Failed {summary}",
|
53
|
+
description=description,
|
54
|
+
data=None,
|
55
|
+
metadata=None,
|
56
|
+
other=category,
|
57
|
+
)
|
58
|
+
|
59
|
+
@staticmethod
|
60
|
+
def async_exception_handler(
|
61
|
+
layer: BaseEnums.OperationLayer,
|
62
|
+
resource: str,
|
63
|
+
operation: BaseEnums.OperationType,
|
64
|
+
summary: str,
|
65
|
+
target: Optional[BaseEnums.OperationTarget] = None,
|
66
|
+
environment: Optional[BaseEnums.EnvironmentType] = None,
|
67
|
+
create_type: Optional[BaseEnums.CreateType] = None,
|
68
|
+
update_type: Optional[BaseEnums.UpdateType] = None,
|
69
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = None,
|
70
|
+
logger: Optional[BaseLogger] = None,
|
71
|
+
fail_result_class: type[
|
72
|
+
BaseClientServiceResultsTransfers.Fail
|
73
|
+
] = BaseClientServiceResultsTransfers.Fail,
|
74
|
+
):
|
75
|
+
"""Decorator to handle exceptions consistently for async operation functions."""
|
76
|
+
|
77
|
+
def decorator(func):
|
78
|
+
@wraps(func)
|
79
|
+
async def wrapper(*args, **kwargs):
|
80
|
+
try:
|
81
|
+
return await func(*args, **kwargs)
|
82
|
+
except ValidationError as e:
|
83
|
+
return BaseClientExceptions._exception_handler(
|
84
|
+
layer=layer,
|
85
|
+
resource=resource,
|
86
|
+
operation=operation,
|
87
|
+
summary=summary,
|
88
|
+
e=e,
|
89
|
+
exception=BaseEnums.ExceptionType.VALIDATION,
|
90
|
+
category="Validation error",
|
91
|
+
description=f"A validation error occurred while {operation}. Please try again later or contact administrator.",
|
92
|
+
target=target,
|
93
|
+
environment=environment,
|
94
|
+
create_type=create_type,
|
95
|
+
update_type=update_type,
|
96
|
+
status_update_type=status_update_type,
|
97
|
+
logger=logger,
|
98
|
+
fail_result_class=fail_result_class,
|
99
|
+
)
|
100
|
+
except RequestError as e:
|
101
|
+
return BaseClientExceptions._exception_handler(
|
102
|
+
layer=layer,
|
103
|
+
resource=resource,
|
104
|
+
operation=operation,
|
105
|
+
summary=summary,
|
106
|
+
e=e,
|
107
|
+
exception=BaseEnums.ExceptionType.UNAVAILABLE,
|
108
|
+
category="Request error",
|
109
|
+
description=f"A request error occurred while {operation}. Please try again later or contact administrator.",
|
110
|
+
target=target,
|
111
|
+
environment=environment,
|
112
|
+
create_type=create_type,
|
113
|
+
update_type=update_type,
|
114
|
+
status_update_type=status_update_type,
|
115
|
+
logger=logger,
|
116
|
+
fail_result_class=fail_result_class,
|
117
|
+
)
|
118
|
+
except Exception as e:
|
119
|
+
return BaseClientExceptions._exception_handler(
|
120
|
+
layer=layer,
|
121
|
+
resource=resource,
|
122
|
+
operation=operation,
|
123
|
+
summary=summary,
|
124
|
+
e=e,
|
125
|
+
exception=BaseEnums.ExceptionType.INTERNAL,
|
126
|
+
category="Internal processing error",
|
127
|
+
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
128
|
+
target=target,
|
129
|
+
environment=environment,
|
130
|
+
create_type=create_type,
|
131
|
+
update_type=update_type,
|
132
|
+
status_update_type=status_update_type,
|
133
|
+
logger=logger,
|
134
|
+
fail_result_class=fail_result_class,
|
135
|
+
)
|
136
|
+
|
137
|
+
return wrapper
|
138
|
+
|
139
|
+
return decorator
|
140
|
+
|
141
|
+
@staticmethod
|
142
|
+
def sync_exception_handler(
|
143
|
+
layer: BaseEnums.OperationLayer,
|
144
|
+
resource: str,
|
145
|
+
operation: BaseEnums.OperationType,
|
146
|
+
summary: str,
|
147
|
+
target: Optional[BaseEnums.OperationTarget] = None,
|
148
|
+
environment: Optional[BaseEnums.EnvironmentType] = None,
|
149
|
+
create_type: Optional[BaseEnums.CreateType] = None,
|
150
|
+
update_type: Optional[BaseEnums.UpdateType] = None,
|
151
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = None,
|
152
|
+
logger: Optional[BaseLogger] = None,
|
153
|
+
fail_result_class: type[
|
154
|
+
BaseClientServiceResultsTransfers.Fail
|
155
|
+
] = BaseClientServiceResultsTransfers.Fail,
|
156
|
+
):
|
157
|
+
"""Decorator to handle exceptions consistently for sync operation functions."""
|
158
|
+
|
159
|
+
def decorator(func):
|
160
|
+
@wraps(func)
|
161
|
+
def wrapper(*args, **kwargs):
|
162
|
+
try:
|
163
|
+
return func(*args, **kwargs)
|
164
|
+
except ValidationError as e:
|
165
|
+
return BaseClientExceptions._exception_handler(
|
166
|
+
layer=layer,
|
167
|
+
resource=resource,
|
168
|
+
operation=operation,
|
169
|
+
summary=summary,
|
170
|
+
e=e,
|
171
|
+
exception=BaseEnums.ExceptionType.VALIDATION,
|
172
|
+
category="Validation error",
|
173
|
+
description=f"A validation error occurred while {operation}. Please try again later or contact administrator.",
|
174
|
+
target=target,
|
175
|
+
environment=environment,
|
176
|
+
create_type=create_type,
|
177
|
+
update_type=update_type,
|
178
|
+
status_update_type=status_update_type,
|
179
|
+
logger=logger,
|
180
|
+
fail_result_class=fail_result_class,
|
181
|
+
)
|
182
|
+
except RequestError as e:
|
183
|
+
return BaseClientExceptions._exception_handler(
|
184
|
+
layer=layer,
|
185
|
+
resource=resource,
|
186
|
+
operation=operation,
|
187
|
+
summary=summary,
|
188
|
+
e=e,
|
189
|
+
exception=BaseEnums.ExceptionType.UNAVAILABLE,
|
190
|
+
category="Request error",
|
191
|
+
description=f"A request error occurred while {operation}. Please try again later or contact administrator.",
|
192
|
+
target=target,
|
193
|
+
environment=environment,
|
194
|
+
create_type=create_type,
|
195
|
+
update_type=update_type,
|
196
|
+
status_update_type=status_update_type,
|
197
|
+
logger=logger,
|
198
|
+
fail_result_class=fail_result_class,
|
199
|
+
)
|
200
|
+
except Exception as e:
|
201
|
+
return BaseClientExceptions._exception_handler(
|
202
|
+
layer=layer,
|
203
|
+
resource=resource,
|
204
|
+
operation=operation,
|
205
|
+
summary=summary,
|
206
|
+
e=e,
|
207
|
+
exception=BaseEnums.ExceptionType.INTERNAL,
|
208
|
+
category="Internal processing error",
|
209
|
+
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
210
|
+
target=target,
|
211
|
+
environment=environment,
|
212
|
+
create_type=create_type,
|
213
|
+
update_type=update_type,
|
214
|
+
status_update_type=status_update_type,
|
215
|
+
logger=logger,
|
216
|
+
fail_result_class=fail_result_class,
|
217
|
+
)
|
218
|
+
|
219
|
+
return wrapper
|
220
|
+
|
221
|
+
return decorator
|
@@ -0,0 +1,38 @@
|
|
1
|
+
from fastapi import Request, status
|
2
|
+
from fastapi.encoders import jsonable_encoder
|
3
|
+
from fastapi.exceptions import RequestValidationError
|
4
|
+
from fastapi.responses import JSONResponse
|
5
|
+
from starlette.exceptions import HTTPException as StarletteHTTPException
|
6
|
+
from maleo_foundation.models.responses import BaseResponses
|
7
|
+
|
8
|
+
|
9
|
+
class BaseRequestExceptions:
|
10
|
+
@staticmethod
|
11
|
+
def authentication_error_handler(request: Request, exc: Exception):
|
12
|
+
return JSONResponse(
|
13
|
+
content=BaseResponses.Unauthorized(other=str(exc)).model_dump(mode="json"), # type: ignore
|
14
|
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
15
|
+
)
|
16
|
+
|
17
|
+
@staticmethod
|
18
|
+
async def validation_exception_handler(
|
19
|
+
request: Request, exc: RequestValidationError
|
20
|
+
):
|
21
|
+
serialized_error = jsonable_encoder(exc.errors())
|
22
|
+
return JSONResponse(
|
23
|
+
content=BaseResponses.ValidationError(other=serialized_error).model_dump(mode="json"), # type: ignore
|
24
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
25
|
+
)
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
|
29
|
+
if exc.status_code in BaseResponses.other_responses:
|
30
|
+
return JSONResponse(
|
31
|
+
content=BaseResponses.other_responses[exc.status_code]["model"]().model_dump(mode="json"), # type: ignore
|
32
|
+
status_code=exc.status_code,
|
33
|
+
)
|
34
|
+
|
35
|
+
return JSONResponse(
|
36
|
+
content=BaseResponses.ServerError().model_dump(mode="json"), # type: ignore
|
37
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
38
|
+
)
|
@@ -0,0 +1,221 @@
|
|
1
|
+
from datetime import datetime, timezone
|
2
|
+
from functools import wraps
|
3
|
+
from pydantic import ValidationError
|
4
|
+
from sqlalchemy.exc import SQLAlchemyError
|
5
|
+
from typing import Optional
|
6
|
+
from maleo_foundation.enums import BaseEnums
|
7
|
+
from maleo_foundation.models.transfers.results.service.general import (
|
8
|
+
BaseServiceGeneralResultsTransfers,
|
9
|
+
)
|
10
|
+
from maleo_foundation.utils.logging import BaseLogger
|
11
|
+
|
12
|
+
|
13
|
+
class BaseServiceExceptions:
|
14
|
+
@staticmethod
|
15
|
+
def _exception_handler(
|
16
|
+
layer: BaseEnums.OperationLayer,
|
17
|
+
resource: str,
|
18
|
+
operation: BaseEnums.OperationType,
|
19
|
+
summary: str,
|
20
|
+
e: Exception,
|
21
|
+
exception: BaseEnums.ExceptionType,
|
22
|
+
category: str,
|
23
|
+
description: str,
|
24
|
+
target: Optional[BaseEnums.OperationTarget] = None,
|
25
|
+
environment: Optional[BaseEnums.EnvironmentType] = None,
|
26
|
+
create_type: Optional[BaseEnums.CreateType] = None,
|
27
|
+
update_type: Optional[BaseEnums.UpdateType] = None,
|
28
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = None,
|
29
|
+
logger: Optional[BaseLogger] = None,
|
30
|
+
fail_result_class: type[
|
31
|
+
BaseServiceGeneralResultsTransfers.Fail
|
32
|
+
] = BaseServiceGeneralResultsTransfers.Fail,
|
33
|
+
) -> BaseServiceGeneralResultsTransfers.Fail:
|
34
|
+
if logger:
|
35
|
+
logger.error(
|
36
|
+
f"{category} occurred while {summary}: '{str(e)}'",
|
37
|
+
exc_info=True,
|
38
|
+
)
|
39
|
+
return fail_result_class(
|
40
|
+
success=False,
|
41
|
+
exception=exception,
|
42
|
+
timestamp=datetime.now(timezone.utc),
|
43
|
+
origin=BaseEnums.OperationOrigin.SERVICE,
|
44
|
+
layer=layer,
|
45
|
+
target=target,
|
46
|
+
environment=environment,
|
47
|
+
resource=resource,
|
48
|
+
operation=operation,
|
49
|
+
create_type=create_type,
|
50
|
+
update_type=update_type,
|
51
|
+
status_update_type=status_update_type,
|
52
|
+
message=f"Failed {summary}",
|
53
|
+
description=description,
|
54
|
+
data=None,
|
55
|
+
metadata=None,
|
56
|
+
other=category,
|
57
|
+
)
|
58
|
+
|
59
|
+
@staticmethod
|
60
|
+
def async_exception_handler(
|
61
|
+
layer: BaseEnums.OperationLayer,
|
62
|
+
resource: str,
|
63
|
+
operation: BaseEnums.OperationType,
|
64
|
+
summary: str,
|
65
|
+
target: Optional[BaseEnums.OperationTarget] = None,
|
66
|
+
environment: Optional[BaseEnums.EnvironmentType] = None,
|
67
|
+
create_type: Optional[BaseEnums.CreateType] = None,
|
68
|
+
update_type: Optional[BaseEnums.UpdateType] = None,
|
69
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = None,
|
70
|
+
logger: Optional[BaseLogger] = None,
|
71
|
+
fail_result_class: type[
|
72
|
+
BaseServiceGeneralResultsTransfers.Fail
|
73
|
+
] = BaseServiceGeneralResultsTransfers.Fail,
|
74
|
+
):
|
75
|
+
"""Decorator to handle exceptions consistently for async operation functions."""
|
76
|
+
|
77
|
+
def decorator(func):
|
78
|
+
@wraps(func)
|
79
|
+
async def wrapper(*args, **kwargs):
|
80
|
+
try:
|
81
|
+
return await func(*args, **kwargs)
|
82
|
+
except ValidationError as e:
|
83
|
+
return BaseServiceExceptions._exception_handler(
|
84
|
+
layer=layer,
|
85
|
+
resource=resource,
|
86
|
+
operation=operation,
|
87
|
+
summary=summary,
|
88
|
+
e=e,
|
89
|
+
exception=BaseEnums.ExceptionType.VALIDATION,
|
90
|
+
category="Validation error",
|
91
|
+
description=f"A validation error occurred while {operation}. Please try again later or contact administrator.",
|
92
|
+
target=target,
|
93
|
+
environment=environment,
|
94
|
+
create_type=create_type,
|
95
|
+
update_type=update_type,
|
96
|
+
status_update_type=status_update_type,
|
97
|
+
logger=logger,
|
98
|
+
fail_result_class=fail_result_class,
|
99
|
+
)
|
100
|
+
except SQLAlchemyError as e:
|
101
|
+
return BaseServiceExceptions._exception_handler(
|
102
|
+
layer=layer,
|
103
|
+
resource=resource,
|
104
|
+
operation=operation,
|
105
|
+
summary=summary,
|
106
|
+
e=e,
|
107
|
+
exception=BaseEnums.ExceptionType.INTERNAL,
|
108
|
+
category="Database error",
|
109
|
+
description=f"A database error occurred while {operation}. Please try again later or contact administrator.",
|
110
|
+
target=target,
|
111
|
+
environment=environment,
|
112
|
+
create_type=create_type,
|
113
|
+
update_type=update_type,
|
114
|
+
status_update_type=status_update_type,
|
115
|
+
logger=logger,
|
116
|
+
fail_result_class=fail_result_class,
|
117
|
+
)
|
118
|
+
except Exception as e:
|
119
|
+
return BaseServiceExceptions._exception_handler(
|
120
|
+
layer=layer,
|
121
|
+
resource=resource,
|
122
|
+
operation=operation,
|
123
|
+
summary=summary,
|
124
|
+
e=e,
|
125
|
+
exception=BaseEnums.ExceptionType.INTERNAL,
|
126
|
+
category="Internal processing error",
|
127
|
+
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
128
|
+
target=target,
|
129
|
+
environment=environment,
|
130
|
+
create_type=create_type,
|
131
|
+
update_type=update_type,
|
132
|
+
status_update_type=status_update_type,
|
133
|
+
logger=logger,
|
134
|
+
fail_result_class=fail_result_class,
|
135
|
+
)
|
136
|
+
|
137
|
+
return wrapper
|
138
|
+
|
139
|
+
return decorator
|
140
|
+
|
141
|
+
@staticmethod
|
142
|
+
def sync_exception_handler(
|
143
|
+
layer: BaseEnums.OperationLayer,
|
144
|
+
resource: str,
|
145
|
+
operation: BaseEnums.OperationType,
|
146
|
+
summary: str,
|
147
|
+
target: Optional[BaseEnums.OperationTarget] = None,
|
148
|
+
environment: Optional[BaseEnums.EnvironmentType] = None,
|
149
|
+
create_type: Optional[BaseEnums.CreateType] = None,
|
150
|
+
update_type: Optional[BaseEnums.UpdateType] = None,
|
151
|
+
status_update_type: Optional[BaseEnums.StatusUpdateType] = None,
|
152
|
+
logger: Optional[BaseLogger] = None,
|
153
|
+
fail_result_class: type[
|
154
|
+
BaseServiceGeneralResultsTransfers.Fail
|
155
|
+
] = BaseServiceGeneralResultsTransfers.Fail,
|
156
|
+
):
|
157
|
+
"""Decorator to handle exceptions consistently for sync operation functions."""
|
158
|
+
|
159
|
+
def decorator(func):
|
160
|
+
@wraps(func)
|
161
|
+
def wrapper(*args, **kwargs):
|
162
|
+
try:
|
163
|
+
return func(*args, **kwargs)
|
164
|
+
except ValidationError as e:
|
165
|
+
return BaseServiceExceptions._exception_handler(
|
166
|
+
layer=layer,
|
167
|
+
resource=resource,
|
168
|
+
operation=operation,
|
169
|
+
summary=summary,
|
170
|
+
e=e,
|
171
|
+
exception=BaseEnums.ExceptionType.VALIDATION,
|
172
|
+
category="Validation error",
|
173
|
+
description=f"A validation error occurred while {operation}. Please try again later or contact administrator.",
|
174
|
+
target=target,
|
175
|
+
environment=environment,
|
176
|
+
create_type=create_type,
|
177
|
+
update_type=update_type,
|
178
|
+
status_update_type=status_update_type,
|
179
|
+
logger=logger,
|
180
|
+
fail_result_class=fail_result_class,
|
181
|
+
)
|
182
|
+
except SQLAlchemyError as e:
|
183
|
+
return BaseServiceExceptions._exception_handler(
|
184
|
+
layer=layer,
|
185
|
+
resource=resource,
|
186
|
+
operation=operation,
|
187
|
+
summary=summary,
|
188
|
+
e=e,
|
189
|
+
exception=BaseEnums.ExceptionType.INTERNAL,
|
190
|
+
category="Database error",
|
191
|
+
description=f"A database error occurred while {operation}. Please try again later or contact administrator.",
|
192
|
+
target=target,
|
193
|
+
environment=environment,
|
194
|
+
create_type=create_type,
|
195
|
+
update_type=update_type,
|
196
|
+
status_update_type=status_update_type,
|
197
|
+
logger=logger,
|
198
|
+
fail_result_class=fail_result_class,
|
199
|
+
)
|
200
|
+
except Exception as e:
|
201
|
+
return BaseServiceExceptions._exception_handler(
|
202
|
+
layer=layer,
|
203
|
+
resource=resource,
|
204
|
+
operation=operation,
|
205
|
+
summary=summary,
|
206
|
+
e=e,
|
207
|
+
exception=BaseEnums.ExceptionType.INTERNAL,
|
208
|
+
category="Internal processing error",
|
209
|
+
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
210
|
+
target=target,
|
211
|
+
environment=environment,
|
212
|
+
create_type=create_type,
|
213
|
+
update_type=update_type,
|
214
|
+
status_update_type=status_update_type,
|
215
|
+
logger=logger,
|
216
|
+
fail_result_class=fail_result_class,
|
217
|
+
)
|
218
|
+
|
219
|
+
return wrapper
|
220
|
+
|
221
|
+
return decorator
|
@@ -2,7 +2,7 @@ maleo_foundation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
2
2
|
maleo_foundation/authentication.py,sha256=2Y2py-teDSO_YTFdZiPtuYhC8r3qIzn7CKyLNN8b2NQ,2727
|
3
3
|
maleo_foundation/authorization.py,sha256=8P1hleBYRv8kda4uQcbHVujHVAlI92YV1Flfzf-oJEU,285
|
4
4
|
maleo_foundation/constants.py,sha256=cgW2TjXYEdQRoYCL3fMk3r5B2Yr-Av67CaEAdY5SZ6o,1529
|
5
|
-
maleo_foundation/enums.py,sha256=
|
5
|
+
maleo_foundation/enums.py,sha256=AwfCsYBa8ieqxc6N0gVwqJ7GFj7M76qI1mDw_9LrU9I,6153
|
6
6
|
maleo_foundation/extended_types.py,sha256=oOAYc5f89WcPt5OWEaNdeceENHiPVr4KDhdttg6bA_w,305
|
7
7
|
maleo_foundation/rest_controller_result.py,sha256=uZxBxZ5hB98q1B4hNyRigHcO0560NYfUjq8L662aOPw,2172
|
8
8
|
maleo_foundation/types.py,sha256=Tq50KOISbnsMslVGBCqlY77lRAQZa-UUFDGqqwRglow,2466
|
@@ -36,7 +36,7 @@ maleo_foundation/managers/configuration.py,sha256=Zc397mT3Qn1Q_gDeuDVKl5YA3bSM-o
|
|
36
36
|
maleo_foundation/managers/credential.py,sha256=um1M45deBEzTVfsUcpAtKEp3Rb_dH1qQrr8abkG_GeU,3057
|
37
37
|
maleo_foundation/managers/db.py,sha256=y0rQIg-vohhFUtck3v1LCdXov7XYjy9PFiCsVtcg8VI,6496
|
38
38
|
maleo_foundation/managers/middleware.py,sha256=Uglwt4X3MauKtBvbPTyHl0-32od3IN6AYYUtiUCoV9I,2464
|
39
|
-
maleo_foundation/managers/service.py,sha256=
|
39
|
+
maleo_foundation/managers/service.py,sha256=YRG1cLc7yGytDXzOe-btKJ5K0YRHJfkgfGF3D5h3ty4,11795
|
40
40
|
maleo_foundation/managers/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
41
41
|
maleo_foundation/managers/client/base.py,sha256=iM5xZjLm5VQqqpiYcba-rifW0LgkVd-gRTE6XwdOFqY,4369
|
42
42
|
maleo_foundation/managers/client/maleo.py,sha256=ATZXgP8OGqoF51mxjg21UTuWwQbVte-iY0lJ4liNaog,2648
|
@@ -46,11 +46,11 @@ maleo_foundation/managers/client/google/parameter.py,sha256=emBgc1qCQcnETKYvwv35
|
|
46
46
|
maleo_foundation/managers/client/google/secret.py,sha256=75q32U-kcTljVb19MZQQ5sOVOnf1HkquyK8nIoyeMrY,5014
|
47
47
|
maleo_foundation/managers/client/google/storage.py,sha256=uUc3RGu5PyGOKrObP-ub2Vpztqidu5BUADUrRTMxy7E,6569
|
48
48
|
maleo_foundation/managers/client/google/subscription.py,sha256=KLXneM39r8Uzvevir_jL7s9-q4iSakNUkD_I66JGbng,5365
|
49
|
-
maleo_foundation/middlewares/authentication.py,sha256=
|
49
|
+
maleo_foundation/middlewares/authentication.py,sha256=b4dPkLKFqJBmhWKEvynTLe45Wax8jCcPq0luIlU_id0,4189
|
50
50
|
maleo_foundation/middlewares/base.py,sha256=ZXMJTiuDBa6sIbgD_g1MhhlMkszsYkt3Ocl4boPtbEU,16825
|
51
51
|
maleo_foundation/middlewares/cors.py,sha256=1QgRXOcURuEhBYMerclqbECgtAE4CFo0EhB4gJXu8Yg,2294
|
52
52
|
maleo_foundation/models/__init__.py,sha256=OlZXaeOhGXz_FppPm87jIOItnr-r179QhIcOWDOORyQ,248
|
53
|
-
maleo_foundation/models/responses.py,sha256=
|
53
|
+
maleo_foundation/models/responses.py,sha256=Tg--iTXwA0zHhd991mJiHIrBbqEW8QYC-pCM5yboIzI,8489
|
54
54
|
maleo_foundation/models/table.py,sha256=k0-OtahF2KRmvFUL8TborT6PoIhGsyoVrPJBKGg1QbU,1855
|
55
55
|
maleo_foundation/models/schemas/__init__.py,sha256=tmjBCyG4uMRjiTbnbhIjZaR8q7zk0_J_CqnRzsSfoBQ,279
|
56
56
|
maleo_foundation/models/schemas/encryption.py,sha256=S86FGlcBhyGxxZ5ObNSHTjSDwBUlUtLOMoCAKd5wE34,687
|
@@ -58,7 +58,7 @@ maleo_foundation/models/schemas/general.py,sha256=jxzBsVGsdKKEiM14MfV47dDiAZalUK
|
|
58
58
|
maleo_foundation/models/schemas/hash.py,sha256=jthDmu_VTBydffPruAIAiR8l0Xs6IrlgTptaP42zr1M,447
|
59
59
|
maleo_foundation/models/schemas/key.py,sha256=LSEDQpaCxavwp5je2O-ZNyOPtrFW_lXDywF9LK-An1w,622
|
60
60
|
maleo_foundation/models/schemas/parameter.py,sha256=OE1hg100lEa2IlGlT2Zz6PJ-OcC-6ZfDzsTOeJvvEig,3907
|
61
|
-
maleo_foundation/models/schemas/result.py,sha256=
|
61
|
+
maleo_foundation/models/schemas/result.py,sha256=MTRobolQeFuhjJCV652fALgLraGwCaXfcL1yRWG54tI,7772
|
62
62
|
maleo_foundation/models/schemas/signature.py,sha256=h0sa91vnCaivmvlbqOd7RLiCz8qAY8gCzEnm0DOBlSg,649
|
63
63
|
maleo_foundation/models/schemas/token.py,sha256=eh4k9rm_MoaCfGV3Nqa7yFH-PH7Ec6WY4RxHhbF4m5U,591
|
64
64
|
maleo_foundation/models/transfers/__init__.py,sha256=V5kdd8wuXqe78bQ7HG3a8vW3Rkke2wTr6mb5lC0IQJg,301
|
@@ -76,9 +76,9 @@ maleo_foundation/models/transfers/general/configurations/database.py,sha256=4j46
|
|
76
76
|
maleo_foundation/models/transfers/general/configurations/middleware.py,sha256=gBm7yv-PYOPcv-u6SXq8cMWfuuo9LwPSXuqoJ4uw9h0,1761
|
77
77
|
maleo_foundation/models/transfers/general/configurations/service.py,sha256=1sDBwJYvO7tlKz9YH7eIkfMPWmUqRkx7aW-EMw8tpBQ,306
|
78
78
|
maleo_foundation/models/transfers/general/configurations/cache/__init__.py,sha256=eCEeFFP4jN9FWFHWLadAnP1NoJH4CJQm7WRnXhmHUh0,264
|
79
|
-
maleo_foundation/models/transfers/general/configurations/cache/redis.py,sha256=
|
79
|
+
maleo_foundation/models/transfers/general/configurations/cache/redis.py,sha256=SNnI7hm8giKfR2Kp5sD_fmxo4Q5fkRCdi9zMKwTKPCs,1331
|
80
80
|
maleo_foundation/models/transfers/general/configurations/client/__init__.py,sha256=1w17i9CH4bSQ40o8rwIew2F_id25XklFqI1YPowcHvQ,356
|
81
|
-
maleo_foundation/models/transfers/general/configurations/client/maleo.py,sha256=
|
81
|
+
maleo_foundation/models/transfers/general/configurations/client/maleo.py,sha256=0Hk6no800DdaAlv0SZ1OqVGxbp4LtJz1cJ0ZNbBejK4,2063
|
82
82
|
maleo_foundation/models/transfers/parameters/__init__.py,sha256=HiV7hPn8rUaN7XeOwC_VugYQ4QQO7kbZ0fsp11GDznQ,355
|
83
83
|
maleo_foundation/models/transfers/parameters/client.py,sha256=2V1XvhSmIDDZL7MFVpD_dR5jWIoydQnFW67n9z6rRMA,4041
|
84
84
|
maleo_foundation/models/transfers/parameters/general.py,sha256=NUFsrrfByN9OX9QLYc2Bn0LpNPoxrKBuZae-IVhOiyo,791
|
@@ -99,21 +99,20 @@ maleo_foundation/models/transfers/results/key.py,sha256=dwEWM_FLubTf4tx3dFbvKJye
|
|
99
99
|
maleo_foundation/models/transfers/results/signature.py,sha256=Wjn5GjWTXWMtmSykAZACvAPT_hfXzmwo8GFAOCwYCMw,728
|
100
100
|
maleo_foundation/models/transfers/results/token.py,sha256=uucgesaw7fRUhvfJnsWpjKEARjsTQ8-HF-maAYKei3Q,659
|
101
101
|
maleo_foundation/models/transfers/results/client/__init__.py,sha256=QVW77FHou7OOABTjiIGdwPhXub46AI3GIM8EGk6ONw4,292
|
102
|
-
maleo_foundation/models/transfers/results/client/service.py,sha256=
|
102
|
+
maleo_foundation/models/transfers/results/client/service.py,sha256=_Eu12Zjr7vwjRoCBRkUEHCS0DEeMZtq4vLwGmBGo5tc,1234
|
103
103
|
maleo_foundation/models/transfers/results/client/controllers/__init__.py,sha256=DN3va_Mcxjw0l1s9dSIOy3LkLR1jEERiAohuIA59vpc,175
|
104
|
-
maleo_foundation/models/transfers/results/client/controllers/http.py,sha256=
|
104
|
+
maleo_foundation/models/transfers/results/client/controllers/http.py,sha256=toDx3xeDidtCDybUtPDfHbz0BY8VM-JcZ-5o_9VApRU,1522
|
105
105
|
maleo_foundation/models/transfers/results/encryption/__init__.py,sha256=fq8hH7SHyYgZkYEurnZpj4Plez7Ipy8-8yX60bj-I-w,309
|
106
106
|
maleo_foundation/models/transfers/results/encryption/aes.py,sha256=5aNglJqHT3Ufordl_Bfy9thIXVblMw80xtmLs7KiCXI,877
|
107
107
|
maleo_foundation/models/transfers/results/encryption/rsa.py,sha256=dSIshf386TAF9hfokDmj4XKHsR_MQfQLmft8AF2MTZc,748
|
108
108
|
maleo_foundation/models/transfers/results/service/__init__.py,sha256=J2PANZfFCPIE836hqKLj7a7q9AT5YSPQ0_SlYj3OKP0,295
|
109
|
-
maleo_foundation/models/transfers/results/service/general.py,sha256=
|
109
|
+
maleo_foundation/models/transfers/results/service/general.py,sha256=3l0YGZf8SD7udVm1EHr9frMD2kuWbGY1D_Eo1wrGS0Q,1514
|
110
110
|
maleo_foundation/models/transfers/results/service/controllers/__init__.py,sha256=rRt93gFqsJloJXzNWS_2chBC3hJoG4WaN84H2B5UPow,177
|
111
111
|
maleo_foundation/models/transfers/results/service/controllers/rest.py,sha256=YRD_D064BGqHUJeFH-ArOPmSNnhJO_gr_AI4gTqh8Y0,951
|
112
|
-
maleo_foundation/utils/__init__.py,sha256=
|
112
|
+
maleo_foundation/utils/__init__.py,sha256=advf6IhKQOz64jbI0f9gyabHWa7ti8wTYDkYLD85_Ss,322
|
113
113
|
maleo_foundation/utils/cache.py,sha256=PWNef00iA2m0g3boR7JbzrJQIRITf5nKgdCmMs3s6ag,1159
|
114
114
|
maleo_foundation/utils/client.py,sha256=KDkIEqGX6Tw07Z5HHW4HrG8IWUVkErlqnVijXnpWZGQ,2940
|
115
115
|
maleo_foundation/utils/controller.py,sha256=S69NluxjGCB_toAu3JDLi_izE0-x2ARE_7YK3V8T1Q0,7413
|
116
|
-
maleo_foundation/utils/exceptions.py,sha256=qNbmkfOAz_sIfO_sIypzM6ami-PiK1vs98MJJSAxj7g,6611
|
117
116
|
maleo_foundation/utils/extractor.py,sha256=an9bKvwIniVvUCk0fSetUL_8VGBk_MNEtB2pwgkYb4k,2369
|
118
117
|
maleo_foundation/utils/logging.py,sha256=sOQbvrLdlp1Vwx7y14YitzHx4IHh5iYaCt9WvdrapUI,9141
|
119
118
|
maleo_foundation/utils/merger.py,sha256=UGiuH0EUQJu0WlS1xdPUuvnsNknd3k0DODjdiOTiBdI,704
|
@@ -123,6 +122,10 @@ maleo_foundation/utils/searcher.py,sha256=rcHa0pPZvLEk2MgI4qeGW-K6vlUy2eWTnwWzzT
|
|
123
122
|
maleo_foundation/utils/dependencies/__init__.py,sha256=jJOo4uCTPiEvpgecsl4JEhKzuV85KaNxOd9PiRl-2ic,124
|
124
123
|
maleo_foundation/utils/dependencies/auth.py,sha256=3Z0b-Xi5PAKRKlbv-ZIT46YrQFkjiS7NhSDWZTOWm8I,650
|
125
124
|
maleo_foundation/utils/dependencies/context.py,sha256=pw18j6LZgHdJQVKCvRH71mFZ_li8jP_wIgbtBMLXpxQ,271
|
125
|
+
maleo_foundation/utils/exceptions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
126
|
+
maleo_foundation/utils/exceptions/client.py,sha256=gGA7BWf2Fel33lYqMd2LJVvt1x0HO0OqbopAJCcYnbY,9665
|
127
|
+
maleo_foundation/utils/exceptions/request.py,sha256=p6rfya7HuqlfrvxFZm3KgTf95mPkQ6QCBlLyhiRfGtw,1600
|
128
|
+
maleo_foundation/utils/exceptions/service.py,sha256=bhUvZb3rTx2UYwyVxbNjtKw7aru3UIVZptzTlGGk65g,9698
|
126
129
|
maleo_foundation/utils/formatter/__init__.py,sha256=qzn45FGoZeArJYmgFpdzKe-jp3yREGSrPfc4a-iZHe4,80
|
127
130
|
maleo_foundation/utils/formatter/case.py,sha256=VsDTkKVZgN5b5O4Q6hkEzIDTf635FHS2BF_eY-NNngQ,1359
|
128
131
|
maleo_foundation/utils/loaders/__init__.py,sha256=aBVS-zCBdb9t4Keh5cFJ4Vqv5lFHthJoHTaGPVjnvnU,284
|
@@ -132,7 +135,7 @@ maleo_foundation/utils/loaders/credential/__init__.py,sha256=g-cAxkTE2EtHaG8Tv52
|
|
132
135
|
maleo_foundation/utils/loaders/credential/google.py,sha256=GCJl-bsKSSxoE_ERAkIzRrRNIbIEeqYOhHwzFuBr0mk,6576
|
133
136
|
maleo_foundation/utils/loaders/key/__init__.py,sha256=RfqIbUxkdlx1xrbzJZPD_JHiRFNFLRuQs8JoUPCGCv4,108
|
134
137
|
maleo_foundation/utils/loaders/key/rsa.py,sha256=UXcP0rr4QVacTsHLNQuU05wcow5CHWz-JW-zsVxlbPs,4121
|
135
|
-
maleo_foundation-0.3.
|
136
|
-
maleo_foundation-0.3.
|
137
|
-
maleo_foundation-0.3.
|
138
|
-
maleo_foundation-0.3.
|
138
|
+
maleo_foundation-0.3.57.dist-info/METADATA,sha256=-j2vLiPYXbLAevxpNYD3GYc2Bs3GkcDxvf7FRF_xX0U,4150
|
139
|
+
maleo_foundation-0.3.57.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
140
|
+
maleo_foundation-0.3.57.dist-info/top_level.txt,sha256=_iBos3F_bhEOdjOnzeiEYSrCucasc810xXtLBXI8cQc,17
|
141
|
+
maleo_foundation-0.3.57.dist-info/RECORD,,
|
@@ -1,158 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
from fastapi import Request, status
|
3
|
-
from fastapi.encoders import jsonable_encoder
|
4
|
-
from fastapi.exceptions import RequestValidationError
|
5
|
-
from fastapi.responses import JSONResponse
|
6
|
-
from functools import wraps
|
7
|
-
from pydantic import ValidationError
|
8
|
-
from starlette.exceptions import HTTPException as StarletteHTTPException
|
9
|
-
from sqlalchemy.exc import SQLAlchemyError
|
10
|
-
from typing import Optional
|
11
|
-
from maleo_foundation.models.responses import BaseResponses
|
12
|
-
from maleo_foundation.models.transfers.results.service.general import (
|
13
|
-
BaseServiceGeneralResultsTransfers,
|
14
|
-
)
|
15
|
-
from maleo_foundation.utils.logging import BaseLogger
|
16
|
-
|
17
|
-
|
18
|
-
class BaseExceptions:
|
19
|
-
@staticmethod
|
20
|
-
def authentication_error_handler(request: Request, exc: Exception):
|
21
|
-
return JSONResponse(
|
22
|
-
content=BaseResponses.Unauthorized(other=str(exc)).model_dump(mode="json"), # type: ignore
|
23
|
-
status_code=status.HTTP_401_UNAUTHORIZED,
|
24
|
-
)
|
25
|
-
|
26
|
-
@staticmethod
|
27
|
-
async def validation_exception_handler(
|
28
|
-
request: Request, exc: RequestValidationError
|
29
|
-
):
|
30
|
-
serialized_error = jsonable_encoder(exc.errors())
|
31
|
-
return JSONResponse(
|
32
|
-
content=BaseResponses.ValidationError(other=serialized_error).model_dump(mode="json"), # type: ignore
|
33
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
34
|
-
)
|
35
|
-
|
36
|
-
@staticmethod
|
37
|
-
async def http_exception_handler(request: Request, exc: StarletteHTTPException):
|
38
|
-
if exc.status_code in BaseResponses.other_responses:
|
39
|
-
return JSONResponse(
|
40
|
-
content=BaseResponses.other_responses[exc.status_code]["model"]().model_dump(mode="json"), # type: ignore
|
41
|
-
status_code=exc.status_code,
|
42
|
-
)
|
43
|
-
|
44
|
-
return JSONResponse(
|
45
|
-
content=BaseResponses.ServerError().model_dump(mode="json"), # type: ignore
|
46
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
47
|
-
)
|
48
|
-
|
49
|
-
@staticmethod
|
50
|
-
def repository_exception_handler(
|
51
|
-
operation: str,
|
52
|
-
logger: Optional[BaseLogger] = None,
|
53
|
-
fail_result_class: type[
|
54
|
-
BaseServiceGeneralResultsTransfers.Fail
|
55
|
-
] = BaseServiceGeneralResultsTransfers.Fail,
|
56
|
-
):
|
57
|
-
"""Decorator to handle repository-related exceptions consistently for sync and async functions."""
|
58
|
-
|
59
|
-
def decorator(func):
|
60
|
-
def _handler(e: Exception, category: str, description: str):
|
61
|
-
if logger:
|
62
|
-
logger.error(
|
63
|
-
f"{category} occurred while {operation}: '{str(e)}'",
|
64
|
-
exc_info=True,
|
65
|
-
)
|
66
|
-
return fail_result_class(
|
67
|
-
message=f"Failed {operation}",
|
68
|
-
description=description,
|
69
|
-
other=category,
|
70
|
-
) # type: ignore
|
71
|
-
|
72
|
-
if asyncio.iscoroutinefunction(func):
|
73
|
-
|
74
|
-
@wraps(func)
|
75
|
-
async def async_wrapper(*args, **kwargs):
|
76
|
-
try:
|
77
|
-
return await func(*args, **kwargs)
|
78
|
-
except ValidationError as e:
|
79
|
-
return _handler(
|
80
|
-
e,
|
81
|
-
category="Validation error",
|
82
|
-
description=f"A validation error occurred while {operation}. Please try again later or contact administrator.",
|
83
|
-
)
|
84
|
-
except SQLAlchemyError as e:
|
85
|
-
return _handler(
|
86
|
-
e,
|
87
|
-
category="Database operation failed",
|
88
|
-
description=f"A database error occurred while {operation}. Please try again later or contact administrator.",
|
89
|
-
)
|
90
|
-
except Exception as e:
|
91
|
-
return _handler(
|
92
|
-
e,
|
93
|
-
category="Internal processing error",
|
94
|
-
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
95
|
-
)
|
96
|
-
|
97
|
-
return async_wrapper
|
98
|
-
else:
|
99
|
-
|
100
|
-
@wraps(func)
|
101
|
-
def sync_wrapper(*args, **kwargs):
|
102
|
-
try:
|
103
|
-
return func(*args, **kwargs)
|
104
|
-
except ValidationError as e:
|
105
|
-
return _handler(
|
106
|
-
e,
|
107
|
-
category="Validation error",
|
108
|
-
description=f"A validation error occurred while {operation}. Please try again later or contact administrator.",
|
109
|
-
)
|
110
|
-
except SQLAlchemyError as e:
|
111
|
-
return _handler(
|
112
|
-
e,
|
113
|
-
category="Database operation failed",
|
114
|
-
description=f"A database error occurred while {operation}. Please try again later or contact administrator.",
|
115
|
-
)
|
116
|
-
except Exception as e:
|
117
|
-
return _handler(
|
118
|
-
e,
|
119
|
-
category="Internal processing error",
|
120
|
-
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
121
|
-
)
|
122
|
-
|
123
|
-
return sync_wrapper
|
124
|
-
|
125
|
-
return decorator
|
126
|
-
|
127
|
-
@staticmethod
|
128
|
-
def service_exception_handler(
|
129
|
-
operation: str,
|
130
|
-
logger: Optional[BaseLogger] = None,
|
131
|
-
fail_result_class: type[
|
132
|
-
BaseServiceGeneralResultsTransfers.Fail
|
133
|
-
] = BaseServiceGeneralResultsTransfers.Fail,
|
134
|
-
):
|
135
|
-
"""Decorator to handle service-related exceptions consistently."""
|
136
|
-
|
137
|
-
def decorator(func):
|
138
|
-
@wraps(func)
|
139
|
-
def wrapper(*args, **kwargs):
|
140
|
-
try:
|
141
|
-
return func(*args, **kwargs)
|
142
|
-
except Exception as e:
|
143
|
-
if logger:
|
144
|
-
logger.error(
|
145
|
-
"Unexpected error occurred while %s: '%s'",
|
146
|
-
operation,
|
147
|
-
str(e),
|
148
|
-
exc_info=True,
|
149
|
-
)
|
150
|
-
return fail_result_class(
|
151
|
-
message=f"Failed {operation}",
|
152
|
-
description=f"An unexpected error occurred while {operation}. Please try again later or contact administrator.",
|
153
|
-
other="Internal processing error",
|
154
|
-
) # type: ignore
|
155
|
-
|
156
|
-
return wrapper
|
157
|
-
|
158
|
-
return decorator
|
File without changes
|
File without changes
|