jararaca 0.3.11a3__tar.gz → 0.3.11a4__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.
Files changed (83) hide show
  1. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/PKG-INFO +1 -1
  2. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/pyproject.toml +1 -1
  3. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/__init__.py +28 -0
  4. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/persistence/base.py +2 -1
  5. jararaca-0.3.11a4/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +137 -0
  6. jararaca-0.3.11a3/src/jararaca/persistence/interceptors/aiosqa_interceptor.py +0 -64
  7. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/LICENSE +0 -0
  8. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/README.md +0 -0
  9. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/CNAME +0 -0
  10. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/architecture.md +0 -0
  11. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.jpeg +0 -0
  12. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/assets/_f04774c9-7e05-4da4-8b17-8be23f6a1475.webp +0 -0
  13. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/assets/tracing_example.png +0 -0
  14. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/index.md +0 -0
  15. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/messagebus.md +0 -0
  16. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/scheduler.md +0 -0
  17. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/stylesheets/custom.css +0 -0
  18. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/docs/websocket.md +0 -0
  19. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/__main__.py +0 -0
  20. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/broker_backend/__init__.py +0 -0
  21. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/broker_backend/mapper.py +0 -0
  22. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/broker_backend/redis_broker_backend.py +0 -0
  23. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/cli.py +0 -0
  24. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/common/__init__.py +0 -0
  25. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/core/__init__.py +0 -0
  26. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/core/providers.py +0 -0
  27. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/core/uow.py +0 -0
  28. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/di.py +0 -0
  29. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/files/entity.py.mako +0 -0
  30. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/lifecycle.py +0 -0
  31. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/__init__.py +0 -0
  32. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/bus_message_controller.py +0 -0
  33. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/consumers/__init__.py +0 -0
  34. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/decorators.py +0 -0
  35. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/interceptors/__init__.py +0 -0
  36. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/interceptors/aiopika_publisher_interceptor.py +0 -0
  37. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/interceptors/publisher_interceptor.py +0 -0
  38. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/message.py +0 -0
  39. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/publisher.py +0 -0
  40. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/worker.py +0 -0
  41. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/messagebus/worker_v2.py +0 -0
  42. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/microservice.py +0 -0
  43. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/observability/decorators.py +0 -0
  44. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/observability/interceptor.py +0 -0
  45. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/observability/providers/__init__.py +0 -0
  46. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/observability/providers/otel.py +0 -0
  47. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/persistence/exports.py +0 -0
  48. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/persistence/interceptors/__init__.py +0 -0
  49. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/persistence/session.py +0 -0
  50. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/persistence/sort_filter.py +0 -0
  51. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/persistence/utilities.py +0 -0
  52. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/__init__.py +0 -0
  53. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/decorators.py +0 -0
  54. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/hooks.py +0 -0
  55. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/http_microservice.py +0 -0
  56. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/server.py +0 -0
  57. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/__init__.py +0 -0
  58. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/base_types.py +0 -0
  59. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/context.py +0 -0
  60. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/decorators.py +0 -0
  61. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/redis.py +0 -0
  62. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/types.py +0 -0
  63. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/presentation/websocket/websocket_interceptor.py +0 -0
  64. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/py.typed +0 -0
  65. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/__init__.py +0 -0
  66. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/http/__init__.py +0 -0
  67. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/http/backends/__init__.py +0 -0
  68. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/http/backends/httpx.py +0 -0
  69. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/http/backends/otel.py +0 -0
  70. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/http/decorators.py +0 -0
  71. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/rpc/http/httpx.py +0 -0
  72. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/scheduler/__init__.py +0 -0
  73. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/scheduler/decorators.py +0 -0
  74. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/scheduler/scheduler.py +0 -0
  75. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/scheduler/scheduler_v2.py +0 -0
  76. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/scheduler/types.py +0 -0
  77. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/tools/app_config/__init__.py +0 -0
  78. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/tools/app_config/decorators.py +0 -0
  79. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/tools/app_config/interceptor.py +0 -0
  80. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/tools/metadata.py +0 -0
  81. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/tools/typescript/interface_parser.py +0 -0
  82. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/utils/__init__.py +0 -0
  83. {jararaca-0.3.11a3 → jararaca-0.3.11a4}/src/jararaca/utils/rabbitmq_utils.py +0 -0
@@ -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,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "jararaca"
3
- version = "0.3.11a3"
3
+ version = "0.3.11a4"
4
4
  description = "A simple and fast API framework for Python"
5
5
  authors = ["Lucas S <me@luscasleo.dev>"]
6
6
  readme = "README.md"
