maleo-schemas 0.0.1__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.
File without changes
File without changes
@@ -0,0 +1,9 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import Generic, Optional, TypeVar
3
+
4
+
5
+ OperationActionT = TypeVar("OperationActionT", bound=Optional[BaseModel])
6
+
7
+
8
+ class OperationActionMixin(BaseModel, Generic[OperationActionT]):
9
+ action: OperationActionT = Field(..., description="Action.")
@@ -0,0 +1,230 @@
1
+ import traceback
2
+ from typing import Generic, Literal
3
+ from maleo.logging.enums import Level
4
+ from maleo.logging.logger import Base
5
+ from maleo.mixins.general import Success, SuccessT
6
+ from maleo.mixins.operation import (
7
+ OperationIdentifier,
8
+ OperationSummary,
9
+ OperationType,
10
+ )
11
+ from maleo.mixins.timestamp import OperationTimestampMixin
12
+ from maleo.types.base.boolean import OptionalBoolean
13
+ from maleo.types.base.dict import (
14
+ OptionalStringToStringDict,
15
+ StringToAnyDict,
16
+ StringToStringDict,
17
+ )
18
+ from maleo.utils.merger import merge_dicts
19
+ from maleo.dtos.authentication import AuthenticationT, AuthenticationMixin
20
+ from maleo.dtos.contexts.operation import OperationContext, OperationContextMixin
21
+ from maleo.dtos.contexts.request import GenericRequestContextT, RequestContextMixin
22
+ from maleo.dtos.contexts.response import ResponseContextT, ResponseContextMixin
23
+ from maleo.dtos.contexts.service import ServiceContext, ServiceContextMixin
24
+ from maleo.dtos.error import GenericErrorT, ErrorT, ErrorMixin
25
+ from maleo.dtos.resource import ResourceT, ResourceMixin
26
+ from ..response import ResponseT, ResponseMixin
27
+ from .action import (
28
+ OperationActionMixin,
29
+ OperationActionT,
30
+ )
31
+
32
+
33
+ class BaseOperation(
34
+ ResponseMixin[ResponseT],
35
+ ResponseContextMixin[ResponseContextT],
36
+ OperationActionMixin[OperationActionT],
37
+ AuthenticationMixin[AuthenticationT],
38
+ RequestContextMixin[GenericRequestContextT],
39
+ ErrorMixin[GenericErrorT],
40
+ Success[SuccessT],
41
+ ResourceMixin[ResourceT],
42
+ OperationSummary,
43
+ OperationTimestampMixin,
44
+ OperationContextMixin[OperationContext],
45
+ OperationType,
46
+ OperationIdentifier,
47
+ ServiceContextMixin[ServiceContext],
48
+ Generic[
49
+ ResourceT,
50
+ SuccessT,
51
+ GenericErrorT,
52
+ GenericRequestContextT,
53
+ AuthenticationT,
54
+ OperationActionT,
55
+ ResponseContextT,
56
+ ResponseT,
57
+ ],
58
+ ):
59
+ @property
60
+ def log_message(self) -> str:
61
+ message = f"Operation {self.id} - {self.type} - "
62
+
63
+ success_information = f"{'success' if self.success else 'failed'}"
64
+
65
+ if self.response_context is not None:
66
+ success_information += f" {self.response_context.status_code}"
67
+
68
+ message += f"{success_information} - "
69
+
70
+ if self.request_context is not None:
71
+ message += (
72
+ f"{self.request_context.method} {self.request_context.url} - "
73
+ f"IP: {self.request_context.ip_address} - "
74
+ )
75
+
76
+ if self.authentication is None:
77
+ authentication = "No Authentication"
78
+ else:
79
+ # * In this line, 'is_authenticated' is not detected
80
+ # * due to the use of generic, but this property exists
81
+ if not self.authentication.user.is_authenticated:
82
+ authentication = "Unauthenticated"
83
+ else:
84
+ # * In this line, 'display_name' and 'identity' is not detected
85
+ # * due to the use of generic, but this property exists
86
+ authentication = (
87
+ "Authenticated | "
88
+ f"Username: {self.authentication.user.display_name} | "
89
+ f"Email: {self.authentication.user.identity}"
90
+ )
91
+
92
+ message += f"{authentication} - "
93
+ message += self.summary
94
+
95
+ return message
96
+
97
+ @property
98
+ def labels(self) -> StringToStringDict:
99
+ labels = {
100
+ "service": self.service_context.key,
101
+ "environment": self.service_context.environment,
102
+ "operation_id": str(self.id),
103
+ "operation_type": self.type,
104
+ "success": "true" if self.success else "false",
105
+ }
106
+
107
+ if self.request_context is not None:
108
+ labels["method"] = self.request_context.method
109
+ labels["url"] = self.request_context.url
110
+ if self.response_context is not None:
111
+ labels["status_code"] = str(self.response_context.status_code)
112
+
113
+ return labels
114
+
115
+ def log_labels(
116
+ self,
117
+ *,
118
+ additional_labels: OptionalStringToStringDict = None,
119
+ override_labels: OptionalStringToStringDict = None,
120
+ ) -> StringToStringDict:
121
+ if override_labels is not None:
122
+ return override_labels
123
+
124
+ labels = self.labels
125
+ if additional_labels is not None:
126
+ for k, v in additional_labels.items():
127
+ if k in labels.keys():
128
+ raise ValueError(
129
+ f"Key '{k}' already exist in labels, override the labels if necessary"
130
+ )
131
+ labels[k] = v
132
+ labels = merge_dicts(labels, additional_labels)
133
+ return labels
134
+
135
+ def log_extra(
136
+ self,
137
+ *,
138
+ additional_extra: OptionalStringToStringDict = None,
139
+ override_extra: OptionalStringToStringDict = None,
140
+ additional_labels: OptionalStringToStringDict = None,
141
+ override_labels: OptionalStringToStringDict = None,
142
+ ) -> StringToAnyDict:
143
+ labels = self.log_labels(
144
+ additional_labels=additional_labels, override_labels=override_labels
145
+ )
146
+
147
+ if override_extra is not None:
148
+ extra = override_extra
149
+ else:
150
+ extra = {"json_fields": self.model_dump(mode="json"), "labels": labels}
151
+ if additional_extra is not None:
152
+ extra = merge_dicts(extra, additional_extra)
153
+
154
+ return extra
155
+
156
+ def log(
157
+ self,
158
+ logger: Base,
159
+ level: Level,
160
+ *,
161
+ exc_info: OptionalBoolean = None,
162
+ additional_extra: OptionalStringToStringDict = None,
163
+ override_extra: OptionalStringToStringDict = None,
164
+ additional_labels: OptionalStringToStringDict = None,
165
+ override_labels: OptionalStringToStringDict = None,
166
+ ):
167
+ try:
168
+ message = self.log_message
169
+ extra = self.log_extra(
170
+ additional_extra=additional_extra,
171
+ override_extra=override_extra,
172
+ additional_labels=additional_labels,
173
+ override_labels=override_labels,
174
+ )
175
+ logger.log(
176
+ level,
177
+ message,
178
+ exc_info=exc_info,
179
+ extra=extra,
180
+ )
181
+ except Exception:
182
+ print("Failed logging operation:\n", traceback.format_exc())
183
+
184
+
185
+ class FailedBaseOperation(
186
+ BaseOperation[
187
+ ResourceT,
188
+ Literal[False],
189
+ ErrorT,
190
+ GenericRequestContextT,
191
+ AuthenticationT,
192
+ OperationActionT,
193
+ ResponseContextT,
194
+ ResponseT,
195
+ ],
196
+ Generic[
197
+ ResourceT,
198
+ ErrorT,
199
+ GenericRequestContextT,
200
+ AuthenticationT,
201
+ OperationActionT,
202
+ ResponseContextT,
203
+ ResponseT,
204
+ ],
205
+ ):
206
+ success: Literal[False] = False
207
+
208
+
209
+ class SuccessfulBaseOperation(
210
+ BaseOperation[
211
+ ResourceT,
212
+ Literal[True],
213
+ None,
214
+ GenericRequestContextT,
215
+ AuthenticationT,
216
+ OperationActionT,
217
+ ResponseContextT,
218
+ ResponseT,
219
+ ],
220
+ Generic[
221
+ ResourceT,
222
+ GenericRequestContextT,
223
+ AuthenticationT,
224
+ OperationActionT,
225
+ ResponseContextT,
226
+ ResponseT,
227
+ ],
228
+ ):
229
+ success: Literal[True] = True
230
+ error: None = None
@@ -0,0 +1,128 @@
1
+ from typing import Generic, Literal
2
+ from maleo.enums.operation import OperationType
3
+ from maleo.mixins.general import SuccessT
4
+ from maleo.dtos.authentication import AuthenticationT, OptionalAuthentication
5
+ from maleo.dtos.error import GenericErrorT, ErrorT
6
+ from maleo.dtos.contexts.request import RequestContext
7
+ from maleo.dtos.contexts.response import ResponseContext
8
+ from ..response import ResponseT, ErrorResponseT, SuccessResponseT
9
+ from .base import BaseOperation
10
+ from .resource import (
11
+ CreateResourceOperationAction,
12
+ ReadResourceOperationAction,
13
+ UpdateResourceOperationAction,
14
+ DeleteResourceOperationAction,
15
+ ResourceOperationActionT,
16
+ )
17
+
18
+
19
+ class RequestOperation(
20
+ BaseOperation[
21
+ None,
22
+ SuccessT,
23
+ GenericErrorT,
24
+ RequestContext,
25
+ OptionalAuthentication,
26
+ ResourceOperationActionT,
27
+ ResponseContext,
28
+ ResponseT,
29
+ ],
30
+ Generic[
31
+ SuccessT,
32
+ GenericErrorT,
33
+ ResourceOperationActionT,
34
+ ResponseT,
35
+ ],
36
+ ):
37
+ type: OperationType = OperationType.REQUEST
38
+ resource: None = None
39
+
40
+
41
+ class FailedRequestOperation(
42
+ RequestOperation[
43
+ Literal[False],
44
+ ErrorT,
45
+ ResourceOperationActionT,
46
+ ErrorResponseT,
47
+ ],
48
+ Generic[
49
+ ErrorT,
50
+ ResourceOperationActionT,
51
+ ErrorResponseT,
52
+ ],
53
+ ):
54
+ success: Literal[False] = False
55
+ summary: str = "Failed processing request"
56
+
57
+
58
+ class CreateFailedRequestOperation(
59
+ FailedRequestOperation[ErrorT, CreateResourceOperationAction, ErrorResponseT],
60
+ Generic[ErrorT, ErrorResponseT],
61
+ ):
62
+ pass
63
+
64
+
65
+ class ReadFailedRequestOperation(
66
+ FailedRequestOperation[ErrorT, CreateResourceOperationAction, ErrorResponseT],
67
+ Generic[ErrorT, ErrorResponseT],
68
+ ):
69
+ pass
70
+
71
+
72
+ class UpdateFailedRequestOperation(
73
+ FailedRequestOperation[ErrorT, UpdateResourceOperationAction, ErrorResponseT],
74
+ Generic[ErrorT, AuthenticationT, ErrorResponseT],
75
+ ):
76
+ pass
77
+
78
+
79
+ class DeleteFailedRequestOperation(
80
+ FailedRequestOperation[ErrorT, DeleteResourceOperationAction, ErrorResponseT],
81
+ Generic[ErrorT, AuthenticationT, ErrorResponseT],
82
+ ):
83
+ pass
84
+
85
+
86
+ class SuccessfulRequestOperation(
87
+ RequestOperation[
88
+ Literal[True],
89
+ None,
90
+ ResourceOperationActionT,
91
+ SuccessResponseT,
92
+ ],
93
+ Generic[
94
+ ResourceOperationActionT,
95
+ SuccessResponseT,
96
+ ],
97
+ ):
98
+ success: Literal[True] = True
99
+ error: None = None
100
+ summary: str = "Successfully processed request"
101
+
102
+
103
+ class CreateSuccessfulRequestOperation(
104
+ SuccessfulRequestOperation[CreateResourceOperationAction, SuccessResponseT],
105
+ Generic[AuthenticationT, SuccessResponseT],
106
+ ):
107
+ pass
108
+
109
+
110
+ class ReadSuccessfulRequestOperation(
111
+ SuccessfulRequestOperation[ReadResourceOperationAction, SuccessResponseT],
112
+ Generic[AuthenticationT, SuccessResponseT],
113
+ ):
114
+ pass
115
+
116
+
117
+ class UpdateSuccessfulRequestOperation(
118
+ SuccessfulRequestOperation[UpdateResourceOperationAction, SuccessResponseT],
119
+ Generic[AuthenticationT, SuccessResponseT],
120
+ ):
121
+ pass
122
+
123
+
124
+ class DeleteSuccessfulRequestOperation(
125
+ SuccessfulRequestOperation[DeleteResourceOperationAction, SuccessResponseT],
126
+ Generic[AuthenticationT, SuccessResponseT],
127
+ ):
128
+ pass