maleo-foundation 0.1.35__py3-none-any.whl → 0.1.37__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/managers/db.py +4 -5
- maleo_foundation/managers/service.py +3 -4
- maleo_foundation/middlewares/authentication.py +2 -2
- maleo_foundation/middlewares/base.py +2 -19
- maleo_foundation/utils/__init__.py +4 -2
- maleo_foundation/utils/exceptions.py +1 -13
- maleo_foundation/utils/extractor.py +16 -14
- maleo_foundation/utils/keyloader.py +52 -50
- {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/METADATA +1 -1
- {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/RECORD +13 -32
- maleo_foundation/clients/__init__.py +0 -7
- maleo_foundation/clients/general/__init__.py +0 -4
- maleo_foundation/clients/general/http.py +0 -50
- maleo_foundation/clients/google/__init__.py +0 -4
- maleo_foundation/clients/google/base.py +0 -32
- maleo_foundation/clients/google/cloud/__init__.py +0 -8
- maleo_foundation/clients/google/cloud/base.py +0 -32
- maleo_foundation/clients/google/cloud/logging.py +0 -63
- maleo_foundation/clients/google/cloud/secret.py +0 -149
- maleo_foundation/clients/google/cloud/storage.py +0 -110
- maleo_foundation/clients/google/secret.py +0 -61
- maleo_foundation/clients/google/storage.py +0 -57
- maleo_foundation/clients/utils/__init__.py +0 -5
- maleo_foundation/clients/utils/logger.py +0 -54
- maleo_foundation/db/__init__.py +0 -4
- maleo_foundation/db/engine.py +0 -76
- maleo_foundation/db/manager.py +0 -122
- maleo_foundation/db/session.py +0 -111
- maleo_foundation/utils/logger.py +0 -92
- /maleo_foundation/{db → models}/table.py +0 -0
- {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/WHEEL +0 -0
- {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/top_level.txt +0 -0
maleo_foundation/managers/db.py
CHANGED
@@ -5,17 +5,16 @@ from sqlalchemy.engine import Engine, create_engine
|
|
5
5
|
from sqlalchemy.exc import SQLAlchemyError
|
6
6
|
from sqlalchemy.ext.declarative import DeclarativeMeta
|
7
7
|
from sqlalchemy.orm import sessionmaker, Session, declarative_base
|
8
|
-
from typing import Generator
|
8
|
+
from typing import Generator
|
9
9
|
from maleo_foundation.types import BaseTypes
|
10
|
-
from maleo_foundation.utils.
|
11
|
-
from maleo_foundation.db.table import BaseTable
|
10
|
+
from maleo_foundation.utils.logging import ServiceLogger
|
12
11
|
|
13
12
|
class MetadataManager:
|
14
13
|
Base:DeclarativeMeta = declarative_base()
|
15
14
|
metadata:MetaData = Base.metadata
|
16
15
|
|
17
16
|
class SessionManager:
|
18
|
-
def __init__(self, logger:
|
17
|
+
def __init__(self, logger:ServiceLogger, engine:Engine):
|
19
18
|
self._logger = logger
|
20
19
|
self._logger.info("Initializing SessionMaker")
|
21
20
|
self._sessionmaker:sessionmaker[Session] = sessionmaker(bind=engine, expire_on_commit=False)
|
@@ -62,7 +61,7 @@ class DatabaseManager:
|
|
62
61
|
def __init__(
|
63
62
|
self,
|
64
63
|
metadata:MetaData,
|
65
|
-
logger:
|
64
|
+
logger:ServiceLogger,
|
66
65
|
url:BaseTypes.OptionalString = None
|
67
66
|
):
|
68
67
|
self._metadata = metadata #* Define database metadata
|
@@ -1,6 +1,5 @@
|
|
1
1
|
import json
|
2
2
|
import os
|
3
|
-
import uvicorn
|
4
3
|
from fastapi import FastAPI, APIRouter
|
5
4
|
from fastapi.exceptions import RequestValidationError
|
6
5
|
from starlette.exceptions import HTTPException
|
@@ -21,7 +20,7 @@ from maleo_foundation.middlewares.base import RequestProcessor
|
|
21
20
|
from maleo_foundation.services.token import BaseTokenService
|
22
21
|
from maleo_foundation.types import BaseTypes
|
23
22
|
from maleo_foundation.utils.exceptions import BaseExceptions
|
24
|
-
from maleo_foundation.utils.keyloader import
|
23
|
+
from maleo_foundation.utils.keyloader import BaseKeyLoaders
|
25
24
|
from maleo_foundation.utils.logging import GoogleCloudLogging, ServiceLogger, MiddlewareLogger
|
26
25
|
|
27
26
|
class LogConfig(BaseModel):
|
@@ -295,14 +294,14 @@ class ServiceManager:
|
|
295
294
|
def _parse_keys(self) -> None:
|
296
295
|
#* Parse private key
|
297
296
|
key_type = BaseEnums.KeyType.PRIVATE
|
298
|
-
private =
|
297
|
+
private = BaseKeyLoaders.load_rsa(
|
299
298
|
type=key_type,
|
300
299
|
path=self._settings.PRIVATE_KEY_PATH,
|
301
300
|
password=self._settings.KEY_PASSWORD
|
302
301
|
)
|
303
302
|
#* Parse public key
|
304
303
|
key_type = BaseEnums.KeyType.PUBLIC
|
305
|
-
public =
|
304
|
+
public = BaseKeyLoaders.load_rsa(
|
306
305
|
type=key_type,
|
307
306
|
path=self._settings.PUBLIC_KEY_PATH
|
308
307
|
)
|
@@ -6,7 +6,7 @@ from typing import Tuple
|
|
6
6
|
from maleo_foundation.authentication import Credentials, User
|
7
7
|
from maleo_foundation.models.transfers.parameters.token import BaseTokenParametersTransfers
|
8
8
|
from maleo_foundation.services.token import BaseTokenService
|
9
|
-
from maleo_foundation.utils.extractor import
|
9
|
+
from maleo_foundation.utils.extractor import BaseExtractors
|
10
10
|
from maleo_foundation.utils.logging import MiddlewareLogger
|
11
11
|
|
12
12
|
class Backend(AuthenticationBackend):
|
@@ -16,7 +16,7 @@ class Backend(AuthenticationBackend):
|
|
16
16
|
self._key = key
|
17
17
|
|
18
18
|
async def authenticate(self, conn:HTTPConnection) -> Tuple[Credentials, User]:
|
19
|
-
client_ip = extract_client_ip(conn)
|
19
|
+
client_ip = BaseExtractors.extract_client_ip(conn)
|
20
20
|
if "Authorization" not in conn.headers:
|
21
21
|
self._logger.info(f"Request | IP: {client_ip} | URL: {conn.url.path} - Result | General: Header did not contain authorization")
|
22
22
|
return Credentials(), User(authenticated=False)
|
@@ -9,7 +9,7 @@ from fastapi.responses import JSONResponse
|
|
9
9
|
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
|
10
10
|
from typing import Awaitable, Callable, Optional, Sequence
|
11
11
|
from maleo_foundation.models.responses import BaseResponses
|
12
|
-
from maleo_foundation.utils.extractor import
|
12
|
+
from maleo_foundation.utils.extractor import BaseExtractors
|
13
13
|
from maleo_foundation.utils.logging import MiddlewareLogger
|
14
14
|
|
15
15
|
RequestProcessor = Callable[[Request], Awaitable[Optional[Response]]]
|
@@ -80,23 +80,6 @@ class BaseMiddleware(BaseHTTPMiddleware):
|
|
80
80
|
self.last_cleanup = now
|
81
81
|
self.logger.debug(f"Cleaned up request cache. Removed {len(inactive_ips)} inactive IPs. Current tracked IPs: {len(self.requests)}")
|
82
82
|
|
83
|
-
def _extract_client_ip(self, request:Request) -> str:
|
84
|
-
"""Extract client IP with more robust handling of proxies"""
|
85
|
-
#* Check for X-Forwarded-For header (common when behind proxy/load balancer)
|
86
|
-
x_forwarded_for = request.headers.get("X-Forwarded-For")
|
87
|
-
if x_forwarded_for:
|
88
|
-
#* The client's IP is the first one in the list
|
89
|
-
ips = [ip.strip() for ip in x_forwarded_for.split(",")]
|
90
|
-
return ips[0]
|
91
|
-
|
92
|
-
#* Check for X-Real-IP header (used by some proxies)
|
93
|
-
x_real_ip = request.headers.get("X-Real-IP")
|
94
|
-
if x_real_ip:
|
95
|
-
return x_real_ip
|
96
|
-
|
97
|
-
#* Fall back to direct client connection
|
98
|
-
return request.client.host if request.client else "unknown"
|
99
|
-
|
100
83
|
def _check_rate_limit(self, client_ip:str) -> bool:
|
101
84
|
"""Check if the client has exceeded their rate limit"""
|
102
85
|
with self._lock:
|
@@ -179,7 +162,7 @@ class BaseMiddleware(BaseHTTPMiddleware):
|
|
179
162
|
self._cleanup_old_data() #* Run periodic cleanup
|
180
163
|
request_timestamp = datetime.now(tz=timezone.utc) #* Record the request timestamp
|
181
164
|
start_time = time.perf_counter() #* Record the start time
|
182
|
-
client_ip = extract_client_ip(request) #* Get request IP with improved extraction
|
165
|
+
client_ip = BaseExtractors.extract_client_ip(request) #* Get request IP with improved extraction
|
183
166
|
|
184
167
|
try:
|
185
168
|
#* 1. Rate limit check
|
@@ -1,13 +1,15 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
from .formatter import BaseFormatter
|
3
|
-
from .logger import BaseLogger
|
4
3
|
from .exceptions import BaseExceptions
|
4
|
+
from .extractor import BaseExtractors
|
5
|
+
from .keyloader import BaseKeyLoaders
|
5
6
|
from .controller import BaseControllerUtils
|
6
7
|
from .query import BaseQueryUtils
|
7
8
|
|
8
9
|
class BaseUtils:
|
9
10
|
Formatter = BaseFormatter
|
10
|
-
Logger = BaseLogger
|
11
11
|
Exceptions = BaseExceptions
|
12
|
+
Extractors = BaseExtractors
|
13
|
+
KeyLoader = BaseKeyLoaders
|
12
14
|
Controller = BaseControllerUtils
|
13
15
|
Query = BaseQueryUtils
|
@@ -8,7 +8,7 @@ from typing import Optional
|
|
8
8
|
from maleo_foundation.models.responses import BaseResponses
|
9
9
|
from maleo_foundation.models.transfers.results.service.general import BaseServiceGeneralResultsTransfers
|
10
10
|
from maleo_foundation.models.transfers.results.service.query import BaseServiceQueryResultsTransfers
|
11
|
-
from maleo_foundation.utils.
|
11
|
+
from maleo_foundation.utils.logging import BaseLogger
|
12
12
|
|
13
13
|
class BaseExceptions:
|
14
14
|
@staticmethod
|
@@ -27,15 +27,9 @@ class BaseExceptions:
|
|
27
27
|
def database_exception_handler(
|
28
28
|
operation:str,
|
29
29
|
logger:Optional[BaseLogger] = None,
|
30
|
-
logger_factory:Optional[LoggerFactory] = None,
|
31
30
|
fail_result_class:type[BaseServiceQueryResultsTransfers.Fail] = BaseServiceQueryResultsTransfers.Fail
|
32
31
|
):
|
33
32
|
"""Decorator to handle database-related exceptions consistently."""
|
34
|
-
if logger is not None and logger_factory is not None:
|
35
|
-
raise RuntimeError("Only one of 'logger' or 'logger_factory' should be provided, not both.")
|
36
|
-
if logger is None and logger_factory is None:
|
37
|
-
raise RuntimeError("One of 'logger' or 'logger_factory' must be provided.")
|
38
|
-
logger = logger or logger_factory()
|
39
33
|
def decorator(func):
|
40
34
|
@wraps(func)
|
41
35
|
def wrapper(*args, **kwargs):
|
@@ -62,15 +56,9 @@ class BaseExceptions:
|
|
62
56
|
def service_exception_handler(
|
63
57
|
operation:str,
|
64
58
|
logger:Optional[BaseLogger] = None,
|
65
|
-
logger_factory:Optional[LoggerFactory] = None,
|
66
59
|
fail_result_class:type[BaseServiceGeneralResultsTransfers.Fail] = BaseServiceGeneralResultsTransfers.Fail
|
67
60
|
):
|
68
61
|
"""Decorator to handle service-related exceptions consistently."""
|
69
|
-
if logger is not None and logger_factory is not None:
|
70
|
-
raise RuntimeError("Only one of 'logger' or 'logger_factory' should be provided, not both.")
|
71
|
-
if logger is None and logger_factory is None:
|
72
|
-
raise RuntimeError("One of 'logger' or 'logger_factory' must be provided.")
|
73
|
-
logger = logger or logger_factory()
|
74
62
|
def decorator(func):
|
75
63
|
@wraps(func)
|
76
64
|
def wrapper(*args, **kwargs):
|
@@ -1,18 +1,20 @@
|
|
1
1
|
from starlette.requests import HTTPConnection
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
class BaseExtractors:
|
4
|
+
@staticmethod
|
5
|
+
def extract_client_ip(conn:HTTPConnection) -> str:
|
6
|
+
"""Extract client IP with more robust handling of proxies"""
|
7
|
+
#* Check for X-Forwarded-For header (common when behind proxy/load balancer)
|
8
|
+
x_forwarded_for = conn.headers.get("X-Forwarded-For")
|
9
|
+
if x_forwarded_for:
|
10
|
+
#* The client's IP is the first one in the list
|
11
|
+
ips = [ip.strip() for ip in x_forwarded_for.split(",")]
|
12
|
+
return ips[0]
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
#* Check for X-Real-IP header (used by some proxies)
|
15
|
+
x_real_ip = conn.headers.get("X-Real-IP")
|
16
|
+
if x_real_ip:
|
17
|
+
return x_real_ip
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
+
#* Fall back to direct client connection
|
20
|
+
return conn.client.host if conn.client else "unknown"
|
@@ -3,63 +3,65 @@ from cryptography.hazmat.primitives import serialization
|
|
3
3
|
from typing import Optional, Union
|
4
4
|
from maleo_foundation.enums import BaseEnums
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
6
|
+
class BaseKeyLoaders:
|
7
|
+
@staticmethod
|
8
|
+
def load_rsa(
|
9
|
+
type:BaseEnums.KeyType,
|
10
|
+
path: Union[str, pathlib.Path],
|
11
|
+
password:Optional[Union[str, bytes]] = None,
|
12
|
+
format:BaseEnums.KeyFormatType = BaseEnums.KeyFormatType.STRING,
|
13
|
+
) -> Union[bytes, str]:
|
14
|
+
"""
|
15
|
+
Load an RSA private or public key strictly from a file.
|
14
16
|
|
15
|
-
|
16
|
-
|
17
|
-
|
17
|
+
Args:
|
18
|
+
path (str | pathlib.Path): Path to the PEM file.
|
19
|
+
password (str | bytes | None): Password for encrypted private keys (optional).
|
18
20
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
21
|
+
Returns:
|
22
|
+
rsa.RSAPrivateKey | rsa.RSAPublicKey
|
23
|
+
"""
|
24
|
+
if not isinstance(type, BaseEnums.KeyType):
|
25
|
+
raise TypeError("Invalid key type")
|
24
26
|
|
25
|
-
|
27
|
+
file_path = pathlib.Path(path)
|
26
28
|
|
27
|
-
|
28
|
-
|
29
|
+
if not file_path.is_file():
|
30
|
+
raise FileNotFoundError(f"Key file not found: {file_path}")
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
+
if password is not None and not isinstance(password, (str, bytes)):
|
33
|
+
raise TypeError("Invalid passsword type")
|
32
34
|
|
33
|
-
|
34
|
-
|
35
|
+
if not isinstance(format, BaseEnums.KeyFormatType):
|
36
|
+
raise TypeError("Invalid key format type")
|
35
37
|
|
36
|
-
|
38
|
+
key_data = file_path.read_bytes()
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
40
|
+
if type == BaseEnums.KeyType.PRIVATE:
|
41
|
+
private_key = serialization.load_pem_private_key(
|
42
|
+
key_data,
|
43
|
+
password=password.encode() if isinstance(password, str) else password,
|
44
|
+
)
|
45
|
+
private_key_bytes = private_key.private_bytes(
|
46
|
+
encoding=serialization.Encoding.PEM,
|
47
|
+
format=serialization.PrivateFormat.PKCS8,
|
48
|
+
encryption_algorithm=serialization.NoEncryption()
|
49
|
+
)
|
50
|
+
if format == BaseEnums.KeyFormatType.BYTES:
|
51
|
+
return private_key_bytes
|
52
|
+
elif format == BaseEnums.KeyFormatType.STRING:
|
53
|
+
return private_key_bytes.decode()
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
55
|
+
elif type == BaseEnums.KeyType.PUBLIC:
|
56
|
+
public_key = serialization.load_pem_public_key(key_data)
|
57
|
+
public_key_bytes = public_key.public_bytes(
|
58
|
+
encoding=serialization.Encoding.PEM,
|
59
|
+
format=serialization.PublicFormat.SubjectPublicKeyInfo
|
60
|
+
)
|
61
|
+
if format == BaseEnums.KeyFormatType.BYTES:
|
62
|
+
return public_key_bytes
|
63
|
+
elif format == BaseEnums.KeyFormatType.STRING:
|
64
|
+
return public_key_bytes.decode()
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
+
else:
|
67
|
+
raise ValueError(f"Unsupported key type: {type}")
|
@@ -4,25 +4,6 @@ maleo_foundation/constants.py,sha256=aBmEfWlBqZxi0k-n6h2NM1YRLOjMnheEiLyQcjP-zCQ
|
|
4
4
|
maleo_foundation/enums.py,sha256=uvwl3dl2r6BoJMEbtSETiLoyJubHup9Lc7VOg7w7zQo,2943
|
5
5
|
maleo_foundation/extended_types.py,sha256=pIKt-_9tby4rmune3fmWcCW_mohaNRh_1lywBmdc-L4,301
|
6
6
|
maleo_foundation/types.py,sha256=aKXnIgEhYGSfFqNMGLc4qIKGkINBRpkOo9R9cb2CbwI,2414
|
7
|
-
maleo_foundation/clients/__init__.py,sha256=W8vydJYeDEi6gdmOZSBFSSDsfZJtb8C05CHErZgsZ30,188
|
8
|
-
maleo_foundation/clients/general/__init__.py,sha256=l9eQrBeLW4aXtGU5aK3i6fD-msVR4526W7D9V8WCXIg,91
|
9
|
-
maleo_foundation/clients/general/http.py,sha256=pObW6EaMeLDNsRZ9QJPzfhZDzcZ33kCsb-9Yfoh2MA4,1670
|
10
|
-
maleo_foundation/clients/google/__init__.py,sha256=1uv6nF9QbATsSAcMimQOT7Y-eBljjDunBojNX6oAtS8,90
|
11
|
-
maleo_foundation/clients/google/base.py,sha256=tdiqNNtvy-Ev_L7R4Dg9y7V14QdlbfCOQ2Mulo238aE,1141
|
12
|
-
maleo_foundation/clients/google/secret.py,sha256=4k3pDs4HAibeCEgv8nUBADfhk2aftG9L1sfR3UxAyfE,2516
|
13
|
-
maleo_foundation/clients/google/storage.py,sha256=smsmrjKAyxtfdqz3EzuUVx_rQeaTaYZ5VKNWCvwQ4U8,1971
|
14
|
-
maleo_foundation/clients/google/cloud/__init__.py,sha256=WGMPxEKKdkz3XGY5dZn9E-nYhD1kv1MgRHbmVnky4zk,245
|
15
|
-
maleo_foundation/clients/google/cloud/base.py,sha256=V_5Zdu90FQLgAfUZvlB1KojFzXNKZNIR516gjDXgaPU,1146
|
16
|
-
maleo_foundation/clients/google/cloud/logging.py,sha256=s9T9bex0GeCPwIHrBRvilT23iyNKqJ5z50KcT76Jt5Y,2202
|
17
|
-
maleo_foundation/clients/google/cloud/secret.py,sha256=1dua0V2FHesjltLdc1N4PF8xTXPzmcSA3sgwBzYNUtM,5853
|
18
|
-
maleo_foundation/clients/google/cloud/storage.py,sha256=t8hAZiQj_RFhJJXE8a20WP7spNKTEFw1RK1AqurL3T8,3848
|
19
|
-
maleo_foundation/clients/utils/__init__.py,sha256=hChEGABHH4tOFxPRcpxmlhkM9PgF18M7wXapH88hpu4,131
|
20
|
-
maleo_foundation/clients/utils/logger.py,sha256=FMnHKV4i6xR6e8XN7kCNwTf1jhSLdJUIO7teSm5g0D4,1829
|
21
|
-
maleo_foundation/db/__init__.py,sha256=fmvhCz4_siHfyKJujcUakKDKmuLxMhxn2w5tmfQwfcM,135
|
22
|
-
maleo_foundation/db/engine.py,sha256=hhYjCt5IEb864H2RNlUVS7GfMzuThHKRV260Bgkhn_o,3003
|
23
|
-
maleo_foundation/db/manager.py,sha256=nSstMJ9JBoEKTSLlz6MNf4Wuet8DLp2Pipfveg4kM1c,4663
|
24
|
-
maleo_foundation/db/session.py,sha256=6flx_HVh4Fe3EohK2xDcyXmVAPOci1KFvhVK4wFcKtA,4736
|
25
|
-
maleo_foundation/db/table.py,sha256=Dk5GXeO0gbBBPN2PJtZhlUx2x3vMbT4dxTBc3YLBbuc,1199
|
26
7
|
maleo_foundation/expanded_types/__init__.py,sha256=lm_r7rxlLA0sgSTGQBMR9ZbZbVDpD7Te-UYb3oRVi1g,364
|
27
8
|
maleo_foundation/expanded_types/client.py,sha256=To0kRXp3QTmuSu5rWKaCiTsMK9qkYiyYKYbHfw-y1fY,2396
|
28
9
|
maleo_foundation/expanded_types/general.py,sha256=bjIBREYTS73tvS-Key7P7db82a2HHlSJ1XBAvKuYmT0,826
|
@@ -30,9 +11,9 @@ maleo_foundation/expanded_types/query.py,sha256=0yUG-JIVsanzB7KAkrRz_OsrhP6J0bRq
|
|
30
11
|
maleo_foundation/expanded_types/service.py,sha256=q8jpKdbCbLWwH1UPQavKpVE14rC5rveduk2cFWzuhGw,2416
|
31
12
|
maleo_foundation/expanded_types/token.py,sha256=4fRTJw6W5MYq71NksNrWNi7qYHQ4_lQwfu9WxwrMipc,355
|
32
13
|
maleo_foundation/managers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
33
|
-
maleo_foundation/managers/db.py,sha256=
|
14
|
+
maleo_foundation/managers/db.py,sha256=ZN0b43OgqQtk2WHKMJQ0E2TeaSEyVJ0-l4FEkrSG0Qo,4645
|
34
15
|
maleo_foundation/managers/middleware.py,sha256=7CDXPMb28AR7J72TWOeKFxOlMypKezEtO9mr53a88B0,4032
|
35
|
-
maleo_foundation/managers/service.py,sha256
|
16
|
+
maleo_foundation/managers/service.py,sha256=-xsghwPtqV95YcktytV7Zba_E38JkmwUPlHXcLppfkQ,20413
|
36
17
|
maleo_foundation/managers/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
18
|
maleo_foundation/managers/client/base.py,sha256=lYREmEoTLShlPPXOKKiAopjefJ8nIWHCi7IvWkXXKeY,1465
|
38
19
|
maleo_foundation/managers/client/maleo.py,sha256=NibYGdiN3EXUw5nx-tL48QAZym14GcA4BDZihGJNQ-g,4254
|
@@ -41,11 +22,12 @@ maleo_foundation/managers/client/google/base.py,sha256=7jCnzkBN-F8xJEfP5eopuyfRB
|
|
41
22
|
maleo_foundation/managers/client/google/secret.py,sha256=E2SthMUHScIo9Cz5ICbCK7xBg16hnzKANk7--B82828,3481
|
42
23
|
maleo_foundation/managers/client/google/storage.py,sha256=CZmbKBS4p7OCYb5MKWmGB56-Dl7gi7xXteoqpJpVH08,2748
|
43
24
|
maleo_foundation/middlewares/__init__.py,sha256=bqE2EIFC3rWcR2AwFPR0fk2kSFfeTRzgA24GbnuT5RA,3697
|
44
|
-
maleo_foundation/middlewares/authentication.py,sha256=
|
45
|
-
maleo_foundation/middlewares/base.py,sha256=
|
25
|
+
maleo_foundation/middlewares/authentication.py,sha256=mpJ4WJ25zw4SGvgpeJE9eSV3-AtK5IJtN2U8Dh9rmMk,3132
|
26
|
+
maleo_foundation/middlewares/base.py,sha256=iGc_4JZYxE0k47Dty4aFOvpgXjQY_W_4tgqYndhq3V8,10991
|
46
27
|
maleo_foundation/middlewares/cors.py,sha256=9uvBvY2N6Vxa9RP_YtESxcWo6Doi6uS0lzAG9iLY7Uc,2288
|
47
28
|
maleo_foundation/models/__init__.py,sha256=AaKehO7c1HyKhoTGRmNHDddSeBXkW-_YNrpOGBu8Ms8,246
|
48
29
|
maleo_foundation/models/responses.py,sha256=Ka9Peb1fVuQKaxyy11FVkUPtGtzyEm_9Xfe8Vla3ml0,4764
|
30
|
+
maleo_foundation/models/table.py,sha256=Dk5GXeO0gbBBPN2PJtZhlUx2x3vMbT4dxTBc3YLBbuc,1199
|
49
31
|
maleo_foundation/models/schemas/__init__.py,sha256=Xj8Ahsqyra-fmEaVcGPok5GOOsPQlKcknHYMvbjvENA,277
|
50
32
|
maleo_foundation/models/schemas/general.py,sha256=hEQQPcddxMsJXMb36nqItIAfp3pqUyJOlaD7nXkNM2I,3609
|
51
33
|
maleo_foundation/models/schemas/parameter.py,sha256=K47z2NzmTEhUiOfRiRLyRPXoQurbWsKBL7ObXAxIWRY,2100
|
@@ -72,17 +54,16 @@ maleo_foundation/models/transfers/results/service/controllers/__init__.py,sha256
|
|
72
54
|
maleo_foundation/models/transfers/results/service/controllers/rest.py,sha256=wCuFyOTQkuBs2cqjPsWnPy0XIsCfMqGByhrSy57qp7Y,1107
|
73
55
|
maleo_foundation/services/__init__.py,sha256=Ho5zJSA89xdGFKIwOdzjmd8sm23cIuwrqYAxCEBBTIU,120
|
74
56
|
maleo_foundation/services/token.py,sha256=ZqRqOdGUnaSIam6-JHVdAW1UST-2EDtcVN0fpbPmXY4,1638
|
75
|
-
maleo_foundation/utils/__init__.py,sha256=
|
57
|
+
maleo_foundation/utils/__init__.py,sha256=eEnPPeA6la0mu7535EFEKUB02C1IO_R8JgYcohvf1qU,471
|
76
58
|
maleo_foundation/utils/controller.py,sha256=ECzPzpw36zBAjKcWcDbUAhIJGbc6UpeypdUUX6ipXBg,6396
|
77
|
-
maleo_foundation/utils/exceptions.py,sha256=
|
78
|
-
maleo_foundation/utils/extractor.py,sha256=
|
79
|
-
maleo_foundation/utils/keyloader.py,sha256=
|
80
|
-
maleo_foundation/utils/logger.py,sha256=uTvzzKnGjbxRVLHbiMDw2zKKWNaCwV35sxgjDStEwNQ,3569
|
59
|
+
maleo_foundation/utils/exceptions.py,sha256=LPPcU-6_3NbRIBZg2Nr2Ac5HF1qZJbHbMVnwfIfZg6g,3702
|
60
|
+
maleo_foundation/utils/extractor.py,sha256=SZXVYDHWGaA-Dd1BUydwF2HHdZqexEielS4CjL0Ceng,814
|
61
|
+
maleo_foundation/utils/keyloader.py,sha256=TOKgKLqvUV27MYkej9d_MQB9O8bOJ_WzaXlqHorkmpo,2581
|
81
62
|
maleo_foundation/utils/logging.py,sha256=MwvZmZSA8SIdfq-knEvpYIgqnSpHcyHrZY9TVHWVHJA,9023
|
82
63
|
maleo_foundation/utils/query.py,sha256=ODQ3adOYQNj5E2cRW9ytbjBz56nEDcnfq8mQ6YZbCCM,4375
|
83
64
|
maleo_foundation/utils/formatter/__init__.py,sha256=iKf5YCbEdg1qKnFHyKqqcQbqAqEeRUf8mhI3v3dQoj8,78
|
84
65
|
maleo_foundation/utils/formatter/case.py,sha256=TmvvlfzGdC_omMTB5vAa40TZBxQ3hnr-SYeo0M52Rlg,1352
|
85
|
-
maleo_foundation-0.1.
|
86
|
-
maleo_foundation-0.1.
|
87
|
-
maleo_foundation-0.1.
|
88
|
-
maleo_foundation-0.1.
|
66
|
+
maleo_foundation-0.1.37.dist-info/METADATA,sha256=G4M-2SvG4uuTt1hiIP7g0UnQmI4-SQUWbxb_OGm5tjc,3190
|
67
|
+
maleo_foundation-0.1.37.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
|
68
|
+
maleo_foundation-0.1.37.dist-info/top_level.txt,sha256=_iBos3F_bhEOdjOnzeiEYSrCucasc810xXtLBXI8cQc,17
|
69
|
+
maleo_foundation-0.1.37.dist-info/RECORD,,
|
@@ -1,50 +0,0 @@
|
|
1
|
-
import httpx
|
2
|
-
from contextlib import asynccontextmanager
|
3
|
-
from typing import AsyncGenerator, Optional
|
4
|
-
|
5
|
-
class HTTPClientManager:
|
6
|
-
client:Optional[httpx.AsyncClient] = None
|
7
|
-
base_url:Optional[str] = None
|
8
|
-
|
9
|
-
@classmethod
|
10
|
-
def initialize(cls) -> None:
|
11
|
-
"""Initialize the HTTP client if not already initialized."""
|
12
|
-
if cls.client is None:
|
13
|
-
cls.client = httpx.AsyncClient()
|
14
|
-
|
15
|
-
@classmethod
|
16
|
-
async def _client_handler(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
|
17
|
-
"""Reusable generator for client handling."""
|
18
|
-
if cls.client is None:
|
19
|
-
raise RuntimeError("Client has not been initialized. Call initialize first.")
|
20
|
-
|
21
|
-
yield cls.client
|
22
|
-
|
23
|
-
@classmethod
|
24
|
-
async def inject_client(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
|
25
|
-
return cls._client_handler()
|
26
|
-
|
27
|
-
@classmethod
|
28
|
-
@asynccontextmanager
|
29
|
-
async def get_client(cls) -> AsyncGenerator[httpx.AsyncClient, None]:
|
30
|
-
"""
|
31
|
-
Async context manager for manual HTTP client handling.
|
32
|
-
Supports `async with HTTPClientManager.get() as client:`
|
33
|
-
"""
|
34
|
-
async for client in cls._client_handler():
|
35
|
-
yield client
|
36
|
-
|
37
|
-
@classmethod
|
38
|
-
def get_url(cls) -> str:
|
39
|
-
if cls.base_url is None:
|
40
|
-
raise RuntimeError("Base URL has not been initialized. Call initialize first.")
|
41
|
-
return cls.base_url
|
42
|
-
|
43
|
-
@classmethod
|
44
|
-
async def dispose(cls) -> None:
|
45
|
-
"""Dispose of the HTTP client and release any resources."""
|
46
|
-
if cls.client is not None:
|
47
|
-
await cls.client.aclose()
|
48
|
-
cls.client = None
|
49
|
-
if cls.base_url is not None:
|
50
|
-
cls.base_url = None
|
@@ -1,32 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
from google.auth import default
|
3
|
-
from google.oauth2 import service_account
|
4
|
-
from maleo_foundation.types import BaseTypes
|
5
|
-
|
6
|
-
class GoogleClientManager:
|
7
|
-
def __init__(self, google_credentials_path:BaseTypes.OptionalString = None) -> None:
|
8
|
-
google_credentials_path = google_credentials_path or os.getenv("GOOGLE_CREDENTIALS_PATH")
|
9
|
-
try:
|
10
|
-
if google_credentials_path is not None:
|
11
|
-
self._credentials = service_account.Credentials.from_service_account_file(filename=google_credentials_path)
|
12
|
-
else:
|
13
|
-
self._credentials, _ = default()
|
14
|
-
except Exception as e:
|
15
|
-
raise ValueError(f"Failed to initialize credentials: {str(e)}")
|
16
|
-
|
17
|
-
@property
|
18
|
-
def credentials(self) -> service_account.Credentials:
|
19
|
-
return self._credentials
|
20
|
-
|
21
|
-
@property
|
22
|
-
def name(self) -> str:
|
23
|
-
raise NotImplementedError()
|
24
|
-
|
25
|
-
@property
|
26
|
-
def client(self):
|
27
|
-
raise NotImplementedError()
|
28
|
-
|
29
|
-
def dispose(self) -> None:
|
30
|
-
"""Dispose of the client and release any resources."""
|
31
|
-
if self._credentials is not None:
|
32
|
-
self._credentials = None
|
@@ -1,32 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
from google.auth import default
|
3
|
-
from google.oauth2 import service_account
|
4
|
-
from maleo_foundation.types import BaseTypes
|
5
|
-
|
6
|
-
class GoogleCloudClientManager:
|
7
|
-
def __init__(self, google_credentials_path:BaseTypes.OptionalString = None) -> None:
|
8
|
-
google_credentials_path = google_credentials_path or os.getenv("GOOGLE_CREDENTIALS_PATH")
|
9
|
-
try:
|
10
|
-
if google_credentials_path is not None:
|
11
|
-
self._credentials = service_account.Credentials.from_service_account_file(filename=google_credentials_path)
|
12
|
-
else:
|
13
|
-
self._credentials, _ = default()
|
14
|
-
except Exception as e:
|
15
|
-
raise ValueError(f"Failed to initialize credentials: {str(e)}")
|
16
|
-
|
17
|
-
@property
|
18
|
-
def credentials(self) -> service_account.Credentials:
|
19
|
-
return self._credentials
|
20
|
-
|
21
|
-
@property
|
22
|
-
def name(self) -> str:
|
23
|
-
raise NotImplementedError()
|
24
|
-
|
25
|
-
@property
|
26
|
-
def client(self):
|
27
|
-
raise NotImplementedError()
|
28
|
-
|
29
|
-
def dispose(self) -> None:
|
30
|
-
"""Dispose of the client and release any resources."""
|
31
|
-
if self._credentials is not None:
|
32
|
-
self._credentials = None
|
@@ -1,63 +0,0 @@
|
|
1
|
-
import os
|
2
|
-
from google.auth import default
|
3
|
-
from google.cloud.logging import Client
|
4
|
-
from google.cloud.logging.handlers import CloudLoggingHandler
|
5
|
-
from google.oauth2 import service_account
|
6
|
-
from typing import Optional
|
7
|
-
from .base import GoogleCloudClientManager
|
8
|
-
|
9
|
-
class GoogleCloudLogging:
|
10
|
-
_client:Optional[Client] = None
|
11
|
-
|
12
|
-
@classmethod
|
13
|
-
def initialize(cls) -> Client:
|
14
|
-
"""Initialize the cloud logging if not already initialized."""
|
15
|
-
if cls._client is None:
|
16
|
-
#* Setup credentials with fallback chain
|
17
|
-
credentials = None
|
18
|
-
credentials_file = os.getenv("GOOGLE_APPLICATION_CREDENTIALS")
|
19
|
-
try:
|
20
|
-
if credentials_file:
|
21
|
-
credentials = service_account.Credentials.from_service_account_file(credentials_file)
|
22
|
-
else:
|
23
|
-
credentials, _ = default()
|
24
|
-
except Exception as e:
|
25
|
-
raise ValueError(f"Failed to initialize credentials: {str(e)}")
|
26
|
-
|
27
|
-
cls._client = Client(credentials=credentials)
|
28
|
-
cls._client.setup_logging()
|
29
|
-
|
30
|
-
@classmethod
|
31
|
-
def dispose(cls) -> None:
|
32
|
-
"""Dispose of the cloud logging and release any resources."""
|
33
|
-
if cls._client is not None:
|
34
|
-
cls._client = None
|
35
|
-
|
36
|
-
@classmethod
|
37
|
-
def _get_client(cls) -> Client:
|
38
|
-
"""Retrieve the cloud logging client, initializing it if necessary."""
|
39
|
-
cls.initialize()
|
40
|
-
return cls._client
|
41
|
-
|
42
|
-
@classmethod
|
43
|
-
def create_handler(cls, name:str):
|
44
|
-
cls.initialize()
|
45
|
-
return CloudLoggingHandler(client=cls._client, name=name)
|
46
|
-
|
47
|
-
class GoogleCloudLoggingV2(GoogleCloudClientManager):
|
48
|
-
def __init__(self, google_credentials_path = None) -> None:
|
49
|
-
super().__init__(google_credentials_path)
|
50
|
-
self._client = Client(credentials=self._credentials)
|
51
|
-
self._client.setup_logging()
|
52
|
-
|
53
|
-
@property
|
54
|
-
def client(self) -> Client:
|
55
|
-
return self._client
|
56
|
-
|
57
|
-
def dispose(self) -> None:
|
58
|
-
if self._client is not None:
|
59
|
-
self._client = None
|
60
|
-
return super().dispose()
|
61
|
-
|
62
|
-
def create_handler(self, name:str) -> CloudLoggingHandler:
|
63
|
-
return CloudLoggingHandler(client=self._client, name=name)
|