sotkalib 0.0.2__py3-none-any.whl → 0.0.4__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.
sotkalib/sqla/db.py ADDED
@@ -0,0 +1,101 @@
1
+ from pydantic import BaseModel, Field
2
+ from sqlalchemy import Engine, create_engine
3
+ from sqlalchemy.ext.asyncio import AsyncEngine, async_sessionmaker, create_async_engine
4
+ from sqlalchemy.ext.asyncio.session import AsyncSession
5
+ from sqlalchemy.orm import Session, sessionmaker
6
+
7
+ from sotkalib.log import get_logger
8
+
9
+
10
+ class ConnectionTimeoutError(Exception): pass
11
+
12
+ class DatabaseSettings(BaseModel):
13
+ uri: str = Field(examples=[
14
+ "postgresql://username:password@localhost:5432/database"
15
+ ])
16
+ async_driver: str = "asyncpg"
17
+ echo: bool = False
18
+ pool_size: int = 10
19
+
20
+ @property
21
+ def async_uri(self) -> str:
22
+ return self.uri.replace("postgresql://", "postgresql" + self.async_driver + "://")
23
+
24
+ class Database:
25
+ _sync_engine: Engine | None
26
+ _async_engine: AsyncEngine | None
27
+ _sync_session_factory: sessionmaker = None
28
+ _async_session_factory: async_sessionmaker = None
29
+
30
+ logger = get_logger("sqldb.instance")
31
+
32
+ def __init__(self, settings: DatabaseSettings):
33
+ self.__async_uri = settings.async_uri
34
+ self.__sync_uri = settings.uri
35
+ self.echo = settings.echo
36
+ self.pool_size = settings.pool_size
37
+
38
+ def __enter__(self):
39
+ return self
40
+
41
+ def __exit__(self, exc_type, exc_val, exc_tb):
42
+ if self._sync_engine:
43
+ self._sync_engine.dispose()
44
+ self.logger.info("closed sync db connection")
45
+
46
+ async def __aenter__(self):
47
+ return self
48
+
49
+ async def __aexit__(self, *args):
50
+ if self._async_engine:
51
+ await self._async_engine.dispose()
52
+ self.logger.info("closed async db connection")
53
+
54
+ def __async_init(self):
55
+ self._async_engine = create_async_engine(
56
+ url=self.__async_uri,
57
+ echo=self.echo,
58
+ pool_size=self.pool_size,
59
+ )
60
+ self._async_session_factory = async_sessionmaker(bind=self._async_engine, expire_on_commit=False)
61
+ self.logger.debug( # noqa: PLE1205
62
+ "successfully initialized async db connection, engine.status = {} sessionmaker.status = {}",
63
+ self._async_engine.name is not None,
64
+ self._async_session_factory is not None,
65
+ )
66
+
67
+ @property
68
+ def async_session(self) -> async_sessionmaker[AsyncSession]:
69
+ if self._async_engine is None or self._async_session_factory is None:
70
+ self.logger.debug("async_sf not found, initializing")
71
+ self.__async_init()
72
+ if self._async_engine is None or self._async_session_factory is None:
73
+ self.logger.error(c := "could not asynchronously connect to pgsql")
74
+ raise ConnectionTimeoutError(c)
75
+ self.logger.debug("success getting (asyncmaker)")
76
+ return self._async_session_factory
77
+
78
+ def __sync_init(self):
79
+ self._sync_engine = create_engine(
80
+ url=self.__sync_uri,
81
+ echo=self.echo,
82
+ pool_size=self.pool_size,
83
+ )
84
+ self._sync_session_factory = sessionmaker(bind=self._sync_engine, expire_on_commit=False)
85
+ self.logger.debug( # noqa
86
+ " -> (__sync_init) successfully initialized sync db connection,\n"
87
+ "\t\t\t\tengine.status = {} sessionmaker.status = {}",
88
+ self._sync_engine.name is not None,
89
+ self._sync_session_factory is not None,
90
+ )
91
+
92
+ @property
93
+ def session(self) -> sessionmaker[Session]:
94
+ if self._sync_engine is None or self._sync_session_factory is None:
95
+ self.logger.debug("not found, initializing...")
96
+ self.__sync_init()
97
+ if self._sync_engine is None or self._sync_session_factory is None:
98
+ self.logger.error(c := "could not synchronously connect to pgsql")
99
+ raise ConnectionTimeoutError(c)
100
+ self.logger.debug("success getting (syncmaker)")
101
+ return self._sync_session_factory
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sotkalib
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary:
5
5
  Author: alexey
6
6
  Author-email: alexey <me@pyrorhythm.dev>
@@ -8,6 +8,8 @@ Requires-Dist: aiohttp>=3.13.3
8
8
  Requires-Dist: dotenv>=0.9.9
9
9
  Requires-Dist: loguru>=0.7.3
10
10
  Requires-Dist: pydantic>=2.12.5
11
+ Requires-Dist: redis>=7.1.0
12
+ Requires-Dist: sqlalchemy[asyncio]>=2.0.46
11
13
  Requires-Python: >=3.13
12
14
  Description-Content-Type: text/markdown
13
15
 
