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.
Files changed (32) hide show
  1. maleo_foundation/managers/db.py +4 -5
  2. maleo_foundation/managers/service.py +3 -4
  3. maleo_foundation/middlewares/authentication.py +2 -2
  4. maleo_foundation/middlewares/base.py +2 -19
  5. maleo_foundation/utils/__init__.py +4 -2
  6. maleo_foundation/utils/exceptions.py +1 -13
  7. maleo_foundation/utils/extractor.py +16 -14
  8. maleo_foundation/utils/keyloader.py +52 -50
  9. {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/METADATA +1 -1
  10. {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/RECORD +13 -32
  11. maleo_foundation/clients/__init__.py +0 -7
  12. maleo_foundation/clients/general/__init__.py +0 -4
  13. maleo_foundation/clients/general/http.py +0 -50
  14. maleo_foundation/clients/google/__init__.py +0 -4
  15. maleo_foundation/clients/google/base.py +0 -32
  16. maleo_foundation/clients/google/cloud/__init__.py +0 -8
  17. maleo_foundation/clients/google/cloud/base.py +0 -32
  18. maleo_foundation/clients/google/cloud/logging.py +0 -63
  19. maleo_foundation/clients/google/cloud/secret.py +0 -149
  20. maleo_foundation/clients/google/cloud/storage.py +0 -110
  21. maleo_foundation/clients/google/secret.py +0 -61
  22. maleo_foundation/clients/google/storage.py +0 -57
  23. maleo_foundation/clients/utils/__init__.py +0 -5
  24. maleo_foundation/clients/utils/logger.py +0 -54
  25. maleo_foundation/db/__init__.py +0 -4
  26. maleo_foundation/db/engine.py +0 -76
  27. maleo_foundation/db/manager.py +0 -122
  28. maleo_foundation/db/session.py +0 -111
  29. maleo_foundation/utils/logger.py +0 -92
  30. /maleo_foundation/{db → models}/table.py +0 -0
  31. {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/WHEEL +0 -0
  32. {maleo_foundation-0.1.35.dist-info → maleo_foundation-0.1.37.dist-info}/top_level.txt +0 -0
@@ -1,149 +0,0 @@
1
- import os
2
- from google.api_core import retry
3
- from google.api_core.exceptions import NotFound
4
- from google.auth import default
5
- from google.cloud import secretmanager
6
- from google.oauth2 import service_account
7
- from typing import Optional
8
- from .base import GoogleCloudClientManager
9
-
10
- class GoogleSecretManager:
11
- _project:Optional[str] = None
12
- _client:Optional[secretmanager.SecretManagerServiceClient] = None
13
-
14
- @classmethod
15
- def initialize(cls, project_id:Optional[str] = None) -> None:
16
- """Initialize the cloud storage if not already initialized."""
17
- cls._project = project_id or os.getenv("GCP_PROJECT_ID")
18
- if cls._project is None:
19
- raise ValueError("GCP_PROJECT_ID environment variable must be set if no project_id is provided")
20
- if cls._client is None:
21
- #* Setup credentials with fallback chain
22
- credentials = None
23
- credentials_file = os.getenv("GOOGLE_CREDENTIALS_PATH")
24
- try:
25
- if credentials_file:
26
- credentials = service_account.Credentials.from_service_account_file(credentials_file)
27
- else:
28
- credentials, _ = default()
29
- except Exception as e:
30
- raise ValueError(f"Failed to initialize credentials: {str(e)}")
31
-
32
- cls._client = secretmanager.SecretManagerServiceClient(credentials=credentials)
33
-
34
- @classmethod
35
- def dispose(cls):
36
- """Disposes of the Google Secret Manager client"""
37
- if cls._client is not None:
38
- cls._client = None
39
- if cls._project is not None:
40
- cls._project = None
41
-
42
- @classmethod
43
- @retry.Retry(
44
- predicate=retry.if_exception_type(Exception),
45
- timeout=5
46
- )
47
- def get(
48
- cls,
49
- name:str,
50
- version:str = "latest",
51
- ) -> Optional[str]:
52
- try:
53
- secret_path = f"projects/{cls._project}/secrets/{name}/versions/{version}"
54
- request = secretmanager.AccessSecretVersionRequest(name=secret_path)
55
- response = cls._client.access_secret_version(request=request)
56
- return response.payload.data.decode()
57
- except Exception as e:
58
- return None
59
-
60
- @classmethod
61
- @retry.Retry(
62
- predicate=retry.if_exception_type(Exception),
63
- timeout=5
64
- )
65
- def create(
66
- cls,
67
- name:str,
68
- data:str
69
- ) -> Optional[str]:
70
- parent = f"projects/{cls._project}"
71
- secret_path = f"{parent}/secrets/{name}"
72
- try:
73
- #* Check if the secret already exists
74
- request = secretmanager.GetSecretRequest(name=secret_path)
75
- cls._client.get_secret(request=request)
76
-
77
- except NotFound:
78
- #* Secret does not exist, create it first
79
- try:
80
- secret = secretmanager.Secret(name=name, replication={"automatic": {}})
81
- request = secretmanager.CreateSecretRequest(parent=parent, secret_id=name, secret=secret)
82
- cls._client.create_secret(request=request)
83
- except Exception as e:
84
- return None
85
-
86
- #* Add a new secret version
87
- try:
88
- payload = secretmanager.SecretPayload(data=data.encode()) # ✅ Fixed attribute name
89
- request = secretmanager.AddSecretVersionRequest(parent=secret_path, payload=payload)
90
- response = cls._client.add_secret_version(request=request)
91
- return data
92
- except Exception as e:
93
- return None
94
-
95
- class GoogleSecretManagerV2(GoogleCloudClientManager):
96
- def __init__(self, google_credentials_path = None) -> None:
97
- super().__init__(google_credentials_path)
98
- self._project_id = self.credentials.project_id
99
- self._client = secretmanager.SecretManagerServiceClient(credentials=self.credentials)
100
-
101
- @property
102
- def project_id(self):
103
- return self._project_id
104
-
105
- @property
106
- def client(self) -> secretmanager.SecretManagerServiceClient:
107
- return self._client
108
-
109
- def dispose(self):
110
- if self._client is not None:
111
- self._client = None
112
- return super().dispose()
113
-
114
- @retry.Retry(predicate=retry.if_exception_type(Exception), timeout=5)
115
- def get(self, name:str, version:str = "latest") -> Optional[str]:
116
- try:
117
- secret_path = f"projects/{self._project_id}/secrets/{name}/versions/{version}"
118
- request = secretmanager.AccessSecretVersionRequest(name=secret_path)
119
- response = self._client.access_secret_version(request=request)
120
- return response.payload.data.decode()
121
- except Exception as e:
122
- return None
123
-
124
- @retry.Retry(predicate=retry.if_exception_type(Exception), timeout=5)
125
- def create(self, name:str, data:str) -> Optional[str]:
126
- parent = f"projects/{self._project_id}"
127
- secret_path = f"{parent}/secrets/{name}"
128
- try:
129
- #* Check if the secret already exists
130
- request = secretmanager.GetSecretRequest(name=secret_path)
131
- self._client.get_secret(request=request)
132
-
133
- except NotFound:
134
- #* Secret does not exist, create it first
135
- try:
136
- secret = secretmanager.Secret(name=name, replication={"automatic": {}})
137
- request = secretmanager.CreateSecretRequest(parent=parent, secret_id=name, secret=secret)
138
- self._client.create_secret(request=request)
139
- except Exception as e:
140
- return None
141
-
142
- #* Add a new secret version
143
- try:
144
- payload = secretmanager.SecretPayload(data=data.encode()) # ✅ Fixed attribute name
145
- request = secretmanager.AddSecretVersionRequest(parent=secret_path, payload=payload)
146
- response = self._client.add_secret_version(request=request)
147
- return data
148
- except Exception as e:
149
- return None
@@ -1,110 +0,0 @@
1
- import os
2
- from datetime import timedelta
3
- from google.auth import default
4
- from google.cloud.storage import Bucket, Client
5
- from google.oauth2 import service_account
6
- from typing import Optional
7
- from maleo_foundation.types import BaseTypes
8
- from .base import GoogleCloudClientManager
9
-
10
- class GoogleCloudStorage:
11
- _client:Optional[Client] = None
12
- _bucket:Optional[Bucket] = None
13
-
14
- @classmethod
15
- def initialize(cls) -> None:
16
- """Initialize the cloud storage if not already initialized."""
17
- if cls._client is None:
18
- #* Setup credentials with fallback chain
19
- credentials = None
20
- credentials_file = os.getenv("GOOGLE_CREDENTIALS_PATH")
21
- try:
22
- if credentials_file:
23
- credentials = service_account.Credentials.from_service_account_file(credentials_file)
24
- else:
25
- credentials, _ = default()
26
- except Exception as e:
27
- raise ValueError(f"Failed to initialize credentials: {str(e)}")
28
-
29
- cls._client = Client(credentials=credentials)
30
-
31
- #* Preload bucket
32
- bucket_name = os.getenv("GCS_BUCKET_NAME")
33
- if not bucket_name:
34
- cls._client.close()
35
- raise ValueError("GCS_BUCKET_NAME environment variable must be set")
36
-
37
- #* Validate bucket existence
38
- bucket = cls._client.lookup_bucket(bucket_name)
39
- if bucket is None:
40
- raise ValueError(f"Bucket '{bucket_name}' does not exist.")
41
-
42
- cls._bucket = bucket
43
-
44
- @classmethod
45
- def dispose(cls) -> None:
46
- """Dispose of the cloud storage and release any resources."""
47
- if cls._client is not None:
48
- cls._client.close()
49
- cls._client = None
50
- cls._bucket = None
51
-
52
- @classmethod
53
- def _get_client(cls) -> Client:
54
- """Retrieve the cloud storage client, initializing it if necessary."""
55
- cls.initialize()
56
- return cls._client
57
-
58
- @classmethod
59
- def generate_signed_url(cls, location:str) -> str:
60
- """
61
- generate signed URL of a file in the bucket based on its location.
62
-
63
- Args:
64
- location: str
65
- Location of the file inside the bucket
66
-
67
- Returns:
68
- str: File's pre-signed download url
69
-
70
- Raises:
71
- ValueError: If the file does not exist
72
- """
73
- cls.initialize()
74
- blob = cls._bucket.blob(blob_name=location)
75
- if not blob.exists():
76
- raise ValueError(f"File '{location}' did not exists.")
77
-
78
- url = blob.generate_signed_url(version="v4", expiration=timedelta(minutes=15), method="GET")
79
- return url
80
-
81
- class GoogleCloudStorageV2(GoogleCloudClientManager):
82
- def __init__(self, google_credentials_path = None, bucket_name:BaseTypes.OptionalString = None) -> None:
83
- super().__init__(google_credentials_path)
84
- self._client = Client(credentials=self._credentials)
85
- self._bucket_name = bucket_name or os.getenv("GCS_BUCKET_NAME")
86
- if self._bucket_name is None:
87
- self._client.close()
88
- raise ValueError("GCS_BUCKET_NAME environment variable must be set if 'bucket_name' is set to None")
89
- self._bucket = self._client.lookup_bucket(bucket_name=self._bucket_name)
90
- if self._bucket is None:
91
- raise ValueError(f"Bucket '{self._bucket_name}' does not exist.")
92
-
93
- @property
94
- def client(self) -> Client:
95
- return self._client
96
-
97
- @property
98
- def bucket_name(self) -> str:
99
- return self._bucket_name
100
-
101
- @property
102
- def bucket(self) -> Bucket:
103
- return self._bucket
104
-
105
- def dispose(self):
106
- if self._bucket is not None:
107
- self._bucket = None
108
- if self._client is not None:
109
- self._client = None
110
- return super().dispose()
@@ -1,61 +0,0 @@
1
- from google.api_core import retry
2
- from google.api_core.exceptions import NotFound
3
- from google.cloud import secretmanager
4
- from typing import Optional
5
- from .base import GoogleClientManager
6
-
7
- class GoogleSecretManager(GoogleClientManager):
8
- def __init__(self, google_credentials_path = None) -> None:
9
- super().__init__(google_credentials_path)
10
- self._project_id = self.credentials.project_id
11
- self._client = secretmanager.SecretManagerServiceClient(credentials=self.credentials)
12
-
13
- @property
14
- def project_id(self):
15
- return self._project_id
16
-
17
- @property
18
- def client(self) -> secretmanager.SecretManagerServiceClient:
19
- return self._client
20
-
21
- def dispose(self):
22
- if self._client is not None:
23
- self._client = None
24
- return super().dispose()
25
-
26
- @retry.Retry(predicate=retry.if_exception_type(Exception), timeout=5)
27
- def get(self, name:str, version:str = "latest") -> Optional[str]:
28
- try:
29
- secret_path = f"projects/{self._project_id}/secrets/{name}/versions/{version}"
30
- request = secretmanager.AccessSecretVersionRequest(name=secret_path)
31
- response = self._client.access_secret_version(request=request)
32
- return response.payload.data.decode()
33
- except Exception as e:
34
- return None
35
-
36
- @retry.Retry(predicate=retry.if_exception_type(Exception), timeout=5)
37
- def create(self, name:str, data:str) -> Optional[str]:
38
- parent = f"projects/{self._project_id}"
39
- secret_path = f"{parent}/secrets/{name}"
40
- try:
41
- #* Check if the secret already exists
42
- request = secretmanager.GetSecretRequest(name=secret_path)
43
- self._client.get_secret(request=request)
44
-
45
- except NotFound:
46
- #* Secret does not exist, create it first
47
- try:
48
- secret = secretmanager.Secret(name=name, replication={"automatic": {}})
49
- request = secretmanager.CreateSecretRequest(parent=parent, secret_id=name, secret=secret)
50
- self._client.create_secret(request=request)
51
- except Exception as e:
52
- return None
53
-
54
- #* Add a new secret version
55
- try:
56
- payload = secretmanager.SecretPayload(data=data.encode())
57
- request = secretmanager.AddSecretVersionRequest(parent=secret_path, payload=payload)
58
- response = self._client.add_secret_version(request=request)
59
- return data
60
- except Exception as e:
61
- return None
@@ -1,57 +0,0 @@
1
- import os
2
- from datetime import timedelta
3
- from google.cloud.storage import Bucket, Client
4
- from maleo_foundation.types import BaseTypes
5
- from .base import GoogleClientManager
6
-
7
- class GoogleCloudStorage(GoogleClientManager):
8
- def __init__(self, google_credentials_path = None, bucket_name:BaseTypes.OptionalString = None) -> None:
9
- super().__init__(google_credentials_path)
10
- self._client = Client(credentials=self._credentials)
11
- self._bucket_name = bucket_name or os.getenv("GCS_BUCKET_NAME")
12
- if self._bucket_name is None:
13
- self._client.close()
14
- raise ValueError("GCS_BUCKET_NAME environment variable must be set if 'bucket_name' is set to None")
15
- self._bucket = self._client.lookup_bucket(bucket_name=self._bucket_name)
16
- if self._bucket is None:
17
- raise ValueError(f"Bucket '{self._bucket_name}' does not exist.")
18
-
19
- @property
20
- def client(self) -> Client:
21
- return self._client
22
-
23
- @property
24
- def bucket_name(self) -> str:
25
- return self._bucket_name
26
-
27
- @property
28
- def bucket(self) -> Bucket:
29
- return self._bucket
30
-
31
- def dispose(self):
32
- if self._bucket is not None:
33
- self._bucket = None
34
- if self._client is not None:
35
- self._client = None
36
- return super().dispose()
37
-
38
- def generate_signed_url(self, location:str) -> str:
39
- """
40
- generate signed URL of a file in the bucket based on its location.
41
-
42
- Args:
43
- location: str
44
- Location of the file inside the bucket
45
-
46
- Returns:
47
- str: File's pre-signed download url
48
-
49
- Raises:
50
- ValueError: If the file does not exist
51
- """
52
- blob = self._bucket.blob(blob_name=location)
53
- if not blob.exists():
54
- raise ValueError(f"File '{location}' did not exists.")
55
-
56
- url = blob.generate_signed_url(version="v4", expiration=timedelta(minutes=15), method="GET")
57
- return url
@@ -1,5 +0,0 @@
1
- from __future__ import annotations
2
- from .logger import ClientLoggerManager
3
-
4
- class BaseClientUtils:
5
- Logger = ClientLoggerManager
@@ -1,54 +0,0 @@
1
- from typing import Dict
2
- from maleo_foundation.enums import BaseEnums
3
- from maleo_foundation.types import BaseTypes
4
- from maleo_foundation.utils.logger import BaseLogger
5
-
6
- class ClientLoggerManager:
7
- _loggers:Dict[type, BaseLogger] = {}
8
-
9
- @classmethod
10
- def initialize(
11
- cls,
12
- base_dir:str,
13
- client_name:str,
14
- service_name:BaseTypes.OptionalString = None,
15
- level:BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO
16
- ) -> BaseLogger:
17
- """Initialize client logger if not already initialized."""
18
- if cls not in cls._loggers:
19
- cls._loggers[cls] = BaseLogger(
20
- base_dir=base_dir,
21
- type=BaseEnums.LoggerType.CLIENT,
22
- service_name=service_name,
23
- client_name=client_name,
24
- level=level
25
- )
26
- return cls._loggers[cls]
27
-
28
- @classmethod
29
- def get(cls) -> BaseLogger:
30
- """Return client logger (if exist) or raise Runtime Error"""
31
- if cls not in cls._loggers:
32
- raise RuntimeError("Logger has not been initialized. Call 'initialize' first.")
33
- return cls._loggers[cls]
34
-
35
- class MaleoFoundationLoggerManager(ClientLoggerManager):
36
- @classmethod
37
- def initialize(
38
- cls,
39
- base_dir:str,
40
- service_name:BaseTypes.OptionalString = None,
41
- level:BaseEnums.LoggerLevel = BaseEnums.LoggerLevel.INFO
42
- ) -> BaseLogger:
43
- """Initialize MaleoFoundation's client logger if not already initialized."""
44
- return super().initialize(
45
- base_dir=base_dir,
46
- client_name="MaleoFoundation",
47
- service_name=service_name,
48
- level=level
49
- )
50
-
51
- @classmethod
52
- def get(cls) -> BaseLogger:
53
- """Return client logger (if exist) or raise Runtime Error"""
54
- return super().get()
@@ -1,4 +0,0 @@
1
- from .table import BaseTable
2
- from .engine import EngineManager
3
- from .session import SessionManager
4
- from .manager import DatabaseManager
@@ -1,76 +0,0 @@
1
- import os
2
- from sqlalchemy import create_engine, Engine
3
- from typing import Optional
4
- from maleo_foundation.types import BaseTypes
5
- from maleo_foundation.utils.logger import BaseLogger
6
-
7
- class EngineManager:
8
- _logger:Optional[BaseLogger] = None
9
- _engine:Optional[Engine] = None
10
-
11
- @classmethod
12
- def initialize(cls, logger:BaseLogger, url:Optional[str] = None) -> Engine:
13
- """Initialize the engine if not already initialized."""
14
- if cls._engine is None:
15
- cls._logger = logger
16
- url = url or os.getenv("DB_CONNECTION_STRING")
17
- if url is None:
18
- raise ValueError("DB_CONNECTION_STRING environment variable must be set if url is not provided")
19
- cls._engine = create_engine(url=url, echo=False, pool_pre_ping=True, pool_recycle=3600)
20
- cls._logger.info("EngineManager initialized successfully.")
21
- return cls._engine
22
-
23
- @classmethod
24
- def get(cls) -> Engine:
25
- """Retrieve the engine, initializing it if necessary."""
26
- if cls._logger is None:
27
- raise RuntimeError("Logger has not been initialized. Call initialize(db_connection_string, logger) first.")
28
- if cls._engine is None:
29
- raise RuntimeError("Engine has not been initialized. Call initialize(db_connection_string, logger) first.")
30
-
31
- return cls._engine
32
-
33
- @classmethod
34
- def dispose(cls) -> None:
35
- """Dispose of the engine and release any resources."""
36
- if cls._engine is not None:
37
- cls._engine.dispose()
38
- cls._engine = None
39
-
40
- cls._logger.info("Engine disposed successfully.")
41
- cls._logger = None
42
-
43
- class EngineManagerV2:
44
- _logger:Optional[BaseLogger] = None
45
- _engine:Optional[Engine] = None
46
-
47
- def __init__(self, logger:BaseLogger, url:BaseTypes.OptionalString = None):
48
- """Initialize the engine manager."""
49
- self._logger = logger
50
- url = url or os.getenv("DB_CONNECTION_STRING")
51
- if url is None:
52
- raise ValueError("DB_CONNECTION_STRING environment variable must be set if url is not provided")
53
- self._engine = create_engine(url=url, echo=False, pool_pre_ping=True, pool_recycle=3600)
54
-
55
- @property
56
- def logger(self) -> BaseLogger:
57
- """Retrieve the logger."""
58
- if self._logger is None:
59
- raise RuntimeError("Logger has not been initialized. Call initialize(db_connection_string, logger) first.")
60
- return self._logger
61
-
62
- @property
63
- def engine(self) -> Engine:
64
- """Retrieve the engine."""
65
- if self._engine is None:
66
- raise RuntimeError("Engine has not been initialized. Call initialize(db_connection_string, logger) first.")
67
- return self._engine
68
-
69
- def dispose(self) -> None:
70
- """Dispose of the engine and release any resources."""
71
- if self._engine is not None:
72
- self._engine.dispose()
73
- self._engine = None
74
-
75
- self._logger.info("Engine disposed successfully.")
76
- self._logger = None
@@ -1,122 +0,0 @@
1
- import os
2
- from contextlib import contextmanager
3
- from sqlalchemy import MetaData
4
- from sqlalchemy.engine import Engine, create_engine
5
- from sqlalchemy.exc import SQLAlchemyError
6
- from sqlalchemy.ext.declarative import DeclarativeMeta
7
- from sqlalchemy.orm import sessionmaker, Session, declarative_base
8
- from typing import Generator, Optional, Type
9
- from maleo_foundation.types import BaseTypes
10
- from maleo_foundation.utils.logger import BaseLogger
11
- from .table import BaseTable
12
-
13
- class DatabaseManager:
14
- Base:DeclarativeMeta = declarative_base() #* Correct way to define a declarative base
15
-
16
- #* Explicitly define the type of metadata
17
- metadata:MetaData = Base.metadata
18
-
19
- @classmethod
20
- def initialize(cls, engine:Engine):
21
- """Creates the database tables if they do not exist."""
22
- cls.metadata.create_all(engine)
23
-
24
- class MetadataManager:
25
- _Base:DeclarativeMeta = declarative_base()
26
-
27
- @property
28
- def Base(self) -> DeclarativeMeta:
29
- return self._Base
30
-
31
- @property
32
- def metadata(self) -> MetaData:
33
- return self._Base.metadata
34
-
35
- class SessionManager:
36
- def __init__(self, logger:BaseLogger, engine:Engine):
37
- self._logger = logger
38
- self._sessionmaker:sessionmaker[Session] = sessionmaker(bind=engine, expire_on_commit=False)
39
- self._logger.info("SessionManager initialized successfully.")
40
-
41
- def _session_handler(self) -> Generator[Session, None, None]:
42
- """Reusable function for managing database sessions."""
43
- if self._logger is None:
44
- raise RuntimeError("Logger has not been initialized. Call initialize() first.")
45
- if self._sessionmaker is None:
46
- raise RuntimeError("SessionLocal has not been initialized. Call initialize() first.")
47
-
48
- session = self._sessionmaker()
49
- self._logger.debug("New database session created.")
50
- try:
51
- yield session #* Provide session
52
- session.commit() #* Auto-commit on success
53
- except SQLAlchemyError as e:
54
- session.rollback() #* Rollback on error
55
- self._logger.error(f"[SQLAlchemyError] Database transaction failed: {e}", exc_info=True)
56
- raise
57
- except Exception as e:
58
- session.rollback() #* Rollback on error
59
- self._logger.error(f"[Exception] Database transaction failed: {e}", exc_info=True)
60
- raise
61
- finally:
62
- session.close() #* Ensure session closes
63
- self._logger.debug("Database session closed.")
64
-
65
- def inject(self) -> Generator[Session, None, None]:
66
- """Returns a generator that yields a SQLAlchemy session for dependency injection."""
67
- return self._session_handler()
68
-
69
- @contextmanager
70
- def get(self) -> Generator[Session, None, None]:
71
- """Context manager for manual session handling. Supports `with SessionManager.get() as session:`"""
72
- yield from self._session_handler()
73
-
74
- def dispose(self) -> None:
75
- """Dispose of the sessionmaker and release any resources."""
76
- if self._sessionmaker is not None:
77
- self._sessionmaker.close_all()
78
- self._sessionmaker = None
79
-
80
- self._logger.info("SessionManager disposed successfully.")
81
- self._logger = None
82
-
83
- class DatabaseManagerV2:
84
- # _metadata:Optional[MetaData] = None
85
- # _logger:Optional[BaseLogger] = None
86
- # _engine:Optional[Engine] = None
87
- # _session:Optional[SessionManager] = None
88
-
89
- def __init__(
90
- self,
91
- metadata:MetaData,
92
- logger:BaseLogger,
93
- url:BaseTypes.OptionalString = None
94
- ):
95
- self._metadata = metadata #* Define database metadata
96
- self._logger = logger #* Define database logger
97
-
98
- #* Create engine
99
- url = url or os.getenv("DB_URL")
100
- if url is None:
101
- raise ValueError("DB_URL environment variable must be set if url is not provided")
102
- self._engine = create_engine(url=url, echo=False, pool_pre_ping=True, pool_recycle=3600)
103
-
104
- self._metadata.create_all(bind=self._engine) #* Create all tables
105
- self._session = SessionManager(logger=self._logger, engine=self._engine) #* Define session
106
-
107
- def dispose(self) -> None:
108
- #* Dispose session
109
- if self._session is not None:
110
- self._session.dispose()
111
- self._session = None
112
- #* Dispose engine
113
- if self._engine is not None:
114
- self._engine.dispose()
115
- self._engine = None
116
- #* Dispose logger
117
- if self._logger is not None:
118
- self._logger.dispose()
119
- self._logger = None
120
- #* Dispose metadata
121
- if self._metadata is not None:
122
- self._metadata = None