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 CHANGED
@@ -67,19 +67,69 @@ class BaseEnums:
67
67
  REFRESH = "refresh"
68
68
  ACCESS = "access"
69
69
 
70
- class StatusUpdateType(StrEnum):
71
- ACTIVATE = "activate"
72
- DEACTIVATE = "deactivate"
73
- RESTORE = "restore"
74
- DELETE = "delete"
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 UpdateType(StrEnum):
77
- STATUS = "status"
78
- DATA = "data"
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 BaseExceptions
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=BaseExceptions.validation_exception_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=BaseExceptions.http_exception_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 BaseExceptions
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=BaseExceptions.authentication_error_handler, # type: ignore
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
- class Fail(BaseResultSchemas.Fail):
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(BaseResultSchemas.NoData):
87
- pass
88
-
89
- class SingleData(BaseResultSchemas.SingleData):
90
- pass
91
-
92
- class UnpaginatedMultipleData(BaseResultSchemas.UnpaginatedMultipleData):
93
- pass
94
-
95
- class PaginatedMultipleData(BaseResultSchemas.PaginatedMultipleData):
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 pydantic import BaseModel, Field
2
- from typing import Dict, Optional, Union, Any
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="before")
18
- @classmethod
19
- def process_response(cls, values: dict) -> dict:
20
- """Process the response to set status_code, content, and success."""
21
- response: Response = values.get("response")
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
- if response:
24
- values["status_code"] = response.status_code
25
- values["success"] = response.is_success
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
- # * Determine content type and parse accordingly
28
- content_type: str = response.headers.get("content-type", "")
29
- content_type = content_type.lower()
30
- if "application/json" in content_type:
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
- return values
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 Field, model_validator
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 Field, model_validator
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
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.3.55
3
+ Version: 0.3.57
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -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=teEj0pqZmt-V7yEzYE3PnDO4stINlxRSWbejAatmqEQ,5075
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=GN8batfTPyZUGTVriqi9dZDu601_TYHJcrPL_VdutvQ,11660
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=Foag5Bc4tEiCZtHuCnBAKFq4t4jMoU3ZCrR_MMZRZPc,4167
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=4uIrW8y6gyBQJ5DZRMWKAJcNdamDMCpgCzizwcBHGhw,6081
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=k_VcmdIoZX-9nyxkmH7uPaSZFK2m0tjFIqYbVXdL1jw,4375
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=CUxuw9JSkw-pB4q97IduBnlINmsO487SpnrznYEf4-g,1220
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=aYTNsCAa0Vws1Zkt_6lnYAgJUN7Uo_YI_lAcUIaLiR0,1912
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=XfiHk4AKNIqSuKonjG76U3vfwrxbX7kykcAo1eLMh3c,1469
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=8-FvXt5n9MSutjKSEWE5k70LrC_UGZ2Ri2oCDrEIfYw,1541
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=nx23IHIxiscl1miSz2D2VNN2oFV8e7eKlm-cV4QjFWc,1750
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=L9J946_ySumzbJoOIbSBkhGz0tcjWPZ2_g76EXyxKkk,393
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.55.dist-info/METADATA,sha256=BCt07Y4xUXZCRZgLjDa64c6BpJ3ZlmrMX0ZNAPHKATI,4150
136
- maleo_foundation-0.3.55.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
137
- maleo_foundation-0.3.55.dist-info/top_level.txt,sha256=_iBos3F_bhEOdjOnzeiEYSrCucasc810xXtLBXI8cQc,17
138
- maleo_foundation-0.3.55.dist-info/RECORD,,
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