python3-commons 0.7.6__py3-none-any.whl → 0.8.0__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.
- python3_commons/conf.py +9 -1
- python3_commons/db/__init__.py +52 -40
- {python3_commons-0.7.6.dist-info → python3_commons-0.8.0.dist-info}/METADATA +3 -2
- {python3_commons-0.7.6.dist-info → python3_commons-0.8.0.dist-info}/RECORD +8 -8
- {python3_commons-0.7.6.dist-info → python3_commons-0.8.0.dist-info}/WHEEL +1 -1
- {python3_commons-0.7.6.dist-info → python3_commons-0.8.0.dist-info/licenses}/AUTHORS.rst +0 -0
- {python3_commons-0.7.6.dist-info → python3_commons-0.8.0.dist-info/licenses}/LICENSE +0 -0
- {python3_commons-0.7.6.dist-info → python3_commons-0.8.0.dist-info}/top_level.txt +0 -0
python3_commons/conf.py
CHANGED
@@ -9,7 +9,15 @@ class CommonSettings(BaseSettings):
|
|
9
9
|
|
10
10
|
|
11
11
|
class DBSettings(BaseSettings):
|
12
|
-
|
12
|
+
dsn: PostgresDsn | None = None
|
13
|
+
echo: bool = False,
|
14
|
+
pool_size: int = 20,
|
15
|
+
max_overflow: int = 0,
|
16
|
+
pool_timeout: int = 30,
|
17
|
+
pool_recycle: int = 1800, # 30 minutes
|
18
|
+
|
19
|
+
class Config:
|
20
|
+
env_prefix = 'DB_'
|
13
21
|
|
14
22
|
|
15
23
|
class S3Settings(BaseSettings):
|
python3_commons/db/__init__.py
CHANGED
@@ -1,60 +1,72 @@
|
|
1
|
-
import asyncio
|
2
1
|
import contextlib
|
3
2
|
import logging
|
4
|
-
from typing import AsyncGenerator
|
3
|
+
from typing import AsyncGenerator, Callable, Mapping
|
5
4
|
|
6
|
-
from asyncpg import CannotConnectNowError
|
7
|
-
from pydantic import PostgresDsn
|
8
5
|
from sqlalchemy import MetaData
|
9
|
-
from sqlalchemy.ext.asyncio import
|
6
|
+
from sqlalchemy.ext.asyncio import AsyncSession, AsyncEngine, async_engine_from_config
|
10
7
|
from sqlalchemy.ext.asyncio.session import async_sessionmaker
|
11
8
|
from sqlalchemy.orm import declarative_base
|
12
9
|
|
13
|
-
from python3_commons.conf import
|
10
|
+
from python3_commons.conf import DBSettings
|
14
11
|
|
15
12
|
logger = logging.getLogger(__name__)
|
16
|
-
|
17
13
|
metadata = MetaData()
|
18
14
|
Base = declarative_base(metadata=metadata)
|
19
|
-
engine = create_async_engine(
|
20
|
-
str(db_settings.db_dsn),
|
21
|
-
# echo=True,
|
22
|
-
pool_size=20,
|
23
|
-
max_overflow=0,
|
24
|
-
pool_timeout=30,
|
25
|
-
pool_recycle=1800, # 30 minutes
|
26
|
-
)
|
27
|
-
async_session_maker = async_sessionmaker(engine, expire_on_commit=False)
|
28
15
|
|
29
16
|
|
30
|
-
|
31
|
-
|
32
|
-
|
17
|
+
class AsyncSessionManager:
|
18
|
+
def __init__(self, config: Mapping[str: DBSettings]):
|
19
|
+
self.config: Mapping[str: DBSettings] = config
|
20
|
+
self.engines: dict[str, AsyncEngine] = {}
|
21
|
+
self.session_makers: dict = {}
|
22
|
+
|
23
|
+
def get_config(self, name: str) -> Mapping[str, str | int]:
|
24
|
+
try:
|
25
|
+
return self.config[name]
|
26
|
+
except KeyError:
|
27
|
+
logger.error(f'Missing database config: {name}')
|
33
28
|
|
29
|
+
raise
|
34
30
|
|
35
|
-
|
31
|
+
def get_engine(self, name: str) -> AsyncEngine:
|
32
|
+
try:
|
33
|
+
engine = self.engines[name]
|
34
|
+
except KeyError:
|
35
|
+
logger.debug(f'Creating engine: {name}')
|
36
|
+
engine = async_engine_from_config(self.config[name])
|
37
|
+
self.engines[name] = engine
|
36
38
|
|
39
|
+
return engine
|
37
40
|
|
38
|
-
|
39
|
-
|
41
|
+
def get_session_maker(self, name: str):
|
42
|
+
try:
|
43
|
+
session_maker = self.session_makers[name]
|
44
|
+
except KeyError:
|
45
|
+
logger.debug(f'Creating session maker: {name}')
|
46
|
+
engine = self.get_engine(name)
|
47
|
+
session_maker = async_sessionmaker(engine)
|
48
|
+
self.session_makers[name] = session_maker
|
40
49
|
|
50
|
+
return session_maker
|
41
51
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
total_timeout = 0
|
52
|
+
def get_async_session(self, name: str) -> Callable[[], AsyncGenerator[AsyncSession, None]]:
|
53
|
+
async def get_session() -> AsyncGenerator[AsyncSession, None]:
|
54
|
+
async with self.get_session_maker(name) as session:
|
55
|
+
yield session
|
47
56
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
57
|
+
return get_session
|
58
|
+
|
59
|
+
def get_session_context(self, name: str):
|
60
|
+
return contextlib.asynccontextmanager(lambda: self.get_async_session(name)())
|
61
|
+
|
62
|
+
|
63
|
+
async def is_healthy(engine: AsyncEngine) -> bool:
|
64
|
+
try:
|
65
|
+
async with engine.begin() as conn:
|
66
|
+
result = await conn.execute('SELECT 1;')
|
67
|
+
|
68
|
+
return result.scalar() == 1
|
69
|
+
except Exception as e:
|
70
|
+
logger.error(f'Database connection is not healthy: {e}')
|
71
|
+
|
72
|
+
return False
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: python3-commons
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.8.0
|
4
4
|
Summary: Re-usable Python3 code
|
5
5
|
Author-email: Oleg Korsak <kamikaze.is.waiting.you@gmail.com>
|
6
6
|
License: gpl-3
|
@@ -27,6 +27,7 @@ Requires-Dist: zeep~=4.3.1
|
|
27
27
|
Provides-Extra: testing
|
28
28
|
Requires-Dist: pytest; extra == "testing"
|
29
29
|
Requires-Dist: pytest-cov; extra == "testing"
|
30
|
+
Dynamic: license-file
|
30
31
|
|
31
32
|
Re-usable Python3 code
|
32
33
|
======================
|
@@ -1,12 +1,12 @@
|
|
1
1
|
python3_commons/__init__.py,sha256=0KgaYU46H_IMKn-BuasoRN3C4Hi45KlkHHoPbU9cwiA,189
|
2
2
|
python3_commons/api_client.py,sha256=zj6zTF-DhUMu4bjj9VWLi63mVODG_SB47Q5qlmG-Sxg,4539
|
3
3
|
python3_commons/audit.py,sha256=DMQ-nrWSs0qilD7wkz_8PV4jXcee75O8FgAm2YIuOiY,6256
|
4
|
-
python3_commons/conf.py,sha256=
|
4
|
+
python3_commons/conf.py,sha256=iikzlfmz7acoB-q30LDpDVn0uqN5x9F1TosnAQu00pc,940
|
5
5
|
python3_commons/fs.py,sha256=wfLjybXndwLqNlOxTpm_HRJnuTcC4wbrHEOaEeCo9Wc,337
|
6
6
|
python3_commons/helpers.py,sha256=OmuCF7UeJ6oe-rH1Y4ZYVW_uPQ973lCLsikj01wmNqs,3101
|
7
7
|
python3_commons/object_storage.py,sha256=Bte49twIJ4l6VAzIqK6tLx7DFYwijErUmmhWkrZpSJE,4074
|
8
8
|
python3_commons/permissions.py,sha256=V6kT7gBQ0fZRDQwreM9es90BvvpB3gUofuqnFvx2g-o,1553
|
9
|
-
python3_commons/db/__init__.py,sha256=
|
9
|
+
python3_commons/db/__init__.py,sha256=t9OsJXVbjsNZ0sW_96kzVMac_YKvKSlsrM5oP1uf9Vg,2338
|
10
10
|
python3_commons/db/helpers.py,sha256=0z-pXAxQg0KqrqfoUcRooRHNrrKi-g2mSO6euVMscpE,1891
|
11
11
|
python3_commons/db/models/__init__.py,sha256=AeeTLUqdqQrhCTi14ACWO0ccyVyWFppZVtCeWShSvR0,193
|
12
12
|
python3_commons/db/models/auth.py,sha256=ctHiz_5x17TdXac7a3SjfuZ0-nEgnxK7RwKOY8qflZc,1195
|
@@ -19,9 +19,9 @@ python3_commons/serializers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMp
|
|
19
19
|
python3_commons/serializers/json.py,sha256=P288wWz9ic38QWEMrpp_uwKPYkQiOgvE1cI4WZn6ZCg,808
|
20
20
|
python3_commons/serializers/msgpack.py,sha256=tzIGGyDL3UpZnnouCtnxuYDx6InKM_C3PP1N4PN8wd4,1269
|
21
21
|
python3_commons/serializers/msgspec.py,sha256=FuZVqOLJb0-lEKrs7dtjhwEbHIpfMUk5yu1hD64zRdc,2038
|
22
|
-
python3_commons-0.
|
23
|
-
python3_commons-0.
|
24
|
-
python3_commons-0.
|
25
|
-
python3_commons-0.
|
26
|
-
python3_commons-0.
|
27
|
-
python3_commons-0.
|
22
|
+
python3_commons-0.8.0.dist-info/licenses/AUTHORS.rst,sha256=3R9JnfjfjH5RoPWOeqKFJgxVShSSfzQPIrEr1nxIo9Q,90
|
23
|
+
python3_commons-0.8.0.dist-info/licenses/LICENSE,sha256=xxILuojHm4fKQOrMHPSslbyy6WuKAN2RiG74HbrYfzM,34575
|
24
|
+
python3_commons-0.8.0.dist-info/METADATA,sha256=9JFDLJDERSBAArdTZSDt8TOX35dfQEAqR1Ri8-cXbHo,1149
|
25
|
+
python3_commons-0.8.0.dist-info/WHEEL,sha256=1tXe9gY0PYatrMPMDd6jXqjfpz_B-Wqm32CPfRC58XU,91
|
26
|
+
python3_commons-0.8.0.dist-info/top_level.txt,sha256=lJI6sCBf68eUHzupCnn2dzG10lH3jJKTWM_hrN1cQ7M,16
|
27
|
+
python3_commons-0.8.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|