@@ -0,0 +1,25 @@
1
+ sotkalib/__init__.py,sha256=t3dEAlrtHABFRZdF7RM5K2N1fDUTVwUPmBPG4jFdvSY,138
2
+ sotkalib/config/__init__.py,sha256=CSjn02NCnBPO14QOg4OzKI-lTxyKoBxQ4ODsiWamlIM,102
3
+ sotkalib/config/field.py,sha256=596_6DLnUIMN86h2uob9YN5IrHnc7fguWScSbIYsTH4,326
4
+ sotkalib/config/struct.py,sha256=gv1jFrSRytMC6bZTUDOUQf00Zo1iKxQvuTxGv9qnyHI,5679
5
+ sotkalib/enum/__init__.py,sha256=pKpLPm8fqHO4Et21TWIybIPRiehN1KrmxcBh6hPRsxM,127
6
+ sotkalib/enum/mixins.py,sha256=rgXb0eXaBSozrviOMJo1671x4DiN9SELtw3-x6PvhDM,1821
7
+ sotkalib/exceptions/__init__.py,sha256=H2h-yW1o0_X1Z9O-hWgj6h2spFxpzJJQ_N2ITMr600A,58
8
+ sotkalib/exceptions/api/__init__.py,sha256=tIFOiRlbPkgCRNv5OPZ1M98nRnAMkFIuqSK7dZpKMRI,38
9
+ sotkalib/exceptions/api/exc.py,sha256=gqx4GrHXUvKcR7tEmJpRqPbDWOT2AgKoyck8-FovQCc,1329
10
+ sotkalib/exceptions/handlers/__init__.py,sha256=rA6o6_LVa-0TToyPhT1vB_Lz2E0U8EUfHICAYgAUd78,178
11
+ sotkalib/exceptions/handlers/args_incl_error.py,sha256=DB8TMhZdSkwZwEahOJ99zXWknqBTkSC4IKZsZ5psxdg,535
12
+ sotkalib/exceptions/handlers/core.py,sha256=5fhusoxBhUz59TaVWobplBvD-sbkZKBnmmu-fcSyRk4,836
13
+ sotkalib/http/__init__.py,sha256=HxOuGbHbz39MD0ICjOSh4zv-nGPZca9TgxP4rCceamw,241
14
+ sotkalib/http/client_session.py,sha256=OtGTpwr8I7tsgOxRGS8c7tby5sGT_T6B0Zc8HTC9Sxs,8838
15
+ sotkalib/log/__init__.py,sha256=xrBx--c8QU5xkb3_n61LuqF8ySUaxlQkHCxHyH_D8aE,58
16
+ sotkalib/log/factory.py,sha256=Wl8qY2-vimpctRlRYSWPLjC0KgeEGgSSuDDJaxWtvK8,309
17
+ sotkalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
18
+ sotkalib/redis/__init__.py,sha256=wv3AIRw3aXXLgTTrt6my8C8jSBl4-R3dWRfGLbGTHng,167
19
+ sotkalib/redis/client.py,sha256=0TWe-gYqFiuCjqimCQrVrnTHSM0EROIoJL36M3qwOtQ,1118
20
+ sotkalib/redis/lock.py,sha256=nEZjIyXmgq3vH-Urs8qXC_N8lmXNho00SaTZ7wJIEIo,2528
21
+ sotkalib/sqla/__init__.py,sha256=fYT8O-bPcdXxJ3QVu3KbypwbZ_hpm8Eq1CuQgjvyNJ8,86
22
+ sotkalib/sqla/db.py,sha256=lxE6XLgX-CowyhfRwTAA_FGJybiihaGWWzlNe8M41CE,3866
23
+ sotkalib-0.0.4.dist-info/WHEEL,sha256=5DEXXimM34_d4Gx1AuF9ysMr1_maoEtGKjaILM3s4w4,80
24
+ sotkalib-0.0.4.dist-info/METADATA,sha256=4OxxOFpmiDXvjlOjQveYAlGtkXS1P8WXNZz0jchKDVY,380
25
+ sotkalib-0.0.4.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: uv 0.9.28
2
+ Generator: uv 0.9.29
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,12 +0,0 @@
1
- sotkalib/__init__.py,sha256=ebrSgK8GtSh2aZNdP3vKA6A4b1iHLFNWzpgznyOOn8Q,48
2
- sotkalib/config/__init__.py,sha256=CSjn02NCnBPO14QOg4OzKI-lTxyKoBxQ4ODsiWamlIM,102
3
- sotkalib/config/field.py,sha256=UaIiZBa4TUOB-akEqIvFJKxj2QjjsTaAjL2r163N-V4,790
4
- sotkalib/config/struct.py,sha256=kUabPNOv9uA8d0SzBOfr-w08YOYKy-D8LN0sof_ZQ5Q,6453
5
- sotkalib/http/__init__.py,sha256=gkuf1ZM7qXRmnm-yDUMmxxbCuu7bLek_PL3UmMQBtlM,317
6
- sotkalib/http/client_session.py,sha256=9AyOLFQFXf_lkirJcfp0NBIzx5owdRtDJZM-PEcCKtI,8952
7
- sotkalib/log/__init__.py,sha256=xrBx--c8QU5xkb3_n61LuqF8ySUaxlQkHCxHyH_D8aE,58
8
- sotkalib/log/factory.py,sha256=N8SZNvCdBLmsM0ES38x2BxZbJD1GgdMHtJ8h8lZjv7A,806
9
- sotkalib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
10
- sotkalib-0.0.2.dist-info/WHEEL,sha256=fAguSjoiATBe7TNBkJwOjyL1Tt4wwiaQGtNtjRPNMQA,80
11
- sotkalib-0.0.2.dist-info/METADATA,sha256=TOF1FK1cVfMXt1kXc4gVjFsFsGj8hi5uMdQkude7sMQ,309
12
- sotkalib-0.0.2.dist-info/RECORD,,