maleo-identity-client 0.6.2__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.
@@ -0,0 +1,272 @@
1
+ import json
2
+ from copy import deepcopy
3
+ from datetime import datetime, timezone
4
+ from typing import ClassVar, Literal, overload
5
+ from uuid import UUID
6
+ from nexo.client.service import ClientService
7
+ from nexo.database.enums import Connection
8
+ from nexo.database.utils import build_cache_key
9
+ from nexo.enums.cardinality import Cardinality
10
+ from nexo.enums.connection import Header
11
+ from nexo.logging.enums import LogLevel
12
+ from nexo.schemas.connection import ConnectionContext
13
+ from nexo.schemas.exception.factory import MaleoExceptionFactory
14
+ from nexo.schemas.operation.action.resource import ReadResourceOperationAction
15
+ from nexo.schemas.operation.enums import OperationType, Target
16
+ from nexo.schemas.operation.mixins import Timestamp
17
+ from nexo.schemas.operation.resource import (
18
+ ReadMultipleResourceOperation,
19
+ ReadSingleResourceOperation,
20
+ )
21
+ from nexo.schemas.pagination import StrictPagination
22
+ from nexo.schemas.resource import Resource, AggregateField
23
+ from nexo.schemas.response import (
24
+ MultipleDataResponse,
25
+ ReadMultipleDataResponse,
26
+ SingleDataResponse,
27
+ ReadSingleDataResponse,
28
+ )
29
+ from nexo.schemas.security.authorization import (
30
+ AnyAuthorization,
31
+ AuthorizationFactory,
32
+ )
33
+ from nexo.schemas.security.impersonation import OptImpersonation
34
+ from nexo.types.dict import OptStrToStrDict
35
+ from nexo.utils.merger import merge_dicts
36
+ from maleo.identity.constants.user_profile import USER_PROFILE_RESOURCE
37
+ from maleo.identity.mixins.user_profile import is_id_identifier
38
+ from maleo.identity.schemas.common import UserProfileSchema
39
+ from maleo.identity.schemas.user_profile import (
40
+ ReadMultipleParameter,
41
+ ReadSingleParameter,
42
+ )
43
+ from ..config import ClientConfig
44
+
45
+
46
+ class UserProfileClientService(ClientService[ClientConfig]):
47
+ _resource: ClassVar[Resource] = USER_PROFILE_RESOURCE
48
+
49
+ @overload
50
+ async def read(
51
+ self,
52
+ cardinality: Literal[Cardinality.MULTIPLE],
53
+ *,
54
+ operation_id: UUID,
55
+ connection_context: ConnectionContext,
56
+ authorization: AnyAuthorization,
57
+ impersonation: OptImpersonation = None,
58
+ parameters: ReadMultipleParameter,
59
+ headers: OptStrToStrDict = None,
60
+ ) -> ReadMultipleDataResponse[UserProfileSchema, StrictPagination, None]: ...
61
+ @overload
62
+ async def read(
63
+ self,
64
+ cardinality: Literal[Cardinality.SINGLE],
65
+ *,
66
+ operation_id: UUID,
67
+ connection_context: ConnectionContext,
68
+ authorization: AnyAuthorization,
69
+ impersonation: OptImpersonation = None,
70
+ parameters: ReadSingleParameter,
71
+ headers: OptStrToStrDict = None,
72
+ ) -> ReadSingleDataResponse[UserProfileSchema, None]: ...
73
+ async def read(
74
+ self,
75
+ cardinality: Cardinality,
76
+ *,
77
+ operation_id: UUID,
78
+ connection_context: ConnectionContext,
79
+ authorization: AnyAuthorization,
80
+ impersonation: OptImpersonation = None,
81
+ parameters: ReadMultipleParameter | ReadSingleParameter,
82
+ headers: OptStrToStrDict = None,
83
+ ) -> (
84
+ ReadMultipleDataResponse[UserProfileSchema, StrictPagination, None]
85
+ | ReadSingleDataResponse[UserProfileSchema, None]
86
+ ):
87
+ redis_client = self._redis.manager.client.get(Connection.ASYNC)
88
+
89
+ executed_at = datetime.now(tz=timezone.utc)
90
+
91
+ # Define arguments being used in this function
92
+ positional_arguments = [cardinality]
93
+ keyword_arguments = {
94
+ "authorization": (
95
+ authorization.model_dump(mode="json")
96
+ if authorization is not None
97
+ else None
98
+ ),
99
+ "parameters": parameters.model_dump(mode="json"),
100
+ }
101
+
102
+ # Define full function string
103
+ ext = f"({json.dumps(positional_arguments)}|{json.dumps(keyword_arguments)})"
104
+
105
+ # Define full cache_key
106
+ cache_key = build_cache_key(ext, namespace=self._namespace)
107
+
108
+ if parameters.use_cache:
109
+ # Initialize cache operation context
110
+ operation_context = deepcopy(self._operation_context)
111
+ operation_context.target.type = Target.CACHE
112
+
113
+ redis_response_str = await redis_client.get(cache_key)
114
+
115
+ if redis_response_str is not None:
116
+ operation_timestamp = Timestamp.completed_now(executed_at)
117
+ if cardinality is Cardinality.MULTIPLE:
118
+ response = ReadMultipleDataResponse[
119
+ UserProfileSchema, StrictPagination, None
120
+ ].model_validate_json(redis_response_str)
121
+ operation = ReadMultipleResourceOperation[
122
+ UserProfileSchema, StrictPagination, None
123
+ ](
124
+ application_context=self._application_context,
125
+ id=operation_id,
126
+ context=operation_context,
127
+ resource=self._resource,
128
+ timestamp=operation_timestamp,
129
+ summary=f"Successfully read multiple {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
130
+ connection_context=connection_context,
131
+ authentication=None,
132
+ authorization=authorization,
133
+ impersonation=impersonation,
134
+ response=response,
135
+ )
136
+ operation.log(self._logger, LogLevel.INFO)
137
+ operation.publish(self._logger, self._publishers)
138
+ elif cardinality is Cardinality.SINGLE:
139
+ response = ReadSingleDataResponse[
140
+ UserProfileSchema, None
141
+ ].model_validate_json(redis_response_str)
142
+ operation = ReadSingleResourceOperation[UserProfileSchema, None](
143
+ application_context=self._application_context,
144
+ id=operation_id,
145
+ context=operation_context,
146
+ resource=self._resource,
147
+ timestamp=operation_timestamp,
148
+ summary=f"Successfully read single {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
149
+ connection_context=connection_context,
150
+ authentication=None,
151
+ authorization=authorization,
152
+ impersonation=impersonation,
153
+ response=response,
154
+ )
155
+ operation.log(self._logger, LogLevel.INFO)
156
+ operation.publish(self._logger, self._publishers)
157
+
158
+ return response # type: ignore
159
+
160
+ operation_context = deepcopy(self._operation_context)
161
+ operation_context.target.type = Target.MICROSERVICE
162
+
163
+ async with self._http_client_manager.get() as http_client:
164
+ base_headers = {
165
+ Header.CONTENT_TYPE.value: "application/json",
166
+ Header.X_OPERATION_ID.value: str(operation_id),
167
+ }
168
+ if impersonation is not None:
169
+ base_headers[Header.X_USER_ID.value] = str(impersonation.user_id)
170
+ if impersonation.organization_id is not None:
171
+ base_headers[Header.X_ORGANIZATION_ID.value] = str(
172
+ impersonation.organization_id
173
+ )
174
+
175
+ if headers is not None:
176
+ headers = merge_dicts(base_headers, headers)
177
+ else:
178
+ headers = base_headers
179
+
180
+ auth = AuthorizationFactory.httpx_auth(
181
+ scheme=authorization.scheme, authorization=authorization.credentials
182
+ )
183
+
184
+ base_url = f"{self._config.url}/v1/{self._resource.identifiers[-1].slug}"
185
+ if isinstance(parameters, ReadMultipleParameter):
186
+ url = base_url
187
+ elif isinstance(parameters, ReadSingleParameter):
188
+ if is_id_identifier(parameters.identifier):
189
+ url = base_url + f"/{parameters.identifier.value}"
190
+ else:
191
+ url = (
192
+ base_url
193
+ + f"/{parameters.identifier.type}/{parameters.identifier.value}"
194
+ )
195
+
196
+ params = parameters.to_query_params()
197
+
198
+ response = await http_client.get(
199
+ url, params=params, headers=headers, auth=auth
200
+ )
201
+
202
+ operation_timestamp = Timestamp.completed_now(executed_at)
203
+
204
+ if response.is_error:
205
+ exc = MaleoExceptionFactory.from_httpx(
206
+ response,
207
+ operation_type=OperationType.REQUEST,
208
+ application_context=self._application_context,
209
+ operation_id=operation_id,
210
+ operation_context=operation_context,
211
+ operation_action=ReadResourceOperationAction(),
212
+ operation_timestamp=operation_timestamp,
213
+ connection_context=connection_context,
214
+ authentication=None,
215
+ authorization=authorization,
216
+ impersonation=impersonation,
217
+ logger=self._logger,
218
+ )
219
+ exc.log_and_publish_operation(self._logger, self._publishers)
220
+ raise exc
221
+
222
+ if isinstance(parameters, ReadMultipleParameter):
223
+ validated_response = MultipleDataResponse[
224
+ UserProfileSchema, StrictPagination, None
225
+ ].model_validate(response.json())
226
+ service_response = ReadMultipleDataResponse[
227
+ UserProfileSchema, StrictPagination, None
228
+ ].new(
229
+ data=validated_response.data,
230
+ pagination=validated_response.pagination,
231
+ )
232
+ operation = ReadMultipleResourceOperation[
233
+ UserProfileSchema, StrictPagination, None
234
+ ](
235
+ application_context=self._application_context,
236
+ id=operation_id,
237
+ context=operation_context,
238
+ resource=self._resource,
239
+ timestamp=operation_timestamp,
240
+ summary=f"Successfully read multiple {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
241
+ connection_context=connection_context,
242
+ authentication=None,
243
+ authorization=authorization,
244
+ impersonation=impersonation,
245
+ response=service_response,
246
+ )
247
+ operation.log(self._logger, LogLevel.INFO)
248
+ operation.publish(self._logger, self._publishers)
249
+ elif isinstance(parameters, ReadSingleParameter):
250
+ validated_response = SingleDataResponse[
251
+ UserProfileSchema, None
252
+ ].model_validate(response.json())
253
+ service_response = ReadSingleDataResponse[UserProfileSchema, None].new(
254
+ data=validated_response.data,
255
+ )
256
+ operation = ReadSingleResourceOperation[UserProfileSchema, None](
257
+ application_context=self._application_context,
258
+ id=operation_id,
259
+ context=operation_context,
260
+ resource=self._resource,
261
+ timestamp=operation_timestamp,
262
+ summary=f"Successfully read single {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
263
+ connection_context=connection_context,
264
+ authentication=None,
265
+ authorization=authorization,
266
+ impersonation=impersonation,
267
+ response=service_response,
268
+ )
269
+ operation.log(self._logger, LogLevel.INFO)
270
+ operation.publish(self._logger, self._publishers)
271
+
272
+ return service_response # type: ignore
@@ -0,0 +1,280 @@
1
+ import json
2
+ from copy import deepcopy
3
+ from datetime import datetime, timezone
4
+ from typing import ClassVar, Literal, overload
5
+ from uuid import UUID
6
+ from nexo.client.service import ClientService
7
+ from nexo.database.enums import Connection
8
+ from nexo.database.utils import build_cache_key
9
+ from nexo.enums.cardinality import Cardinality
10
+ from nexo.enums.connection import Header
11
+ from nexo.logging.enums import LogLevel
12
+ from nexo.schemas.connection import ConnectionContext
13
+ from nexo.schemas.exception.factory import MaleoExceptionFactory
14
+ from nexo.schemas.operation.action.resource import ReadResourceOperationAction
15
+ from nexo.schemas.operation.enums import OperationType, Target
16
+ from nexo.schemas.operation.mixins import Timestamp
17
+ from nexo.schemas.operation.resource import (
18
+ ReadMultipleResourceOperation,
19
+ ReadSingleResourceOperation,
20
+ )
21
+ from nexo.schemas.pagination import StrictPagination
22
+ from nexo.schemas.resource import Resource, AggregateField
23
+ from nexo.schemas.response import (
24
+ MultipleDataResponse,
25
+ ReadMultipleDataResponse,
26
+ SingleDataResponse,
27
+ ReadSingleDataResponse,
28
+ )
29
+ from nexo.schemas.security.authorization import (
30
+ AnyAuthorization,
31
+ AuthorizationFactory,
32
+ )
33
+ from nexo.schemas.security.impersonation import OptImpersonation
34
+ from nexo.types.dict import OptStrToStrDict
35
+ from nexo.utils.merger import merge_dicts
36
+ from maleo.identity.constants.user_system_role import USER_SYSTEM_ROLE_RESOURCE
37
+ from maleo.identity.mixins.user_system_role import (
38
+ is_id_identifier,
39
+ is_composite_identifier,
40
+ )
41
+ from maleo.identity.schemas.common import UserSystemRoleSchema
42
+ from maleo.identity.schemas.user_system_role import (
43
+ ReadMultipleParameter,
44
+ ReadSingleParameter,
45
+ )
46
+ from ..config import ClientConfig
47
+
48
+
49
+ class UserSystemRoleClientService(ClientService[ClientConfig]):
50
+ _resource: ClassVar[Resource] = USER_SYSTEM_ROLE_RESOURCE
51
+
52
+ @overload
53
+ async def read(
54
+ self,
55
+ cardinality: Literal[Cardinality.MULTIPLE],
56
+ *,
57
+ operation_id: UUID,
58
+ connection_context: ConnectionContext,
59
+ authorization: AnyAuthorization,
60
+ impersonation: OptImpersonation = None,
61
+ parameters: ReadMultipleParameter,
62
+ headers: OptStrToStrDict = None,
63
+ ) -> ReadMultipleDataResponse[UserSystemRoleSchema, StrictPagination, None]: ...
64
+ @overload
65
+ async def read(
66
+ self,
67
+ cardinality: Literal[Cardinality.SINGLE],
68
+ *,
69
+ operation_id: UUID,
70
+ connection_context: ConnectionContext,
71
+ authorization: AnyAuthorization,
72
+ impersonation: OptImpersonation = None,
73
+ parameters: ReadSingleParameter,
74
+ headers: OptStrToStrDict = None,
75
+ ) -> ReadSingleDataResponse[UserSystemRoleSchema, None]: ...
76
+ async def read(
77
+ self,
78
+ cardinality: Cardinality,
79
+ *,
80
+ operation_id: UUID,
81
+ connection_context: ConnectionContext,
82
+ authorization: AnyAuthorization,
83
+ impersonation: OptImpersonation = None,
84
+ parameters: ReadMultipleParameter | ReadSingleParameter,
85
+ headers: OptStrToStrDict = None,
86
+ ) -> (
87
+ ReadMultipleDataResponse[UserSystemRoleSchema, StrictPagination, None]
88
+ | ReadSingleDataResponse[UserSystemRoleSchema, None]
89
+ ):
90
+ redis_client = self._redis.manager.client.get(Connection.ASYNC)
91
+
92
+ executed_at = datetime.now(tz=timezone.utc)
93
+
94
+ # Define arguments being used in this function
95
+ positional_arguments = [cardinality]
96
+ keyword_arguments = {
97
+ "authorization": (
98
+ authorization.model_dump(mode="json")
99
+ if authorization is not None
100
+ else None
101
+ ),
102
+ "parameters": parameters.model_dump(mode="json"),
103
+ }
104
+
105
+ # Define full function string
106
+ ext = f"({json.dumps(positional_arguments)}|{json.dumps(keyword_arguments)})"
107
+
108
+ # Define full cache_key
109
+ cache_key = build_cache_key(ext, namespace=self._namespace)
110
+
111
+ if parameters.use_cache:
112
+ # Initialize cache operation context
113
+ operation_context = deepcopy(self._operation_context)
114
+ operation_context.target.type = Target.CACHE
115
+
116
+ redis_response_str = await redis_client.get(cache_key)
117
+
118
+ if redis_response_str is not None:
119
+ operation_timestamp = Timestamp.completed_now(executed_at)
120
+ if cardinality is Cardinality.MULTIPLE:
121
+ response = ReadMultipleDataResponse[
122
+ UserSystemRoleSchema, StrictPagination, None
123
+ ].model_validate_json(redis_response_str)
124
+ operation = ReadMultipleResourceOperation[
125
+ UserSystemRoleSchema, StrictPagination, None
126
+ ](
127
+ application_context=self._application_context,
128
+ id=operation_id,
129
+ context=operation_context,
130
+ resource=self._resource,
131
+ timestamp=operation_timestamp,
132
+ summary=f"Successfully read multiple {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
133
+ connection_context=connection_context,
134
+ authentication=None,
135
+ authorization=authorization,
136
+ impersonation=impersonation,
137
+ response=response,
138
+ )
139
+ operation.log(self._logger, LogLevel.INFO)
140
+ operation.publish(self._logger, self._publishers)
141
+ elif cardinality is Cardinality.SINGLE:
142
+ response = ReadSingleDataResponse[
143
+ UserSystemRoleSchema, None
144
+ ].model_validate_json(redis_response_str)
145
+ operation = ReadSingleResourceOperation[UserSystemRoleSchema, None](
146
+ application_context=self._application_context,
147
+ id=operation_id,
148
+ context=operation_context,
149
+ resource=self._resource,
150
+ timestamp=operation_timestamp,
151
+ summary=f"Successfully read single {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from cache",
152
+ connection_context=connection_context,
153
+ authentication=None,
154
+ authorization=authorization,
155
+ impersonation=impersonation,
156
+ response=response,
157
+ )
158
+ operation.log(self._logger, LogLevel.INFO)
159
+ operation.publish(self._logger, self._publishers)
160
+
161
+ return response # type: ignore
162
+
163
+ operation_context = deepcopy(self._operation_context)
164
+ operation_context.target.type = Target.MICROSERVICE
165
+
166
+ async with self._http_client_manager.get() as http_client:
167
+ base_headers = {
168
+ Header.CONTENT_TYPE.value: "application/json",
169
+ Header.X_OPERATION_ID.value: str(operation_id),
170
+ }
171
+ if impersonation is not None:
172
+ base_headers[Header.X_USER_ID.value] = str(impersonation.user_id)
173
+ if impersonation.organization_id is not None:
174
+ base_headers[Header.X_ORGANIZATION_ID.value] = str(
175
+ impersonation.organization_id
176
+ )
177
+
178
+ if headers is not None:
179
+ headers = merge_dicts(base_headers, headers)
180
+ else:
181
+ headers = base_headers
182
+
183
+ auth = AuthorizationFactory.httpx_auth(
184
+ scheme=authorization.scheme, authorization=authorization.credentials
185
+ )
186
+
187
+ base_url = f"{self._config.url}/v1/{self._resource.identifiers[-1].slug}"
188
+ if isinstance(parameters, ReadMultipleParameter):
189
+ url = base_url
190
+ elif isinstance(parameters, ReadSingleParameter):
191
+ if is_composite_identifier(parameters.identifier):
192
+ value = parameters.identifier.value
193
+ url = f"{self._config.url}/v1/users/{value[0]}/system-roles/{value[1]}"
194
+ elif is_id_identifier(parameters.identifier):
195
+ url = base_url + f"/{parameters.identifier.value}"
196
+ else:
197
+ url = (
198
+ base_url
199
+ + f"/{parameters.identifier.type}/{parameters.identifier.value}"
200
+ )
201
+
202
+ params = parameters.to_query_params()
203
+
204
+ response = await http_client.get(
205
+ url, params=params, headers=headers, auth=auth
206
+ )
207
+
208
+ operation_timestamp = Timestamp.completed_now(executed_at)
209
+
210
+ if response.is_error:
211
+ exc = MaleoExceptionFactory.from_httpx(
212
+ response,
213
+ operation_type=OperationType.REQUEST,
214
+ application_context=self._application_context,
215
+ operation_id=operation_id,
216
+ operation_context=operation_context,
217
+ operation_action=ReadResourceOperationAction(),
218
+ operation_timestamp=operation_timestamp,
219
+ connection_context=connection_context,
220
+ authentication=None,
221
+ authorization=authorization,
222
+ impersonation=impersonation,
223
+ logger=self._logger,
224
+ )
225
+ exc.log_and_publish_operation(self._logger, self._publishers)
226
+ raise exc
227
+
228
+ if isinstance(parameters, ReadMultipleParameter):
229
+ validated_response = MultipleDataResponse[
230
+ UserSystemRoleSchema, StrictPagination, None
231
+ ].model_validate(response.json())
232
+ service_response = ReadMultipleDataResponse[
233
+ UserSystemRoleSchema, StrictPagination, None
234
+ ].new(
235
+ data=validated_response.data,
236
+ pagination=validated_response.pagination,
237
+ )
238
+ operation = ReadMultipleResourceOperation[
239
+ UserSystemRoleSchema, StrictPagination, None
240
+ ](
241
+ application_context=self._application_context,
242
+ id=operation_id,
243
+ context=operation_context,
244
+ resource=self._resource,
245
+ timestamp=operation_timestamp,
246
+ summary=f"Successfully read multiple {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
247
+ connection_context=connection_context,
248
+ authentication=None,
249
+ authorization=authorization,
250
+ impersonation=impersonation,
251
+ response=service_response,
252
+ )
253
+ operation.log(self._logger, LogLevel.INFO)
254
+ operation.publish(self._logger, self._publishers)
255
+ elif isinstance(parameters, ReadSingleParameter):
256
+ validated_response = SingleDataResponse[
257
+ UserSystemRoleSchema, None
258
+ ].model_validate(response.json())
259
+ service_response = ReadSingleDataResponse[
260
+ UserSystemRoleSchema, None
261
+ ].new(
262
+ data=validated_response.data,
263
+ )
264
+ operation = ReadSingleResourceOperation[UserSystemRoleSchema, None](
265
+ application_context=self._application_context,
266
+ id=operation_id,
267
+ context=operation_context,
268
+ resource=self._resource,
269
+ timestamp=operation_timestamp,
270
+ summary=f"Successfully read single {self._resource.aggregate(AggregateField.NAME, sep=" ").lower()} from microservice",
271
+ connection_context=connection_context,
272
+ authentication=None,
273
+ authorization=authorization,
274
+ impersonation=impersonation,
275
+ response=service_response,
276
+ )
277
+ operation.log(self._logger, LogLevel.INFO)
278
+ operation.publish(self._logger, self._publishers)
279
+
280
+ return service_response # type: ignore
@@ -0,0 +1,143 @@
1
+ Metadata-Version: 2.4
2
+ Name: maleo-identity-client
3
+ Version: 0.6.2
4
+ Summary: MaleoIdentity client package
5
+ Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
+ License: Proprietary
7
+ Requires-Python: >=3.12
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: aioredis>=2.0.1
11
+ Requires-Dist: annotated-doc>=0.0.4
12
+ Requires-Dist: annotated-types>=0.7.0
13
+ Requires-Dist: anyio>=4.12.0
14
+ Requires-Dist: async-timeout>=5.0.1
15
+ Requires-Dist: bcrypt>=5.0.0
16
+ Requires-Dist: black>=25.11.0
17
+ Requires-Dist: cachetools>=6.2.2
18
+ Requires-Dist: certifi>=2025.11.12
19
+ Requires-Dist: cffi>=2.0.0
20
+ Requires-Dist: cfgv>=3.5.0
21
+ Requires-Dist: charset-normalizer>=3.4.4
22
+ Requires-Dist: click>=8.3.1
23
+ Requires-Dist: colorama>=0.4.6
24
+ Requires-Dist: cryptography>=46.0.3
25
+ Requires-Dist: distlib>=0.4.0
26
+ Requires-Dist: dnspython>=2.8.0
27
+ Requires-Dist: elastic-transport>=9.2.0
28
+ Requires-Dist: elasticsearch>=9.2.0
29
+ Requires-Dist: fastapi>=0.123.7
30
+ Requires-Dist: filelock>=3.20.0
31
+ Requires-Dist: google-api-core>=2.28.1
32
+ Requires-Dist: google-auth>=2.43.0
33
+ Requires-Dist: google-cloud-appengine-logging>=1.7.0
34
+ Requires-Dist: google-cloud-audit-log>=0.4.0
35
+ Requires-Dist: google-cloud-core>=2.5.0
36
+ Requires-Dist: google-cloud-logging>=3.12.1
37
+ Requires-Dist: google-cloud-pubsub>=2.33.0
38
+ Requires-Dist: google-cloud-secret-manager>=2.25.0
39
+ Requires-Dist: google-cloud-storage>=3.6.0
40
+ Requires-Dist: google-crc32c>=1.7.1
41
+ Requires-Dist: google-resumable-media>=2.8.0
42
+ Requires-Dist: googleapis-common-protos>=1.72.0
43
+ Requires-Dist: greenlet>=3.2.4
44
+ Requires-Dist: grpc-google-iam-v1>=0.14.3
45
+ Requires-Dist: grpcio>=1.76.0
46
+ Requires-Dist: grpcio-status>=1.76.0
47
+ Requires-Dist: h11>=0.16.0
48
+ Requires-Dist: httpcore>=1.0.9
49
+ Requires-Dist: httpx>=0.28.1
50
+ Requires-Dist: identify>=2.6.15
51
+ Requires-Dist: idna>=3.11
52
+ Requires-Dist: importlib_metadata>=8.7.0
53
+ Requires-Dist: iniconfig>=2.3.0
54
+ Requires-Dist: maleo-enums>=0.0.85
55
+ Requires-Dist: maleo-identity>=0.3.2
56
+ Requires-Dist: maleo-metadata>=0.8.2
57
+ Requires-Dist: motor>=3.7.1
58
+ Requires-Dist: mypy_extensions>=1.1.0
59
+ Requires-Dist: nexo-client>=0.0.31
60
+ Requires-Dist: nexo-crypto>=0.0.5
61
+ Requires-Dist: nexo-database>=0.0.19
62
+ Requires-Dist: nexo-enums>=0.0.5
63
+ Requires-Dist: nexo-google>=0.0.31
64
+ Requires-Dist: nexo-infra>=0.0.10
65
+ Requires-Dist: nexo-logging>=0.0.5
66
+ Requires-Dist: nexo-middlewares>=0.0.31
67
+ Requires-Dist: nexo-schemas>=0.0.19
68
+ Requires-Dist: nexo-soma>=0.0.31
69
+ Requires-Dist: nexo-types>=0.0.5
70
+ Requires-Dist: nexo-utils>=0.0.5
71
+ Requires-Dist: nodeenv>=1.9.1
72
+ Requires-Dist: opentelemetry-api>=1.39.0
73
+ Requires-Dist: opentelemetry-sdk>=1.39.0
74
+ Requires-Dist: opentelemetry-semantic-conventions>=0.60b0
75
+ Requires-Dist: packaging>=25.0
76
+ Requires-Dist: pathspec>=0.12.1
77
+ Requires-Dist: platformdirs>=4.5.0
78
+ Requires-Dist: pluggy>=1.6.0
79
+ Requires-Dist: pre_commit>=4.5.0
80
+ Requires-Dist: proto-plus>=1.26.1
81
+ Requires-Dist: protobuf>=6.33.1
82
+ Requires-Dist: psutil>=7.1.3
83
+ Requires-Dist: pyasn1>=0.6.1
84
+ Requires-Dist: pyasn1_modules>=0.4.2
85
+ Requires-Dist: pycparser>=2.23
86
+ Requires-Dist: pycryptodome>=3.23.0
87
+ Requires-Dist: pydantic>=2.12.5
88
+ Requires-Dist: pydantic-settings>=2.12.0
89
+ Requires-Dist: pydantic_core>=2.41.5
90
+ Requires-Dist: Pygments>=2.19.2
91
+ Requires-Dist: PyJWT>=2.10.1
92
+ Requires-Dist: pymongo>=4.15.5
93
+ Requires-Dist: pytest>=9.0.1
94
+ Requires-Dist: python-dateutil>=2.9.0.post0
95
+ Requires-Dist: python-dotenv>=1.2.1
96
+ Requires-Dist: pytokens>=0.3.0
97
+ Requires-Dist: PyYAML>=6.0.3
98
+ Requires-Dist: redis>=7.1.0
99
+ Requires-Dist: requests>=2.32.5
100
+ Requires-Dist: rsa>=4.9.1
101
+ Requires-Dist: six>=1.17.0
102
+ Requires-Dist: sniffio>=1.3.1
103
+ Requires-Dist: SQLAlchemy>=2.0.44
104
+ Requires-Dist: starlette>=0.50.0
105
+ Requires-Dist: typing-inspection>=0.4.2
106
+ Requires-Dist: typing_extensions>=4.15.0
107
+ Requires-Dist: ua-parser>=1.0.1
108
+ Requires-Dist: ua-parser-builtins>=0.18.0.post1
109
+ Requires-Dist: urllib3>=2.5.0
110
+ Requires-Dist: user-agents>=2.2.0
111
+ Requires-Dist: virtualenv>=20.35.4
112
+ Requires-Dist: zipp>=3.23.0
113
+ Dynamic: license-file
114
+
115
+ # README #
116
+
117
+ This README would normally document whatever steps are necessary to get your application up and running.
118
+
119
+ ### What is this repository for? ###
120
+
121
+ * Quick summary
122
+ * Version
123
+ * [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
124
+
125
+ ### How do I get set up? ###
126
+
127
+ * Summary of set up
128
+ * Configuration
129
+ * Dependencies
130
+ * Database configuration
131
+ * How to run tests
132
+ * Deployment instructions
133
+
134
+ ### Contribution guidelines ###
135
+
136
+ * Writing tests
137
+ * Code review
138
+ * Other guidelines
139
+
140
+ ### Who do I talk to? ###
141
+
142
+ * Repo owner or admin
143
+ * Other community or team contact