@@ -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":
@@ -0,0 +1,137 @@
1
+ from contextlib import asynccontextmanager, contextmanager, suppress
2
+ from contextvars import ContextVar
3
+ from dataclasses import dataclass
4
+ from typing import Any, AsyncGenerator, Generator
5
+
6
+ from sqlalchemy.ext.asyncio import (
7
+ AsyncSession,
8
+ AsyncSessionTransaction,
9
+ async_sessionmaker,
10
+ create_async_engine,
11
+ )
12
+ from sqlalchemy.ext.asyncio.engine import AsyncEngine
13
+
14
+ from jararaca.microservice import AppContext, AppInterceptor
15
+
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={})
32
+
33
+
34
+ @contextmanager
35
+ def providing_session(
36
+ session: AsyncSession,
37
+ tx: AsyncSessionTransaction,
38
+ connection_name: str | None = None,
39
+ ) -> Generator[None, Any, None]:
40
+
41
+ connection_name = ensure_name(connection_name)
42
+ current_map = ctx_session_map.get({})
43
+
44
+ token = ctx_session_map.set(
45
+ {**current_map, connection_name: PersistenceCtx(session, tx)}
46
+ )
47
+
48
+ try:
49
+ yield
50
+ finally:
51
+ with suppress(ValueError):
52
+ ctx_session_map.reset(token)
53
+
54
+
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)
71
+ current_map = ctx_session_map.get({})
72
+ if connection_name not in current_map:
73
+ raise ValueError(f"Session not found for connection {connection_name}")
74
+
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
100
+
101
+
102
+ class AIOSQAConfig:
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
109
+
110
+
111
+ class AIOSqlAlchemySessionInterceptor(AppInterceptor):
112
+
113
+ def __init__(self, config: AIOSQAConfig):
114
+ self.config = config
115
+ self.engine = (
116
+ create_async_engine(self.config.url)
117
+ if isinstance(self.config.url, str)
118
+ else self.config.url
119
+ )
120
+
121
+ self.sessionmaker = async_sessionmaker(self.engine)
122
+
123
+ @asynccontextmanager
124
+ async def intercept(self, app_context: AppContext) -> AsyncGenerator[None, None]:
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):
129
+ try:
130
+ yield
131
+ if tx.is_active:
132
+ await tx.commit()
133
+ except Exception as e:
134
+ await tx.rollback()
135
+ raise e
136
+ finally:
137
+ ctx_default_connection_name.reset(token)
@@ -1,64 +0,0 @@
1
- from contextlib import asynccontextmanager, contextmanager, suppress
2
- from contextvars import ContextVar
3
- from dataclasses import dataclass
4
- from typing import Any, AsyncGenerator, Generator
5
-
6
- from sqlalchemy.ext.asyncio import AsyncSession, async_sessionmaker, create_async_engine
7
- from sqlalchemy.ext.asyncio.engine import AsyncEngine
8
-
9
- from jararaca.microservice import AppContext, AppInterceptor
10
-
11
- ctx_session_map = ContextVar[dict[str, AsyncSession]]("ctx_session_map", default={})
12
-
13
-
14
- @contextmanager
15
- def provide_session(
16
- connection_name: str, session: AsyncSession
17
- ) -> Generator[None, Any, None]:
18
- current_map = ctx_session_map.get({})
19
-
20
- token = ctx_session_map.set({**current_map, connection_name: session})
21
-
22
- try:
23
- yield
24
- finally:
25
- with suppress(ValueError):
26
- ctx_session_map.reset(token)
27
-
28
-
29
- def use_session(connection_name: str = "default") -> AsyncSession:
30
- current_map = ctx_session_map.get({})
31
- if connection_name not in current_map:
32
- raise ValueError(f"Session not found for connection {connection_name}")
33
-
34
- return current_map[connection_name]
35
-
36
-
37
- @dataclass
38
- class AIOSQAConfig:
39
- connection_name: str
40
- url: str | AsyncEngine
41
-
42
-
43
- class AIOSqlAlchemySessionInterceptor(AppInterceptor):
44
-
45
- def __init__(self, config: AIOSQAConfig):
46
- self.config = config
47
- self.engine = (
48
- create_async_engine(self.config.url)
49
- if isinstance(self.config.url, str)
50
- else self.config.url
51
- )
52
-
53
- self.sessionmaker = async_sessionmaker(self.engine)
54
-
55
- @asynccontextmanager
56
- 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):
59
- try:
60
- yield
61
- await session.commit()
62
- except Exception as e:
63
- await session.rollback()
64
- raise e
File without changes
File without changes
File without changes
File without changes