nlbone 0.1.21__py3-none-any.whl → 0.1.23__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.
@@ -0,0 +1,118 @@
1
+ from contextlib import asynccontextmanager, contextmanager
2
+ from typing import Generator, Optional, Any, AsyncGenerator
3
+
4
+ from sqlalchemy import create_engine, text
5
+ from sqlalchemy.engine import Engine
6
+ from sqlalchemy.orm import Session, sessionmaker
7
+
8
+ from sqlalchemy.ext.asyncio import (
9
+ AsyncEngine,
10
+ AsyncSession,
11
+ async_sessionmaker,
12
+ create_async_engine,
13
+ )
14
+
15
+ from nlbone.config.settings import get_settings
16
+
17
+ _settings = get_settings()
18
+
19
+ ASYNC_DSN: str = _settings.POSTGRES_DB_DSN
20
+
21
+ if "+asyncpg" in ASYNC_DSN:
22
+ SYNC_DSN: str = ASYNC_DSN.replace("+asyncpg", "+psycopg")
23
+ else:
24
+ SYNC_DSN = ASYNC_DSN
25
+
26
+ _async_engine: Optional[AsyncEngine] = None
27
+ _async_session_factory: Optional[async_sessionmaker[AsyncSession]] = None
28
+
29
+ _sync_engine: Optional[Engine] = None
30
+ _sync_session_factory: Optional[sessionmaker[Session]] = None
31
+
32
+
33
+ def init_async_engine(echo: Optional[bool] = None) -> AsyncEngine:
34
+ global _async_engine, _async_session_factory
35
+ if _async_engine is not None:
36
+ return _async_engine
37
+
38
+ _async_engine = create_async_engine(
39
+ ASYNC_DSN,
40
+ echo=_settings.DEBUG if echo is None else echo,
41
+ pool_pre_ping=True,
42
+ pool_size=5,
43
+ max_overflow=10,
44
+ )
45
+ _async_session_factory = async_sessionmaker(
46
+ bind=_async_engine,
47
+ expire_on_commit=False,
48
+ autoflush=False,
49
+ )
50
+ return _async_engine
51
+
52
+
53
+ @asynccontextmanager
54
+ async def async_session() -> AsyncGenerator[AsyncSession, Any]:
55
+ if _async_session_factory is None:
56
+ init_async_engine()
57
+ assert _async_session_factory is not None
58
+ session = _async_session_factory()
59
+ try:
60
+ yield session
61
+ await session.commit()
62
+ except Exception:
63
+ await session.rollback()
64
+ raise
65
+ finally:
66
+ await session.close()
67
+
68
+
69
+ async def async_ping() -> None:
70
+ eng = init_async_engine()
71
+ async with eng.connect() as conn:
72
+ await conn.execute(text("SELECT 1"))
73
+
74
+
75
+ def init_sync_engine(echo: Optional[bool] = None) -> Engine:
76
+ global _sync_engine, _sync_session_factory
77
+ if _sync_engine is not None:
78
+ return _sync_engine
79
+
80
+ _sync_engine = create_engine(
81
+ SYNC_DSN,
82
+ echo=_settings.DEBUG if echo is None else echo,
83
+ pool_pre_ping=True,
84
+ pool_size=5,
85
+ max_overflow=10,
86
+ future=True,
87
+ )
88
+ _sync_session_factory = sessionmaker(
89
+ bind=_sync_engine,
90
+ autocommit=False,
91
+ autoflush=False,
92
+ expire_on_commit=False,
93
+ future=True,
94
+ )
95
+ return _sync_engine
96
+
97
+
98
+ @contextmanager
99
+ def sync_session() -> Generator[Session, None, None]:
100
+ if _sync_session_factory is None:
101
+ init_sync_engine()
102
+ assert _sync_session_factory is not None
103
+ s = _sync_session_factory()
104
+ try:
105
+ yield s
106
+ s.commit()
107
+ except Exception:
108
+ s.rollback()
109
+ raise
110
+ finally:
111
+ s.close()
112
+
113
+
114
+ def sync_ping() -> None:
115
+ """Health check برای اتصال sync."""
116
+ eng = init_sync_engine()
117
+ with eng.connect() as conn:
118
+ conn.execute(text("SELECT 1"))
nlbone/config/settings.py CHANGED
@@ -12,7 +12,7 @@ class Settings(BaseSettings):
12
12
  ENV: Literal["local", "dev", "staging", "prod"] = Field(default="local")
13
13
  DEBUG: bool = Field(default=False)
14
14
  LOG_LEVEL: Literal["CRITICAL", "ERROR", "WARNING", "INFO", "DEBUG"] = Field(default="INFO")
15
- LOG_JSON: bool = Field(default=True) # اگر False باشد، فرمت متنی ساده می‌شود.
15
+ LOG_JSON: bool = Field(default=True)
16
16
 
17
17
  # ---------------------------
18
18
  # HTTP / Timeouts
@@ -30,10 +30,10 @@ class Settings(BaseSettings):
30
30
  # ---------------------------
31
31
  # Database
32
32
  # ---------------------------
33
- DB_DSN: str = Field(default="postgresql+asyncpg://user:pass@localhost:5432/nlbone")
33
+ POSTGRES_DB_DSN: str = Field(default="postgresql+asyncpg://user:pass@localhost:5432/nlbone")
34
34
 
