fastapi-toolsets 2.4.1__tar.gz → 2.4.2__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.
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/PKG-INFO +1 -1
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/pyproject.toml +1 -1
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/__init__.py +1 -1
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/models/watched.py +40 -2
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/LICENSE +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/README.md +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/_imports.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/app.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/commands/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/commands/fixtures.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/config.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/pyproject.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/utils.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/crud/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/crud/factory.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/crud/search.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/db.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/dependencies.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/exceptions/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/exceptions/exceptions.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/exceptions/handler.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/fixtures/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/fixtures/enum.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/fixtures/registry.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/fixtures/utils.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/logger.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/metrics/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/metrics/handler.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/metrics/registry.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/models/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/models/columns.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/py.typed +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/pytest/__init__.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/pytest/plugin.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/pytest/utils.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/schemas.py +0 -0
- {fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/types.py +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Field-change monitoring via SQLAlchemy session events."""
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import inspect
|
|
4
5
|
import weakref
|
|
5
6
|
from collections.abc import Awaitable
|
|
6
7
|
from enum import Enum
|
|
@@ -25,6 +26,7 @@ _SESSION_PENDING_NEW = "_ft_pending_new"
|
|
|
25
26
|
_SESSION_CREATES = "_ft_creates"
|
|
26
27
|
_SESSION_DELETES = "_ft_deletes"
|
|
27
28
|
_SESSION_UPDATES = "_ft_updates"
|
|
29
|
+
_SESSION_SAVEPOINT_DEPTH = "_ft_sp_depth"
|
|
28
30
|
|
|
29
31
|
|
|
30
32
|
class ModelEvent(str, Enum):
|
|
@@ -65,6 +67,14 @@ def _snapshot_column_attrs(obj: Any) -> dict[str, Any]:
|
|
|
65
67
|
}
|
|
66
68
|
|
|
67
69
|
|
|
70
|
+
def _get_watched_fields(cls: type) -> list[str] | None:
|
|
71
|
+
"""Return the watched fields for *cls*, walking the MRO to inherit from parents."""
|
|
72
|
+
for klass in cls.__mro__:
|
|
73
|
+
if klass in _WATCHED_FIELDS:
|
|
74
|
+
return _WATCHED_FIELDS[klass]
|
|
75
|
+
return None
|
|
76
|
+
|
|
77
|
+
|
|
68
78
|
def _upsert_changes(
|
|
69
79
|
pending: dict[int, tuple[Any, dict[str, dict[str, Any]]]],
|
|
70
80
|
obj: Any,
|
|
@@ -83,6 +93,22 @@ def _upsert_changes(
|
|
|
83
93
|
pending[key] = (obj, changes)
|
|
84
94
|
|
|
85
95
|
|
|
96
|
+
@event.listens_for(AsyncSession.sync_session_class, "after_transaction_create")
|
|
97
|
+
def _after_transaction_create(session: Any, transaction: Any) -> None:
|
|
98
|
+
if transaction.nested:
|
|
99
|
+
session.info[_SESSION_SAVEPOINT_DEPTH] = (
|
|
100
|
+
session.info.get(_SESSION_SAVEPOINT_DEPTH, 0) + 1
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@event.listens_for(AsyncSession.sync_session_class, "after_transaction_end")
|
|
105
|
+
def _after_transaction_end(session: Any, transaction: Any) -> None:
|
|
106
|
+
if transaction.nested:
|
|
107
|
+
depth = session.info.get(_SESSION_SAVEPOINT_DEPTH, 0)
|
|
108
|
+
if depth > 0: # pragma: no branch
|
|
109
|
+
session.info[_SESSION_SAVEPOINT_DEPTH] = depth - 1
|
|
110
|
+
|
|
111
|
+
|
|
86
112
|
@event.listens_for(AsyncSession.sync_session_class, "after_flush")
|
|
87
113
|
def _after_flush(session: Any, flush_context: Any) -> None:
|
|
88
114
|
# New objects: capture references while session.new is still populated.
|
|
@@ -102,7 +128,7 @@ def _after_flush(session: Any, flush_context: Any) -> None:
|
|
|
102
128
|
continue
|
|
103
129
|
|
|
104
130
|
# None = not in dict = watch all fields; list = specific fields only
|
|
105
|
-
watched =
|
|
131
|
+
watched = _get_watched_fields(type(obj))
|
|
106
132
|
changes: dict[str, dict[str, Any]] = {}
|
|
107
133
|
|
|
108
134
|
attrs = (
|
|
@@ -169,7 +195,7 @@ def _schedule_with_snapshot(
|
|
|
169
195
|
_sa_set_committed_value(obj, key, value)
|
|
170
196
|
try:
|
|
171
197
|
result = fn(*args)
|
|
172
|
-
if
|
|
198
|
+
if inspect.isawaitable(result):
|
|
173
199
|
await result
|
|
174
200
|
except Exception as exc:
|
|
175
201
|
_logger.error(_CALLBACK_ERROR_MSG, exc_info=exc)
|
|
@@ -180,12 +206,24 @@ def _schedule_with_snapshot(
|
|
|
180
206
|
|
|
181
207
|
@event.listens_for(AsyncSession.sync_session_class, "after_commit")
|
|
182
208
|
def _after_commit(session: Any) -> None:
|
|
209
|
+
if session.info.get(_SESSION_SAVEPOINT_DEPTH, 0) > 0:
|
|
210
|
+
return
|
|
211
|
+
|
|
183
212
|
creates: list[Any] = session.info.pop(_SESSION_CREATES, [])
|
|
184
213
|
deletes: list[Any] = session.info.pop(_SESSION_DELETES, [])
|
|
185
214
|
field_changes: dict[int, tuple[Any, dict[str, dict[str, Any]]]] = session.info.pop(
|
|
186
215
|
_SESSION_UPDATES, {}
|
|
187
216
|
)
|
|
188
217
|
|
|
218
|
+
if creates and deletes:
|
|
219
|
+
transient_ids = {id(o) for o in creates} & {id(o) for o in deletes}
|
|
220
|
+
if transient_ids:
|
|
221
|
+
creates = [o for o in creates if id(o) not in transient_ids]
|
|
222
|
+
deletes = [o for o in deletes if id(o) not in transient_ids]
|
|
223
|
+
field_changes = {
|
|
224
|
+
k: v for k, v in field_changes.items() if k not in transient_ids
|
|
225
|
+
}
|
|
226
|
+
|
|
189
227
|
if not creates and not deletes and not field_changes:
|
|
190
228
|
return
|
|
191
229
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/commands/__init__.py
RENAMED
|
File without changes
|
{fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/cli/commands/fixtures.py
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
|
|
File without changes
|
{fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/exceptions/__init__.py
RENAMED
|
File without changes
|
{fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/exceptions/exceptions.py
RENAMED
|
File without changes
|
{fastapi_toolsets-2.4.1 → fastapi_toolsets-2.4.2}/src/fastapi_toolsets/exceptions/handler.py
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
|
|
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
|