maleo-managers 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,17 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import Generic, Optional, TypeVar
3
+ from .maleo.config import MaleoClientsConfigT
4
+
5
+
6
+ class Config(BaseModel, Generic[MaleoClientsConfigT]):
7
+ maleo: MaleoClientsConfigT = Field(
8
+ ...,
9
+ description="Maleo client's configurations",
10
+ )
11
+
12
+
13
+ ConfigT = TypeVar("ConfigT", bound=Optional[Config])
14
+
15
+
16
+ class ConfigMixin(BaseModel, Generic[ConfigT]):
17
+ client: ConfigT = Field(..., description="Client config")
@@ -0,0 +1,24 @@
1
+ import httpx
2
+ from contextlib import asynccontextmanager
3
+ from typing import AsyncGenerator
4
+
5
+
6
+ class HTTPClientManager:
7
+ def __init__(self) -> None:
8
+ self._client = httpx.AsyncClient()
9
+
10
+ async def _client_handler(self) -> AsyncGenerator[httpx.AsyncClient, None]:
11
+ """Async generator for client handling"""
12
+ if self._client is None or (
13
+ self._client is not None and self._client.is_closed
14
+ ):
15
+ self._client = httpx.AsyncClient()
16
+ yield self._client
17
+
18
+ async def inject(self) -> AsyncGenerator[httpx.AsyncClient, None]:
19
+ return self._client_handler()
20
+
21
+ @asynccontextmanager
22
+ async def get(self) -> AsyncGenerator[httpx.AsyncClient, None]:
23
+ async for client in self._client_handler():
24
+ yield client
@@ -0,0 +1,176 @@
1
+ from abc import ABC, abstractmethod
2
+ from uuid import UUID
3
+ from Crypto.PublicKey.RSA import RsaKey
4
+ from datetime import datetime
5
+ from httpx import Response
6
+ from pydantic import ValidationError
7
+ from typing import Optional
8
+ from maleo.database.managers import RedisManager
9
+ from maleo.dtos.authentication import GenericAuthentication
10
+ from maleo.dtos.contexts.operation import OperationContext, generate_operation_context
11
+ from maleo.dtos.contexts.request import RequestContext
12
+ from maleo.dtos.contexts.response import ResponseContext
13
+ from maleo.dtos.contexts.service import ServiceContext
14
+ from maleo.dtos.resource import Resource
15
+ from maleo.enums.cache import Origin as CacheOrigin, Layer as CacheLayer
16
+ from maleo.enums.operation import OperationType, Origin, Layer, Target
17
+ from maleo.exceptions import (
18
+ UnprocessableEntity,
19
+ InternalServerError,
20
+ from_resource_http_request,
21
+ )
22
+ from maleo.logging.config import Config as LogConfig
23
+ from maleo.logging.logger import Client
24
+ from maleo.mixins.timestamp import OperationTimestamp
25
+ from maleo.schemas.operation.resource import AllResourceOperationAction
26
+ from maleo.schemas.response import ErrorResponse
27
+ from maleo.utils.cache import build_namespace
28
+ from ...credential import CredentialManager
29
+ from ..http import HTTPClientManager
30
+ from .config import MaleoClientConfig
31
+
32
+
33
+ class MaleoClientService:
34
+ def __init__(
35
+ self,
36
+ config: MaleoClientConfig,
37
+ logger: Client,
38
+ credential_manager: CredentialManager,
39
+ http_client_manager: HTTPClientManager,
40
+ private_key: RsaKey,
41
+ redis: RedisManager,
42
+ service_context: ServiceContext,
43
+ ):
44
+ self._config = config
45
+ self._logger = logger
46
+ self._credential_manager = credential_manager
47
+ self._http_client_manager = http_client_manager
48
+ self._private_key = private_key
49
+ self._redis = redis
50
+ self._service_context = service_context
51
+
52
+ self._namespace = build_namespace(
53
+ base=self._service_context.key,
54
+ client=self._config.key,
55
+ origin=CacheOrigin.CLIENT,
56
+ layer=CacheLayer.SERVICE,
57
+ )
58
+
59
+ self._operation_context = generate_operation_context(
60
+ origin=Origin.CLIENT, layer=Layer.SERVICE, target=Target.INTERNAL
61
+ )
62
+
63
+ def raise_resource_http_request_error(
64
+ self,
65
+ *,
66
+ executed_at: datetime,
67
+ response: Response,
68
+ operation_id: UUID,
69
+ operation_context: OperationContext,
70
+ operation_action: AllResourceOperationAction,
71
+ request_context: Optional[RequestContext],
72
+ authentication: Optional[GenericAuthentication],
73
+ resource: Resource,
74
+ ):
75
+ """Handle HTTP error response and raise appropriate exception"""
76
+ operation_timestamp = OperationTimestamp.completed_now(executed_at)
77
+
78
+ response_context = ResponseContext(
79
+ status_code=response.status_code,
80
+ media_type=response.headers.get("content-type"),
81
+ headers=response.headers.multi_items(),
82
+ body=response.content,
83
+ )
84
+
85
+ try:
86
+ error_response = ErrorResponse.model_validate(response.json())
87
+ except ValidationError as ve:
88
+ exception = UnprocessableEntity(
89
+ OperationType.RESOURCE,
90
+ service_context=self._service_context,
91
+ operation_id=operation_id,
92
+ operation_context=operation_context,
93
+ operation_timestamp=operation_timestamp,
94
+ operation_summary="Validation error occured while validating resource http request's response",
95
+ operation_action=operation_action,
96
+ request_context=request_context,
97
+ authentication=authentication,
98
+ resource=resource,
99
+ details=ve.errors(),
100
+ )
101
+ raise exception from ve
102
+ except Exception as e:
103
+ exception = InternalServerError(
104
+ OperationType.RESOURCE,
105
+ service_context=self._service_context,
106
+ operation_id=operation_id,
107
+ operation_context=self._operation_context,
108
+ operation_timestamp=operation_timestamp,
109
+ operation_summary="Unexpected error occured while validating resource http request's response",
110
+ operation_action=operation_action,
111
+ request_context=request_context,
112
+ authentication=authentication,
113
+ resource=resource,
114
+ details={
115
+ "exc_type": type(e).__name__,
116
+ "exc_data": {
117
+ "message": str(e),
118
+ "args": e.args,
119
+ },
120
+ },
121
+ )
122
+ raise exception from e
123
+
124
+ exception = from_resource_http_request(
125
+ logger=self._logger,
126
+ service_context=self._service_context,
127
+ operation_id=operation_id,
128
+ operation_context=self._operation_context,
129
+ operation_timestamp=operation_timestamp,
130
+ operation_action=operation_action,
131
+ request_context=request_context,
132
+ authentication=authentication,
133
+ resource=resource,
134
+ response_context=response_context,
135
+ response=error_response,
136
+ )
137
+ raise exception
138
+
139
+
140
+ class MaleoClientManager(ABC):
141
+ def __init__(
142
+ self,
143
+ config: MaleoClientConfig,
144
+ log_config: LogConfig,
145
+ credential_manager: CredentialManager,
146
+ private_key: RsaKey,
147
+ redis: RedisManager,
148
+ service_context: Optional[ServiceContext] = None,
149
+ ):
150
+ self._config = config
151
+ self._log_config = log_config
152
+
153
+ self._key = self._config.key
154
+ self._name = self._config.name
155
+
156
+ self._logger = Client(
157
+ environment=self._service_context.environment,
158
+ service_key=self._service_context.key,
159
+ client_key=self._key,
160
+ config=log_config,
161
+ )
162
+
163
+ self._credential_manager = credential_manager
164
+ self._http_client_manager = HTTPClientManager()
165
+ self._private_key = private_key
166
+ self._redis = redis
167
+
168
+ self._service_context = (
169
+ service_context
170
+ if service_context is not None
171
+ else ServiceContext.from_env()
172
+ )
173
+
174
+ @abstractmethod
175
+ def initalize_services(self):
176
+ pass
@@ -0,0 +1,92 @@
1
+ from pydantic import BaseModel, Field
2
+ from typing import Optional, TypeVar
3
+ from maleo.enums.environment import Environment
4
+ from maleo.enums.service import Key
5
+
6
+
7
+ class MaleoClientConfig(BaseModel):
8
+ environment: Environment = Field(..., description="Client's environment")
9
+ key: Key = Field(..., description="Client's key")
10
+ name: str = Field(..., description="Client's name")
11
+ url: str = Field(..., description="Client's URL")
12
+
13
+
14
+ class MaleoTelemetryClientConfigMixin(BaseModel):
15
+ telemetry: MaleoClientConfig = Field(
16
+ ..., description="MaleoTelemetry client's configuration"
17
+ )
18
+
19
+
20
+ class MaleoMetadataClientConfigMixin(BaseModel):
21
+ metadata: MaleoClientConfig = Field(
22
+ ..., description="MaleoMetadata client's configuration"
23
+ )
24
+
25
+
26
+ class MaleoIdentityClientConfigMixin(BaseModel):
27
+ identity: MaleoClientConfig = Field(
28
+ ..., description="MaleoIdentity client's configuration"
29
+ )
30
+
31
+
32
+ class MaleoAccessClientConfigMixin(BaseModel):
33
+ access: MaleoClientConfig = Field(
34
+ ..., description="MaleoAccess client's configuration"
35
+ )
36
+
37
+
38
+ class MaleoWorkshopClientConfigMixin(BaseModel):
39
+ workshop: MaleoClientConfig = Field(
40
+ ..., description="MaleoWorkshop client's configuration"
41
+ )
42
+
43
+
44
+ class MaleoResearchClientConfigMixin(BaseModel):
45
+ research: MaleoClientConfig = Field(
46
+ ..., description="MaleoResearch client's configuration"
47
+ )
48
+
49
+
50
+ class MaleoSOAPIEClientConfigMixin(BaseModel):
51
+ soapie: MaleoClientConfig = Field(
52
+ ..., description="MaleoSOAPIE client's configuration"
53
+ )
54
+
55
+
56
+ class MaleoMedixClientConfigMixin(BaseModel):
57
+ medix: MaleoClientConfig = Field(
58
+ ..., description="MaleoMedix client's configuration"
59
+ )
60
+
61
+
62
+ class MaleoDICOMClientConfigMixin(BaseModel):
63
+ dicom: MaleoClientConfig = Field(
64
+ ..., description="MaleoDICOM client's configuration"
65
+ )
66
+
67
+
68
+ class MaleoScribeClientConfigMixin(BaseModel):
69
+ scribe: MaleoClientConfig = Field(
70
+ ..., description="MaleoScribe client's configuration"
71
+ )
72
+
73
+
74
+ class MaleoCDSClientConfigMixin(BaseModel):
75
+ cds: MaleoClientConfig = Field(..., description="MaleoCDS client's configuration")
76
+
77
+
78
+ class MaleoImagingClientConfigMixin(BaseModel):
79
+ imaging: MaleoClientConfig = Field(
80
+ ..., description="MaleoImaging client's configuration"
81
+ )
82
+
83
+
84
+ class MaleoMCUClientConfigMixin(BaseModel):
85
+ mcu: MaleoClientConfig = Field(..., description="MaleoMCU client's configuration")
86
+
87
+
88
+ class MaleoClientsConfig(BaseModel):
89
+ pass
90
+
91
+
92
+ MaleoClientsConfigT = TypeVar("MaleoClientsConfigT", bound=Optional[MaleoClientsConfig])
@@ -0,0 +1,49 @@
1
+ from pathlib import Path
2
+ from pydantic import BaseModel, Field
3
+ from typing import Generic, Type, TypeVar
4
+ from maleo.database.config import ConfigsT as DatabaseConfigsT
5
+ from maleo.dtos.settings import ServiceSettings
6
+ from maleo.google.pubsub import ConfigT as PubSubConfigT
7
+ from maleo.google.secret import Format, GoogleSecretManager
8
+ from maleo.infra.config import Config as InfraConfig
9
+ from maleo.middlewares.config import Config as MiddlewareConfig
10
+ from maleo.types.base.uuid import OptionalUUID
11
+ from maleo.utils.loaders.yaml import from_path, from_string
12
+ from .client.config import ConfigT as ClientConfigT
13
+
14
+
15
+ class Config(BaseModel, Generic[ClientConfigT, DatabaseConfigsT]):
16
+ cient: ClientConfigT = Field(..., description="Client config")
17
+ database: DatabaseConfigsT = Field(..., description="Database configs")
18
+ infra: InfraConfig = Field(..., description="Infra config")
19
+ middleware: MiddlewareConfig = Field(..., description="Middleware config")
20
+ pubsub: PubSubConfigT = Field(..., description="PubSub config")
21
+
22
+
23
+ ConfigT = TypeVar("ConfigT", bound=Config)
24
+
25
+
26
+ class ConfigManager(Generic[ConfigT]):
27
+ def __init__(
28
+ self,
29
+ settings: ServiceSettings,
30
+ secret_manager: GoogleSecretManager,
31
+ config_cls: Type[ConfigT],
32
+ operation_id: OptionalUUID = None,
33
+ ) -> None:
34
+ use_local = settings.USE_LOCAL_CONFIG
35
+ config_path = settings.CONFIG_PATH
36
+
37
+ if use_local and config_path is not None and isinstance(config_path, str):
38
+ config_path = Path(config_path)
39
+ if config_path.exists() and config_path.is_file():
40
+ data = from_path(config_path)
41
+ self.config: ConfigT = config_cls.model_validate(data)
42
+ return
43
+
44
+ name = f"{settings.SERVICE_KEY}-config-{settings.ENVIRONMENT}"
45
+ read_secret = secret_manager.read(
46
+ Format.STRING, name=name, operation_id=operation_id
47
+ )
48
+ data = from_string(read_secret.data.value)
49
+ self.config: ConfigT = config_cls.model_validate(data)
@@ -0,0 +1,119 @@
1
+ from functools import cached_property
2
+ from Crypto.PublicKey.RSA import RsaKey
3
+ from google.oauth2.service_account import Credentials
4
+ from maleo.crypto.token import encode
5
+ from maleo.dtos.credential import Credential, MaleoCredential
6
+ from maleo.enums.environment import Environment
7
+ from maleo.enums.token import TokenType
8
+ from maleo.google.secret import Format, GoogleSecretManager
9
+ from maleo.dtos.authentication import (
10
+ PrivilegedCredentials,
11
+ AuthenticatedUser,
12
+ PrivilegedAuthentication,
13
+ )
14
+ from maleo.dtos.token import (
15
+ PrivilegedCredentialPayload,
16
+ TimestampPayload,
17
+ PrivilegedPayload,
18
+ PrivilegedAuthenticationToken,
19
+ )
20
+ from maleo.types.base.string import OptionalString
21
+ from maleo.types.base.uuid import OptionalUUID
22
+ from maleo.utils.loaders.yaml import from_string
23
+
24
+
25
+ class CredentialManager:
26
+ def __init__(
27
+ self,
28
+ environment: Environment,
29
+ private_key: RsaKey,
30
+ secret_manager: GoogleSecretManager,
31
+ operation_id: OptionalUUID = None,
32
+ ) -> None:
33
+ self._private_key = private_key
34
+ self._secret_manager = secret_manager
35
+
36
+ name = f"maleo-internal-credentials-{environment}"
37
+ read_secret = secret_manager.read(
38
+ Format.STRING, name=name, operation_id=operation_id
39
+ )
40
+ data = from_string(read_secret.data.value)
41
+ self.maleo_credentials = MaleoCredential.model_validate(data)
42
+
43
+ def assign_google_credentials(self, google_credentials: Credentials) -> None:
44
+ self.google_credentials = google_credentials
45
+
46
+ @property
47
+ def credentials(self) -> Credential:
48
+ if not hasattr(self, "google_credentials") or not isinstance(
49
+ self.google_credentials, Credentials
50
+ ):
51
+ raise ValueError("Google credential not initialized")
52
+ if not hasattr(self, "maleo_credentials") or not isinstance(
53
+ self.maleo_credentials, MaleoCredential
54
+ ):
55
+ raise ValueError("Maleo credential not initialized")
56
+ return Credential(google=self.google_credentials, maleo=self.maleo_credentials)
57
+
58
+ @cached_property
59
+ def token_credential_payload(self) -> PrivilegedCredentialPayload:
60
+ return PrivilegedCredentialPayload(
61
+ iss=None,
62
+ sub=str(self.maleo_credentials.id),
63
+ sr=["administrator"],
64
+ u_i=self.maleo_credentials.id,
65
+ u_uu=self.maleo_credentials.uuid,
66
+ u_u=self.maleo_credentials.username,
67
+ u_e=self.maleo_credentials.email,
68
+ u_ut="service",
69
+ o_i=None,
70
+ o_uu=None,
71
+ o_k=None,
72
+ o_ot=None,
73
+ uor=None,
74
+ )
75
+
76
+ @property
77
+ def token(self) -> OptionalString:
78
+ payload = PrivilegedPayload.model_validate(
79
+ {
80
+ **self.token_credential_payload.model_dump(),
81
+ **TimestampPayload.new_timestamp().model_dump(),
82
+ }
83
+ )
84
+ try:
85
+ return encode(
86
+ payload=payload.model_dump(mode="json"), key=self._private_key
87
+ )
88
+ except Exception:
89
+ return None
90
+
91
+ @property
92
+ def request_credentials(
93
+ self,
94
+ ) -> PrivilegedCredentials:
95
+ return PrivilegedCredentials(
96
+ token=PrivilegedAuthenticationToken(
97
+ type=TokenType.ACCESS,
98
+ payload=PrivilegedPayload.model_validate(
99
+ {
100
+ **self.token_credential_payload.model_dump(),
101
+ **TimestampPayload.new_timestamp().model_dump(),
102
+ }
103
+ ),
104
+ ),
105
+ scopes=["authenticated", "administrator"],
106
+ )
107
+
108
+ @cached_property
109
+ def request_user(self) -> AuthenticatedUser:
110
+ return AuthenticatedUser(
111
+ display_name=self.maleo_credentials.username,
112
+ identity=self.maleo_credentials.email,
113
+ )
114
+
115
+ @property
116
+ def authentication(self) -> PrivilegedAuthentication:
117
+ return PrivilegedAuthentication(
118
+ credentials=self.request_credentials, user=self.request_user
119
+ )
maleo/managers/key.py ADDED
@@ -0,0 +1,40 @@
1
+ from maleo.dtos.settings import ServiceSettings
2
+ from maleo.google.secret import Format, GoogleSecretManager
3
+ from maleo.dtos.key.rsa import Complete
4
+ from maleo.types.base.uuid import OptionalUUID
5
+
6
+
7
+ class RSAKeyManager:
8
+ def __init__(
9
+ self,
10
+ settings: ServiceSettings,
11
+ secret_manager: GoogleSecretManager,
12
+ operation_id: OptionalUUID = None,
13
+ ) -> None:
14
+ if settings.KEY_PASSWORD is not None:
15
+ password = settings.KEY_PASSWORD
16
+ else:
17
+ read_key_password = secret_manager.read(
18
+ Format.STRING,
19
+ name="maleo-key-password",
20
+ operation_id=operation_id,
21
+ )
22
+ password = read_key_password.data.value
23
+
24
+ if settings.PRIVATE_KEY is not None:
25
+ private = settings.PRIVATE_KEY
26
+ else:
27
+ read_private_key = secret_manager.read(
28
+ Format.STRING, name="maleo-private-key", operation_id=operation_id
29
+ )
30
+ private = read_private_key.data.value
31
+
32
+ if settings.PUBLIC_KEY is not None:
33
+ public = settings.PUBLIC_KEY
34
+ else:
35
+ read_public_key = secret_manager.read(
36
+ Format.STRING, name="maleo-public-key", operation_id=operation_id
37
+ )
38
+ public = read_public_key.data.value
39
+
40
+ self.keys = Complete(password=password, private=private, public=public)
@@ -0,0 +1,123 @@
1
+ from abc import ABC, abstractmethod
2
+ from fastapi import FastAPI, APIRouter
3
+ from fastapi.exceptions import RequestValidationError
4
+ from google.cloud import pubsub_v1
5
+ from google.oauth2.service_account import Credentials
6
+ from pydantic import ValidationError
7
+ from starlette.exceptions import HTTPException
8
+ from starlette.types import Lifespan, AppType
9
+ from sqlalchemy import MetaData
10
+ from typing import Generic, Optional
11
+ from uuid import UUID
12
+ from maleo.dtos.settings import ServiceSettingsT
13
+ from maleo.logging.config import Config as LogConfig
14
+ from maleo.logging.logger import ServiceLoggers
15
+ from maleo.middlewares.manager import MiddlewareManager
16
+ from maleo.dtos.key.rsa import Complete
17
+ from maleo.dtos.contexts.service import ServiceContext
18
+ from maleo.exceptions.handlers.request import (
19
+ http_exception_handler,
20
+ maleo_exception_handler,
21
+ pydantic_validation_exception_handler,
22
+ request_validation_exception_handler,
23
+ general_exception_handler,
24
+ )
25
+ from maleo.exceptions import MaleoException
26
+ from .config import ConfigT
27
+
28
+
29
+ class ServiceManager(ABC, Generic[ServiceSettingsT, ConfigT]):
30
+ """ServiceManager class"""
31
+
32
+ key = "service_manager"
33
+ name = "ServiceManager"
34
+
35
+ def __init__(
36
+ self,
37
+ db_metadata: MetaData,
38
+ google_credentials: Credentials,
39
+ log_config: LogConfig,
40
+ settings: ServiceSettingsT,
41
+ config: ConfigT,
42
+ keys: Complete,
43
+ ):
44
+ self._db_metadata = db_metadata
45
+ self._google_credentials = google_credentials
46
+ self._log_config = log_config
47
+ self._settings = settings
48
+ self._config = config
49
+ self._keys = keys
50
+
51
+ self._service_context = ServiceContext(
52
+ environment=self._settings.ENVIRONMENT, key=self._settings.SERVICE_KEY
53
+ )
54
+
55
+ self._initialize_loggers()
56
+ self._initialize_publisher()
57
+
58
+ def _initialize_loggers(self) -> None:
59
+ self.loggers = ServiceLoggers.new(
60
+ environment=self._settings.ENVIRONMENT,
61
+ service_key=self._settings.SERVICE_KEY,
62
+ config=self._log_config,
63
+ )
64
+
65
+ def _initialize_publisher(self) -> None:
66
+ self.publisher = pubsub_v1.PublisherClient()
67
+
68
+ @abstractmethod
69
+ def _initialize_database(self):
70
+ """Initialize all given databases"""
71
+
72
+ def create_app(
73
+ self,
74
+ operation_id: UUID,
75
+ router: APIRouter,
76
+ lifespan: Optional[Lifespan[AppType]] = None,
77
+ version: str = "unknown",
78
+ ) -> FastAPI:
79
+ root_path = self._settings.ROOT_PATH
80
+ self.app = FastAPI(
81
+ title=self._settings.SERVICE_NAME,
82
+ version=version,
83
+ lifespan=lifespan, # type: ignore
84
+ root_path=root_path,
85
+ )
86
+
87
+ # Add middleware(s)
88
+ self.middleware_manager = MiddlewareManager(
89
+ self.app,
90
+ operation_id=operation_id,
91
+ config=self._config.middleware,
92
+ keys=self._keys,
93
+ logger=self.loggers.middleware,
94
+ service_context=self._service_context,
95
+ )
96
+ self.middleware_manager.add(operation_id=operation_id)
97
+
98
+ # Add exception handler(s)
99
+ self.app.add_exception_handler(
100
+ exc_class_or_status_code=ValidationError,
101
+ handler=pydantic_validation_exception_handler, # type: ignore
102
+ )
103
+ self.app.add_exception_handler(
104
+ exc_class_or_status_code=RequestValidationError,
105
+ handler=request_validation_exception_handler, # type: ignore
106
+ )
107
+ self.app.add_exception_handler(
108
+ exc_class_or_status_code=HTTPException,
109
+ handler=http_exception_handler, # type: ignore
110
+ )
111
+ self.app.add_exception_handler(
112
+ exc_class_or_status_code=MaleoException,
113
+ handler=maleo_exception_handler, # type: ignore
114
+ )
115
+ self.app.add_exception_handler(
116
+ exc_class_or_status_code=Exception,
117
+ handler=general_exception_handler, # type: ignore
118
+ )
119
+
120
+ # Include router
121
+ self.app.include_router(router)
122
+
123
+ return self.app
@@ -0,0 +1,137 @@
1
+ Metadata-Version: 2.4
2
+ Name: maleo-managers
3
+ Version: 0.0.1
4
+ Summary: Managers package for MaleoSuite
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-types>=0.7.0
12
+ Requires-Dist: anyio>=4.10.0
13
+ Requires-Dist: async-timeout>=5.0.1
14
+ Requires-Dist: bcrypt>=4.3.0
15
+ Requires-Dist: black>=25.1.0
16
+ Requires-Dist: cachetools>=5.5.2
17
+ Requires-Dist: certifi>=2025.8.3
18
+ Requires-Dist: cffi>=2.0.0
19
+ Requires-Dist: cfgv>=3.4.0
20
+ Requires-Dist: charset-normalizer>=3.4.3
21
+ Requires-Dist: click>=8.2.1
22
+ Requires-Dist: cryptography>=45.0.7
23
+ Requires-Dist: distlib>=0.4.0
24
+ Requires-Dist: dnspython>=2.8.0
25
+ Requires-Dist: elastic-transport>=9.1.0
26
+ Requires-Dist: elasticsearch>=9.1.0
27
+ Requires-Dist: fastapi>=0.116.1
28
+ Requires-Dist: filelock>=3.19.1
29
+ Requires-Dist: google-api-core>=2.25.1
30
+ Requires-Dist: google-auth>=2.40.3
31
+ Requires-Dist: google-cloud-appengine-logging>=1.6.2
32
+ Requires-Dist: google-cloud-audit-log>=0.3.2
33
+ Requires-Dist: google-cloud-core>=2.4.3
34
+ Requires-Dist: google-cloud-logging>=3.12.1
35
+ Requires-Dist: google-cloud-pubsub>=2.31.1
36
+ Requires-Dist: google-cloud-secret-manager>=2.24.0
37
+ Requires-Dist: google-cloud-storage>=3.3.1
38
+ Requires-Dist: google-crc32c>=1.7.1
39
+ Requires-Dist: google-resumable-media>=2.7.2
40
+ Requires-Dist: googleapis-common-protos>=1.70.0
41
+ Requires-Dist: greenlet>=3.2.4
42
+ Requires-Dist: grpc-google-iam-v1>=0.14.2
43
+ Requires-Dist: grpcio>=1.74.0
44
+ Requires-Dist: grpcio-status>=1.74.0
45
+ Requires-Dist: h11>=0.16.0
46
+ Requires-Dist: httpcore>=1.0.9
47
+ Requires-Dist: httpx>=0.28.1
48
+ Requires-Dist: identify>=2.6.14
49
+ Requires-Dist: idna>=3.10
50
+ Requires-Dist: importlib_metadata>=8.7.0
51
+ Requires-Dist: maleo-constants>=0.0.6
52
+ Requires-Dist: maleo-crypto>=0.0.2
53
+ Requires-Dist: maleo-database>=0.0.18
54
+ Requires-Dist: maleo-dtos>=0.0.18
55
+ Requires-Dist: maleo-enums>=0.0.6
56
+ Requires-Dist: maleo-exceptions>=0.0.24
57
+ Requires-Dist: maleo-google>=0.0.12
58
+ Requires-Dist: maleo-infra>=0.0.4
59
+ Requires-Dist: maleo-logging>=0.0.8
60
+ Requires-Dist: maleo-middlewares>=0.0.12
61
+ Requires-Dist: maleo-mixins>=0.0.13
62
+ Requires-Dist: maleo-schemas>=0.0.21
63
+ Requires-Dist: maleo-types-base>=0.0.2
64
+ Requires-Dist: maleo-types-controllers>=0.0.1
65
+ Requires-Dist: maleo-types-enums>=0.0.4
66
+ Requires-Dist: maleo-utils>=0.0.5
67
+ Requires-Dist: motor>=3.7.1
68
+ Requires-Dist: mypy_extensions>=1.1.0
69
+ Requires-Dist: nodeenv>=1.9.1
70
+ Requires-Dist: opentelemetry-api>=1.36.0
71
+ Requires-Dist: opentelemetry-sdk>=1.36.0
72
+ Requires-Dist: opentelemetry-semantic-conventions>=0.57b0
73
+ Requires-Dist: packaging>=25.0
74
+ Requires-Dist: pathspec>=0.12.1
75
+ Requires-Dist: platformdirs>=4.4.0
76
+ Requires-Dist: pre_commit>=4.3.0
77
+ Requires-Dist: proto-plus>=1.26.1
78
+ Requires-Dist: protobuf>=6.32.0
79
+ Requires-Dist: psutil>=7.0.0
80
+ Requires-Dist: pyasn1>=0.6.1
81
+ Requires-Dist: pyasn1_modules>=0.4.2
82
+ Requires-Dist: pycparser>=2.22
83
+ Requires-Dist: pycryptodome>=3.23.0
84
+ Requires-Dist: pydantic>=2.11.7
85
+ Requires-Dist: pydantic-settings>=2.10.1
86
+ Requires-Dist: pydantic_core>=2.33.2
87
+ Requires-Dist: PyJWT>=2.10.1
88
+ Requires-Dist: pymongo>=4.14.1
89
+ Requires-Dist: python-dateutil>=2.9.0.post0
90
+ Requires-Dist: python-dotenv>=1.1.1
91
+ Requires-Dist: PyYAML>=6.0.2
92
+ Requires-Dist: redis>=6.4.0
93
+ Requires-Dist: requests>=2.32.5
94
+ Requires-Dist: rsa>=4.9.1
95
+ Requires-Dist: six>=1.17.0
96
+ Requires-Dist: sniffio>=1.3.1
97
+ Requires-Dist: SQLAlchemy>=2.0.43
98
+ Requires-Dist: starlette>=0.47.3
99
+ Requires-Dist: typing-inspection>=0.4.1
100
+ Requires-Dist: typing_extensions>=4.15.0
101
+ Requires-Dist: ua-parser>=1.0.1
102
+ Requires-Dist: ua-parser-builtins>=0.18.0.post1
103
+ Requires-Dist: urllib3>=2.5.0
104
+ Requires-Dist: user-agents>=2.2.0
105
+ Requires-Dist: virtualenv>=20.34.0
106
+ Requires-Dist: zipp>=3.23.0
107
+ Dynamic: license-file
108
+
109
+ # README #
110
+
111
+ This README would normally document whatever steps are necessary to get your application up and running.
112
+
113
+ ### What is this repository for? ###
114
+
115
+ * Quick summary
116
+ * Version
117
+ * [Learn Markdown](https://bitbucket.org/tutorials/markdowndemo)
118
+
119
+ ### How do I get set up? ###
120
+
121
+ * Summary of set up
122
+ * Configuration
123
+ * Dependencies
124
+ * Database configuration
125
+ * How to run tests
126
+ * Deployment instructions
127
+
128
+ ### Contribution guidelines ###
129
+
130
+ * Writing tests
131
+ * Code review
132
+ * Other guidelines
133
+
134
+ ### Who do I talk to? ###
135
+
136
+ * Repo owner or admin
137
+ * Other community or team contact
@@ -0,0 +1,15 @@
1
+ maleo/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ maleo/managers/config.py,sha256=2iVGNbhWy1z6p763dm3OELhS3zGycLkBi-7KX2H_Sek,2046
3
+ maleo/managers/credential.py,sha256=-acqO72GeNrd_YfMQ9MkhZgWXf-jsNMYTId4ILkwBwI,4087
4
+ maleo/managers/key.py,sha256=CFm3-uLpzmzFmnTEMPTg5rSRxs4Y3HOVNbAgajfP9G4,1407
5
+ maleo/managers/service.py,sha256=Xf6jG5K-IVmbA00rayBeXuM4AaIrQ7mM4RKAU-26mcI,4089
6
+ maleo/managers/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ maleo/managers/client/config.py,sha256=ySx6w9vmFYWHNm3lqO6OY_v1l8pKhQeCtCP7h1txxKE,466
8
+ maleo/managers/client/http.py,sha256=sPPqCbJsNcyIzcZbDv8Sga_fnXJDM812j8qSLLd6QOg,790
9
+ maleo/managers/client/maleo/__init__.py,sha256=8twb4XguV4GvRlR6eBtGA1XEgAuqei-1QHf7zRtxnfU,6423
10
+ maleo/managers/client/maleo/config.py,sha256=fRzsTn-LI6lfuxPNjjhhjl8Ag5ovAttUF2E-W9CB91s,2590
11
+ maleo_managers-0.0.1.dist-info/licenses/LICENSE,sha256=aftGsecnk7TWVX-7KW94FqK4Syy6YSZ8PZEF7EcIp3M,2621
12
+ maleo_managers-0.0.1.dist-info/METADATA,sha256=rxFLjuzJzHewBmlRBN3KKjiQGDS3bDVFtHSxTVT6d34,4281
13
+ maleo_managers-0.0.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
14
+ maleo_managers-0.0.1.dist-info/top_level.txt,sha256=3Tpd1siVsfYoeI9FEOJNYnffx_shzZ3wsPpTvz5bljc,6
15
+ maleo_managers-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,57 @@
1
+ # Proprietary Software License
2
+
3
+ **Copyright (c) 2025 Agra Bima Yuda / Nexmedis**
4
+
5
+ ## License Grant
6
+
7
+ This software and associated documentation files (the "Software") are proprietary and confidential to Agra Bima Yuda and/or Nexmedis ("Licensor"). All rights reserved.
8
+
9
+ ## Restrictions
10
+
11
+ **NO PERMISSION** is granted to any person to:
12
+
13
+ 1. **Use** the Software for any purpose without explicit written permission from the Licensor
14
+ 2. **Copy, modify, merge, publish, distribute, sublicense, or sell** copies of the Software
15
+ 3. **Reverse engineer, decompile, or disassemble** the Software
16
+ 4. **Create derivative works** based upon the Software
17
+ 5. **Remove or alter** any proprietary notices, labels, or marks on the Software
18
+
19
+ ## Permitted Use
20
+
21
+ Use of this Software is permitted only under the following conditions:
22
+
23
+ 1. **Authorized Users**: Only individuals or entities explicitly authorized by the Licensor in writing
24
+ 2. **Internal Use Only**: The Software may only be used for internal business purposes of the authorized entity
25
+ 3. **No Redistribution**: The Software may not be shared, distributed, or made available to any third party
26
+
27
+ ## Ownership
28
+
29
+ The Software is and remains the exclusive property of the Licensor. This license does not grant any ownership rights in the Software.
30
+
31
+ ## Confidentiality
32
+
33
+ The Software contains proprietary and confidential information. Recipients agree to:
34
+
35
+ 1. Maintain the confidentiality of the Software
36
+ 2. Use the same degree of care to protect the Software as they use for their own confidential information, but no less than reasonable care
37
+ 3. Not disclose the Software to any third party without prior written consent
38
+
39
+ ## Termination
40
+
41
+ This license is effective until terminated. The Licensor may terminate this license at any time without notice. Upon termination, all rights granted herein cease immediately, and the recipient must destroy all copies of the Software.
42
+
43
+ ## Disclaimer of Warranty
44
+
45
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
46
+
47
+ ## Limitation of Liability
48
+
49
+ IN NO EVENT SHALL THE LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
50
+
51
+ ## Governing Law
52
+
53
+ This license shall be governed by and construed in accordance with the laws of Indonesia, without regard to its conflict of law provisions.
54
+
55
+ ---
56
+
57
+ For licensing inquiries, contact: agra@nexmedis.com
@@ -0,0 +1 @@
1
+ maleo