maleo-foundation 0.1.35__tar.gz → 0.1.37__tar.gz

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.
Files changed (95) hide show
  1. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/PKG-INFO +1 -1
  2. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/db.py +4 -5
  3. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/service.py +3 -4
  4. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/middlewares/authentication.py +2 -2
  5. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/middlewares/base.py +2 -19
  6. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/__init__.py +4 -2
  7. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/exceptions.py +1 -13
  8. maleo_foundation-0.1.37/maleo_foundation/utils/extractor.py +20 -0
  9. maleo_foundation-0.1.37/maleo_foundation/utils/keyloader.py +67 -0
  10. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation.egg-info/PKG-INFO +1 -1
  11. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation.egg-info/SOURCES.txt +1 -20
  12. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/pyproject.toml +1 -1
  13. maleo_foundation-0.1.35/maleo_foundation/clients/__init__.py +0 -7
  14. maleo_foundation-0.1.35/maleo_foundation/clients/general/__init__.py +0 -4
  15. maleo_foundation-0.1.35/maleo_foundation/clients/general/http.py +0 -50
  16. maleo_foundation-0.1.35/maleo_foundation/clients/google/__init__.py +0 -4
  17. maleo_foundation-0.1.35/maleo_foundation/clients/google/base.py +0 -32
  18. maleo_foundation-0.1.35/maleo_foundation/clients/google/cloud/__init__.py +0 -8
  19. maleo_foundation-0.1.35/maleo_foundation/clients/google/cloud/base.py +0 -32
  20. maleo_foundation-0.1.35/maleo_foundation/clients/google/cloud/logging.py +0 -63
  21. maleo_foundation-0.1.35/maleo_foundation/clients/google/cloud/secret.py +0 -149
  22. maleo_foundation-0.1.35/maleo_foundation/clients/google/cloud/storage.py +0 -110
  23. maleo_foundation-0.1.35/maleo_foundation/clients/google/secret.py +0 -61
  24. maleo_foundation-0.1.35/maleo_foundation/clients/google/storage.py +0 -57
  25. maleo_foundation-0.1.35/maleo_foundation/clients/utils/__init__.py +0 -5
  26. maleo_foundation-0.1.35/maleo_foundation/clients/utils/logger.py +0 -54
  27. maleo_foundation-0.1.35/maleo_foundation/db/__init__.py +0 -4
  28. maleo_foundation-0.1.35/maleo_foundation/db/engine.py +0 -76
  29. maleo_foundation-0.1.35/maleo_foundation/db/manager.py +0 -122
  30. maleo_foundation-0.1.35/maleo_foundation/db/session.py +0 -111
  31. maleo_foundation-0.1.35/maleo_foundation/utils/extractor.py +0 -18
  32. maleo_foundation-0.1.35/maleo_foundation/utils/keyloader.py +0 -65
  33. maleo_foundation-0.1.35/maleo_foundation/utils/logger.py +0 -92
  34. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/README.md +0 -0
  35. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/__init__.py +0 -0
  36. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/authentication.py +0 -0
  37. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/constants.py +0 -0
  38. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/enums.py +0 -0
  39. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/expanded_types/__init__.py +0 -0
  40. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/expanded_types/client.py +0 -0
  41. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/expanded_types/general.py +0 -0
  42. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/expanded_types/query.py +0 -0
  43. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/expanded_types/service.py +0 -0
  44. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/expanded_types/token.py +0 -0
  45. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/extended_types.py +0 -0
  46. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/__init__.py +0 -0
  47. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/__init__.py +0 -0
  48. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/base.py +0 -0
  49. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/google/__init__.py +0 -0
  50. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/google/base.py +0 -0
  51. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/google/secret.py +0 -0
  52. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/google/storage.py +0 -0
  53. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/client/maleo.py +0 -0
  54. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/managers/middleware.py +0 -0
  55. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/middlewares/__init__.py +0 -0
  56. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/middlewares/cors.py +0 -0
  57. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/__init__.py +0 -0
  58. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/responses.py +0 -0
  59. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/schemas/__init__.py +0 -0
  60. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/schemas/general.py +0 -0
  61. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/schemas/parameter.py +0 -0
  62. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/schemas/result.py +0 -0
  63. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/schemas/token.py +0 -0
  64. {maleo_foundation-0.1.35/maleo_foundation/db → maleo_foundation-0.1.37/maleo_foundation/models}/table.py +0 -0
  65. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/__init__.py +0 -0
  66. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/general/__init__.py +0 -0
  67. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/general/token.py +0 -0
  68. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/parameters/__init__.py +0 -0
  69. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/parameters/client.py +0 -0
  70. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/parameters/general.py +0 -0
  71. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/parameters/service.py +0 -0
  72. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/parameters/token.py +0 -0
  73. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/__init__.py +0 -0
  74. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/client/__init__.py +0 -0
  75. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/client/controllers/__init__.py +0 -0
  76. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/client/controllers/http.py +0 -0
  77. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/client/service.py +0 -0
  78. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/service/__init__.py +0 -0
  79. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/service/controllers/__init__.py +0 -0
  80. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/service/controllers/rest.py +0 -0
  81. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/service/general.py +0 -0
  82. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/service/query.py +0 -0
  83. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/models/transfers/results/token.py +0 -0
  84. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/services/__init__.py +0 -0
  85. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/services/token.py +0 -0
  86. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/types.py +0 -0
  87. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/controller.py +0 -0
  88. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/formatter/__init__.py +0 -0
  89. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/formatter/case.py +0 -0
  90. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/logging.py +0 -0
  91. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation/utils/query.py +0 -0
  92. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation.egg-info/dependency_links.txt +0 -0
  93. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation.egg-info/requires.txt +0 -0
  94. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/maleo_foundation.egg-info/top_level.txt +0 -0
  95. {maleo_foundation-0.1.35 → maleo_foundation-0.1.37}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.1.35
