jararaca 0.3.11a3__py3-none-any.whl → 0.3.11a4__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.

Potentially problematic release.


This version of jararaca might be problematic. Click here for more details.

jararaca/__init__.py CHANGED
@@ -73,7 +73,11 @@ if TYPE_CHECKING:
73
73
  from .persistence.interceptors.aiosqa_interceptor import (
74
74
  AIOSQAConfig,
75
75
  AIOSqlAlchemySessionInterceptor,
76
+ providing_new_session,
77
+ providing_session,
78
+ providing_transaction,
76
79
  use_session,
80
+ use_transaction,
77
81
  )
78
82
  from .persistence.utilities import (
79
83
  CriteriaBasedAttributeQueryInjector,
@@ -191,6 +195,10 @@ if TYPE_CHECKING:
191
195
  "Container",
192
196
  "WebSocketInterceptor",
193
197
  "use_session",
198
+ "use_transaction",
199
+ "providing_session",
200
+ "providing_transaction",
201
+ "providing_new_session",
194
202
  "Post",
195
203
  "Get",
196
204
  "Patch",
@@ -335,6 +343,26 @@ _dynamic_imports: "dict[str, tuple[str, str, str | None]]" = {
335
343
  "persistence.interceptors.aiosqa_interceptor",
336
344
  None,
337
345
  ),
346
+ "use_transaction": (
347
+ __SPEC_PARENT__,
348
+ "persistence.interceptors.aiosqa_interceptor",
349
+ None,
350
+ ),
351
+ "providing_session": (
352
+ __SPEC_PARENT__,
353
+ "persistence.interceptors.aiosqa_interceptor",
354
+ None,
355
+ ),
356
+ "providing_new_session": (
357
+ __SPEC_PARENT__,
358
+ "persistence.interceptors.aiosqa_interceptor",
359
+ None,
360
+ ),
361
+ "providing_transaction": (
362
+ __SPEC_PARENT__,
363
+ "persistence.interceptors.aiosqa_interceptor",
364
+ None,
365
+ ),
338
366
  "Post": (__SPEC_PARENT__, "presentation.decorators", None),
339
367
  "Get": (__SPEC_PARENT__, "presentation.decorators", None),
340
368
  "Patch": (__SPEC_PARENT__, "presentation.decorators", None),
@@ -1,6 +1,7 @@
1
1
  from typing import Any, Self, Type, TypeVar
2
2
 
3
3
  from pydantic import BaseModel
4
+ from sqlalchemy.ext.asyncio import AsyncAttrs
4
5
  from sqlalchemy.orm import DeclarativeBase
5
6
 
6
7
  IDENTIFIABLE_SCHEMA_T = TypeVar("IDENTIFIABLE_SCHEMA_T")
@@ -20,7 +21,7 @@ def recursive_get_dict(obj: Any) -> Any:
20
21
  return obj
21
22
 
22
23
 
23
- class BaseEntity(DeclarativeBase):
24
+ class BaseEntity(AsyncAttrs, DeclarativeBase):
24
25
 
25
26
  @classmethod
26
27
  def from_basemodel(cls, mutation: T_BASEMODEL) -> "Self":
@@ -3,21 +3,47 @@ from contextvars import ContextVar
3
3
  from dataclasses import dataclass
4
4
  from typing import Any, AsyncGenerator, Generator
5
5
 
6
- from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
6
+ from sqlalchemy.ext.asyncio import (
7
+ AsyncSession,
8
+ AsyncSessionTransaction,
9
+ async_sessionmaker,
10
+ create_async_engine,
11
+ )
7
12
  from sqlalchemy.ext.asyncio.engine import AsyncEngine
8
13
 
9
14
  from jararaca.microservice import AppContext, AppInterceptor
10
15
 
11
- ctx_session_map = ContextVar[dict[str, AsyncSession]]("ctx_session_map", default={})
16
+ ctx_default_connection_name: ContextVar[str] = ContextVar("ctx_default_connection_name")
17
+
18
+
19
+ def ensure_name(name: str | None) -> str:
20
+ if name is None:
21
+ return ctx_default_connection_name.get()
22
+ return name
23
+
24
+
25
+ @dataclass
26
+ class PersistenceCtx:
27
+ session: AsyncSession
28
+ tx: AsyncSessionTransaction
29
+
30
+
31
+ ctx_session_map = ContextVar[dict[str, PersistenceCtx]]("ctx_session_map", default={})
12
32
 
13
33
 
14
34
  @contextmanager
15
- def provide_session(
16
- connection_name: str, session: AsyncSession
35
+ def providing_session(
36
+ session: AsyncSession,
37
+ tx: AsyncSessionTransaction,
38
+ connection_name: str | None = None,
17
39
  ) -> Generator[None, Any, None]:
40
+
41
+ connection_name = ensure_name(connection_name)
18
42
  current_map = ctx_session_map.get({})
19
43
 
20
- token = ctx_session_map.set({**current_map, connection_name: session})
44
+ token = ctx_session_map.set(
45
+ {**current_map, connection_name: PersistenceCtx(session, tx)}
46
+ )
21
47
 
22
48
  try:
23
49
  yield
@@ -26,18 +52,60 @@ def provide_session(
26
52
  ctx_session_map.reset(token)
27
53
 
28
54
 
29
- def use_session(connection_name: str = "default") -> AsyncSession:
55
+ @asynccontextmanager
56
+ async def providing_new_session(
57
+ connection_name: str | None = None,
58
+ ) -> AsyncGenerator[AsyncSession, None]:
59
+
60
+ current_session = use_session(connection_name)
61
+
62
+ async with AsyncSession(
63
+ current_session.bind,
64
+ ) as new_session, new_session.begin() as new_tx:
65
+ with providing_session(new_session, new_tx, connection_name):
66
+ yield new_session
67
+
68
+
69
+ def use_session(connection_name: str | None = None) -> AsyncSession:
70
+ connection_name = ensure_name(connection_name)
30
71
  current_map = ctx_session_map.get({})
31
72
  if connection_name not in current_map:
32
73
  raise ValueError(f"Session not found for connection {connection_name}")
33
74
 
34
- return current_map[connection_name]
75
+ return current_map[connection_name].session
76
+
77
+
78
+ @contextmanager
79
+ def providing_transaction(
80
+ tx: AsyncSessionTransaction,
81
+ connection_name: str | None = None,
82
+ ) -> Generator[None, Any, None]:
83
+ connection_name = ensure_name(connection_name)
84
+
85
+ current_map = ctx_session_map.get({})
86
+
87
+ if connection_name not in current_map:
88
+ raise ValueError(f"No session found for connection {connection_name}")
89
+
90
+ with providing_session(current_map[connection_name].session, tx, connection_name):
91
+ yield
92
+
93
+
94
+ def use_transaction(connection_name: str | None = None) -> AsyncSessionTransaction:
95
+ current_map = ctx_session_map.get({})
96
+ if connection_name not in current_map:
97
+ raise ValueError(f"Transaction not found for connection {connection_name}")
98
+
99
+ return current_map[connection_name].tx
35
100
 
36
101
 
37
- @dataclass
38
102
  class AIOSQAConfig:
39
- connection_name: str
40
103
  url: str | AsyncEngine
104
+ connection_name: str
105
+
106
+ def __init__(self, url: str | AsyncEngine, connection_name: str = "default"):
107
+ self.url = url
108
+ self.connection_name = connection_name
41
109
 
42
110
 
43
111
  class AIOSqlAlchemySessionInterceptor(AppInterceptor):
@@ -54,11 +122,16 @@ class AIOSqlAlchemySessionInterceptor(AppInterceptor):
54
122
 
55
123
  @asynccontextmanager
56
124
  async def intercept(self, app_context: AppContext) -> AsyncGenerator[None, None]:
57
- async with self.sessionmaker() as session:
58
- with provide_session(self.config.connection_name, session):
125
+
126
+ async with self.sessionmaker() as session, session.begin() as tx:
127
+ token = ctx_default_connection_name.set(self.config.connection_name)
128
+ with providing_session(session, tx, self.config.connection_name):
59
129
  try:
60
130
  yield
61
- await session.commit()
131
+ if tx.is_active:
132
+ await tx.commit()
62
133
  except Exception as e:
63
- await session.rollback()
134
+ await tx.rollback()
64
135
  raise e
136
+ finally:
137
+ ctx_default_connection_name.reset(token)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: jararaca
3
- Version: 0.3.11a3
3
+ Version: 0.3.11a4
4
4
  Summary: A simple and fast API framework for Python
5
5
  Author: Lucas S
6
6
  Author-email: me@luscasleo.dev
@@ -1,4 +1,4 @@
1
- jararaca/__init__.py,sha256=4WO-Th3vY1_0SKdLyviZN2rftiX7R5yPVNPGJ9Mf5Y0,15633
1
+ jararaca/__init__.py,sha256=LL97aPXyHyb-bjW4EYL2y33UjJER2GlvjMlZiTLioEw,16387
2
2
  jararaca/__main__.py,sha256=-O3vsB5lHdqNFjUtoELDF81IYFtR-DSiiFMzRaiSsv4,67
3
3
  jararaca/broker_backend/__init__.py,sha256=GzEIuHR1xzgCJD4FE3harNjoaYzxHMHoEL0_clUaC-k,3528
4
4
  jararaca/broker_backend/mapper.py,sha256=vTsi7sWpNvlga1PWPFg0rCJ5joJ0cdzykkIc2Tuvenc,696
@@ -27,10 +27,10 @@ jararaca/observability/decorators.py,sha256=XffBinFXdiNkY6eo8_1nkr_GapM0RUGBg0ai
27
27
  jararaca/observability/interceptor.py,sha256=GHkuGKFWftN7MDjvYeGFGEPnuJETNhtxRK6yuPrCrpU,1462
28
28
  jararaca/observability/providers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  jararaca/observability/providers/otel.py,sha256=LgfoITdoQTCxKebfLcEfwMiG992wlWY_0AUTd2fo8hY,6065
30
- jararaca/persistence/base.py,sha256=Xfnpvj3yeLdpVBifH5W6AwPCLwL2ot0dpLzbPg1zwkQ,966
30
+ jararaca/persistence/base.py,sha256=xnGUbsLNz3gO-9iJt-Sn5NY13Yc9-misP8wLwQuGGoM,1024
31
31
  jararaca/persistence/exports.py,sha256=Ghx4yoFaB4QVTb9WxrFYgmcSATXMNvrOvT8ybPNKXCA,62
32
32
  jararaca/persistence/interceptors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
- jararaca/persistence/interceptors/aiosqa_interceptor.py,sha256=H6ZjOdosYGCZUzKjugiXQwJkAbnsL4HnkZLOEQhULEc,1986
33
+ jararaca/persistence/interceptors/aiosqa_interceptor.py,sha256=VOaoSFZtcCJTrdYxjLUtzkG6bWMVbOKT6WI1BP2hmls,4090
34
34
  jararaca/persistence/session.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
35
35
  jararaca/persistence/sort_filter.py,sha256=agggpN0YvNjUr6wJjy69NkaqxoDDW13ys9B3r85OujA,9226
36
36
  jararaca/persistence/utilities.py,sha256=imcV4Oi5kXNk6m9QF2-OsnFpcTRY4w5mBYLdEx5XTSQ,14296
@@ -66,8 +66,8 @@ jararaca/tools/metadata.py,sha256=7nlCDYgItNybentPSSCc2MLqN7IpBd0VyQzfjfQycVI,14
66
66
  jararaca/tools/typescript/interface_parser.py,sha256=35xbOrZDQDyTXdMrVZQ8nnFw79f28lJuLYNHAspIqi8,30492
67
67
  jararaca/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
68
68
  jararaca/utils/rabbitmq_utils.py,sha256=FPDP8ZVgvitZXV-oK73D7EIANsqUzXTW7HdpEKsIsyI,2811
69
- jararaca-0.3.11a3.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
70
- jararaca-0.3.11a3.dist-info/METADATA,sha256=JIMh7XrOOOqc11tQi7hoGCfKaW4D7YSWW542qBJbBgk,4954
71
- jararaca-0.3.11a3.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
72
- jararaca-0.3.11a3.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
73
- jararaca-0.3.11a3.dist-info/RECORD,,
69
+ jararaca-0.3.11a4.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
70
+ jararaca-0.3.11a4.dist-info/METADATA,sha256=VeC353GhTULAEFtJysdLpvMX1MBxRhwXsL35n4pCm5k,4954
71
+ jararaca-0.3.11a4.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
72
+ jararaca-0.3.11a4.dist-info/entry_points.txt,sha256=WIh3aIvz8LwUJZIDfs4EeH3VoFyCGEk7cWJurW38q0I,45
73
+ jararaca-0.3.11a4.dist-info/RECORD,,