35
35
  # ---------------------------
36
- # Messaging / Cache (نمونه)
36
+ # Messaging / Cache
37
37
  # ---------------------------
38
38
  REDIS_URL: str = Field(default="redis://localhost:6379/0")
39
39
 
@@ -0,0 +1,16 @@
1
+ from __future__ import annotations
2
+ from typing import AsyncGenerator, Generator
3
+
4
+ from sqlalchemy.orm import Session
5
+ from sqlalchemy.ext.asyncio import AsyncSession
6
+
7
+ from nlbone.adapters.db.sqlalchemy.engine import async_session, sync_session
8
+
9
+
10
+ async def get_async_session() -> AsyncGenerator[AsyncSession, None]:
11
+ async with async_session() as s:
12
+ yield s
13
+
14
+ def get_session() -> Generator[Session, None, None]:
15
+ with sync_session() as s:
16
+ yield s
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nlbone
3
- Version: 0.1.21
3
+ Version: 0.1.23
4
4
  Summary: Backbone package for interfaces and infrastructure in Python projects
5
5
  Author-email: Amir Hosein Kahkbazzadeh <a.khakbazzadeh@gmail.com>
6
6
  License: MIT
@@ -21,6 +21,7 @@ Requires-Dist: pre-commit>=3.7; extra == 'dev'
21
21
  Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
22
22
  Requires-Dist: pytest>=8.0; extra == 'dev'
23
23
  Requires-Dist: ruff>=0.5; extra == 'dev'
24
+ Requires-Dist: tomli; extra == 'dev'
24
25
  Requires-Dist: twine; extra == 'dev'
25
26
  Description-Content-Type: text/markdown
26
27
 
@@ -8,6 +8,7 @@ nlbone/adapters/db/memory.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
8
8
  nlbone/adapters/db/postgres.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
9
  nlbone/adapters/db/query_builder.py,sha256=qL2Ppe39X7pnKpHfWZZanxfEKqQW3grZv5bQLS52mfU,6066
10
10
  nlbone/adapters/db/sqlalchemy/__init__.py,sha256=bq_dIuk4JqT-68k6p0aMb7DY2GqcsvvsuZT5uZDuTBU,127
11
+ nlbone/adapters/db/sqlalchemy/engine.py,sha256=baEByNlB8NFuGVnMMz7xJqNa1_1E7DbLJ0vUo9vFarg,3045
11
12
  nlbone/adapters/db/sqlalchemy/query/__init__.py,sha256=9SFkoNkklaji6kZt_Nl6X6vqMFE92GiqW36Zezr5PuE,129
12
13
  nlbone/adapters/db/sqlalchemy/query/builder.py,sha256=AzUX2MlfrMGY-EITzVJoq9naM5sTL9h9yzI7cCeEBRk,886
13
14
  nlbone/adapters/db/sqlalchemy/query/coercion.py,sha256=uYClfEuew_W4r-vbwj2c5MVpayejhpOMl6h4iUrMotQ,2142
@@ -20,7 +21,7 @@ nlbone/adapters/messaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
20
21
  nlbone/adapters/messaging/redis.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
22
  nlbone/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
23
  nlbone/config/logging.py,sha256=68WRQejEpL6eHEY_cOgdlOjndKc-RWth0n4YmXnceC8,5041
23
- nlbone/config/settings.py,sha256=N3o7FWAEx_aYyOzmoRH6muq4K39rQC-mWJJuHz6Ps90,1864
24
+ nlbone/config/settings.py,sha256=f9zIRsWce8v8ZFI0dd4vBY9O-Oo7TKEBDT4wOA8bKcs,1791
24
25
  nlbone/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
25
26
  nlbone/core/{__init__.py},sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
27
  nlbone/core/application/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -38,6 +39,7 @@ nlbone/di/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
39
  nlbone/di/container.py,sha256=7-lcrH1q9NmNLY7VMpLfPJZYKsvNuXP2U6gOYcCwgPo,304
39
40
  nlbone/interfaces/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
41
  nlbone/interfaces/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
42
+ nlbone/interfaces/api/dependencies.py,sha256=IqDVq1lcCCxd22FBUg523lVANM_j71BYAQtsbrHc4M8,465
41
43
  nlbone/interfaces/api/exceptions.py,sha256=OczR1FND2nbCngwbfgaPrgDbDaz4Pc47mFSHgtL7tW8,313
42
44
  nlbone/interfaces/api/routers.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
45
  nlbone/interfaces/api/schemas.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -49,7 +51,7 @@ nlbone/interfaces/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
49
51
  nlbone/interfaces/jobs/sync_tokens.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
50
52
  nlbone/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
53
  nlbone/utils/time.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
52
- nlbone-0.1.21.dist-info/METADATA,sha256=L89KPfF_G7h-Oh5_VdrING8ycju2yIphCNYKAcKS554,2189
53
- nlbone-0.1.21.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
54
- nlbone-0.1.21.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
- nlbone-0.1.21.dist-info/RECORD,,
54
+ nlbone-0.1.23.dist-info/METADATA,sha256=3hwLuYJE0xbwf5ZZXeubHEO9F45CT4FDiCgMdklj81w,2226
55
+ nlbone-0.1.23.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
56
+ nlbone-0.1.23.dist-info/licenses/LICENSE,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
57
+ nlbone-0.1.23.dist-info/RECORD,,