python3-commons 0.7.6__tar.gz → 0.8.0__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.
- {python3_commons-0.7.6/src/python3_commons.egg-info → python3_commons-0.8.0}/PKG-INFO +3 -2
- {python3_commons-0.7.6 → python3_commons-0.8.0}/pyproject.toml +1 -1
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/conf.py +9 -1
- python3_commons-0.8.0/src/python3_commons/db/__init__.py +72 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0/src/python3_commons.egg-info}/PKG-INFO +3 -2
- python3_commons-0.7.6/src/python3_commons/db/__init__.py +0 -60
- {python3_commons-0.7.6 → python3_commons-0.8.0}/.coveragerc +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/.github/workflows/python-publish.yaml +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/.gitignore +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/AUTHORS.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/CHANGELOG.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/LICENSE +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/README.md +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/README.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/Makefile +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/_static/.gitignore +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/authors.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/changelog.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/conf.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/index.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/docs/license.rst +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/requirements.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/requirements_dev.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/requirements_test.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/setup.cfg +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/setup.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/__init__.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/api_client.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/audit.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/db/helpers.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/db/models/__init__.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/db/models/auth.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/db/models/common.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/db/models/rbac.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/fs.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/helpers.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/logging/__init__.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/logging/filters.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/logging/formatters.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/object_storage.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/permissions.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/serializers/__init__.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/serializers/json.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/serializers/msgpack.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons/serializers/msgspec.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons.egg-info/SOURCES.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons.egg-info/dependency_links.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons.egg-info/requires.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons.egg-info/top_level.txt +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/tests/conftest.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/tests/test_audit.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/tests/test_helpers.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/tests/test_msgpack.py +0 -0
- {python3_commons-0.7.6 → python3_commons-0.8.0}/tests/test_msgspec.py +0 -0
@@ -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
|
======================
|
@@ -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):
|
@@ -0,0 +1,72 @@
|
|
1
|
+
import contextlib
|
2
|
+
import logging
|
3
|
+
from typing import AsyncGenerator, Callable, Mapping
|
4
|
+
|
5
|
+
from sqlalchemy import MetaData
|
6
|
+
from sqlalchemy.ext.asyncio import AsyncSession, AsyncEngine, async_engine_from_config
|
7
|
+
from sqlalchemy.ext.asyncio.session import async_sessionmaker
|
8
|
+
from sqlalchemy.orm import declarative_base
|
9
|
+
|
10
|
+
from python3_commons.conf import DBSettings
|
11
|
+
|
12
|
+
logger = logging.getLogger(__name__)
|
13
|
+
metadata = MetaData()
|
14
|
+
Base = declarative_base(metadata=metadata)
|
15
|
+
|
16
|
+
|
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}')
|
28
|
+
|
29
|
+
raise
|
30
|
+
|
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
|
38
|
+
|
39
|
+
return engine
|
40
|
+
|
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
|
49
|
+
|
50
|
+
return session_maker
|
51
|
+
|
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
|
56
|
+
|
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,60 +0,0 @@
|
|
1
|
-
import asyncio
|
2
|
-
import contextlib
|
3
|
-
import logging
|
4
|
-
from typing import AsyncGenerator
|
5
|
-
|
6
|
-
from asyncpg import CannotConnectNowError
|
7
|
-
from pydantic import PostgresDsn
|
8
|
-
from sqlalchemy import MetaData
|
9
|
-
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
|
10
|
-
from sqlalchemy.ext.asyncio.session import async_sessionmaker
|
11
|
-
from sqlalchemy.orm import declarative_base
|
12
|
-
|
13
|
-
from python3_commons.conf import db_settings
|
14
|
-
|
15
|
-
logger = logging.getLogger(__name__)
|
16
|
-
|
17
|
-
metadata = MetaData()
|
18
|
-
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
|
-
|
29
|
-
|
30
|
-
async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
|
31
|
-
async with async_session_maker() as session:
|
32
|
-
yield session
|
33
|
-
|
34
|
-
|
35
|
-
get_async_session_context = contextlib.asynccontextmanager(get_async_session)
|
36
|
-
|
37
|
-
|
38
|
-
async def is_healthy(pg) -> bool:
|
39
|
-
return await pg.fetchval('SELECT 1 FROM alembic_version;') == 1
|
40
|
-
|
41
|
-
|
42
|
-
async def connect_to_db(database, dsn: PostgresDsn):
|
43
|
-
logger.info('Waiting for services')
|
44
|
-
logger.debug(f'DB_DSN: {dsn}')
|
45
|
-
timeout = 0.001
|
46
|
-
total_timeout = 0
|
47
|
-
|
48
|
-
for i in range(15):
|
49
|
-
try:
|
50
|
-
await database.connect()
|
51
|
-
except (ConnectionRefusedError, CannotConnectNowError):
|
52
|
-
timeout *= 2
|
53
|
-
await asyncio.sleep(timeout)
|
54
|
-
total_timeout += timeout
|
55
|
-
else:
|
56
|
-
break
|
57
|
-
else:
|
58
|
-
msg = f'Unable to connect database for {int(total_timeout)}s'
|
59
|
-
logger.error(msg)
|
60
|
-
raise ConnectionRefusedError(msg)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{python3_commons-0.7.6 → python3_commons-0.8.0}/src/python3_commons.egg-info/dependency_links.txt
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|