3
+ Version: 0.1.37
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -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, Optional, Type
8
+ from typing import Generator
9
9
  from maleo_foundation.types import BaseTypes
10
- from maleo_foundation.utils.logger import BaseLogger
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:BaseLogger, engine:Engine):
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:BaseLogger,
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 load_key
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 = load_key(
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 = load_key(
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 extract_client_ip
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 extract_client_ip
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.logger import BaseLogger, LoggerFactory
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):
@@ -0,0 +1,20 @@
1
+ from starlette.requests import HTTPConnection
2
+
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]
13
+
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
18
+
19
+ #* Fall back to direct client connection
20
+ return conn.client.host if conn.client else "unknown"
@@ -0,0 +1,67 @@
1
+ import pathlib
2
+ from cryptography.hazmat.primitives import serialization
3
+ from typing import Optional, Union
4
+ from maleo_foundation.enums import BaseEnums
5
+
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.
16
+
17
+ Args:
18
+ path (str | pathlib.Path): Path to the PEM file.
19
+ password (str | bytes | None): Password for encrypted private keys (optional).
20
+
21
+ Returns:
22
+ rsa.RSAPrivateKey | rsa.RSAPublicKey
23
+ """
24
+ if not isinstance(type, BaseEnums.KeyType):
25
+ raise TypeError("Invalid key type")
26
+
27
+ file_path = pathlib.Path(path)
28
+
29
+ if not file_path.is_file():
30
+ raise FileNotFoundError(f"Key file not found: {file_path}")
31
+
32
+ if password is not None and not isinstance(password, (str, bytes)):
33
+ raise TypeError("Invalid passsword type")
34
+
35
+ if not isinstance(format, BaseEnums.KeyFormatType):
36
+ raise TypeError("Invalid key format type")
37
+
38
+ key_data = file_path.read_bytes()
39
+
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()
54
+
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()
65
+
66
+ else:
67
+ raise ValueError(f"Unsupported key type: {type}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maleo_foundation
3
- Version: 0.1.35
3
+ Version: 0.1.37
4
4
  Summary: Foundation package for Maleo
5
5
  Author-email: Agra Bima Yuda <agra@nexmedis.com>
6
6
  License: MIT
@@ -11,25 +11,6 @@ maleo_foundation.egg-info/SOURCES.txt
11
11
  maleo_foundation.egg-info/dependency_links.txt
12
12
  maleo_foundation.egg-info/requires.txt
13
13
  maleo_foundation.egg-info/top_level.txt
14
- maleo_foundation/clients/__init__.py
15
- maleo_foundation/clients/general/__init__.py
16
- maleo_foundation/clients/general/http.py
17
- maleo_foundation/clients/google/__init__.py
18
- maleo_foundation/clients/google/base.py
19
- maleo_foundation/clients/google/secret.py
20
- maleo_foundation/clients/google/storage.py
21
- maleo_foundation/clients/google/cloud/__init__.py
22
- maleo_foundation/clients/google/cloud/base.py
23
- maleo_foundation/clients/google/cloud/logging.py
24
- maleo_foundation/clients/google/cloud/secret.py
25
- maleo_foundation/clients/google/cloud/storage.py
26
- maleo_foundation/clients/utils/__init__.py
27
- maleo_foundation/clients/utils/logger.py
28
- maleo_foundation/db/__init__.py
29
- maleo_foundation/db/engine.py
30
- maleo_foundation/db/manager.py
31
- maleo_foundation/db/session.py
32
- maleo_foundation/db/table.py
33
14
  maleo_foundation/expanded_types/__init__.py
34
15
  maleo_foundation/expanded_types/client.py
35
16
  maleo_foundation/expanded_types/general.py
@@ -53,6 +34,7 @@ maleo_foundation/middlewares/base.py
53
34
  maleo_foundation/middlewares/cors.py
54
35
  maleo_foundation/models/__init__.py
55
36
  maleo_foundation/models/responses.py
37
+ maleo_foundation/models/table.py
56
38
  maleo_foundation/models/schemas/__init__.py
57
39
  maleo_foundation/models/schemas/general.py
58
40
  maleo_foundation/models/schemas/parameter.py
@@ -84,7 +66,6 @@ maleo_foundation/utils/controller.py
84
66
  maleo_foundation/utils/exceptions.py
85
67
  maleo_foundation/utils/extractor.py
86
68
  maleo_foundation/utils/keyloader.py
87
- maleo_foundation/utils/logger.py
88
69
  maleo_foundation/utils/logging.py
89
70
  maleo_foundation/utils/query.py
90
71
  maleo_foundation/utils/formatter/__init__.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "maleo_foundation"
7
- version = "0.1.35"
7
+ version = "0.1.37"
8
8
  description = "Foundation package for Maleo"
9
9
  authors = [
10
10
  { name = "Agra Bima Yuda", email = "agra@nexmedis.com" }
@@ -1,7 +0,0 @@
1
- from __future__ import annotations
2
- from .general import BaseGeneralClients
3
- from .google import GoogleClients
4
-
5
- class BaseClients:
6
- General = BaseGeneralClients
7
- Google = GoogleClients
@@ -1,4 +0,0 @@
1
- from .http import HTTPClientManager
2
-
3
- class BaseGeneralClients:
4
- HTTP = HTTPClientManager
@@ -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,4 +0,0 @@
1
- from .cloud import GoogleCloudClients
2
-
3
- class GoogleClients:
4
- Cloud = GoogleCloudClients
@@ -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,8 +0,0 @@
1
- from .logging import GoogleCloudLogging
2
- from .secret import GoogleSecretManager
3
- from .storage import GoogleCloudStorage
4
-
5
- class GoogleCloudClients:
6
- Logging = GoogleCloudLogging
7
- Secret = GoogleSecretManager
8
- Storage = GoogleCloudStorage
@@ -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)