python-general-be-lib 0.12.0__py3-none-any.whl → 0.12.1__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.
- general/interface/repository/crud_repository.py +28 -12
- {python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/METADATA +1 -1
- {python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/RECORD +6 -6
- {python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/WHEEL +1 -1
- {python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/licenses/LICENSE +0 -0
- {python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/top_level.txt +0 -0
|
@@ -169,14 +169,23 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
169
169
|
return _reduced_model(self.entity, frozenset(selected_columns))
|
|
170
170
|
|
|
171
171
|
def _handle_exception(self, session: Session, e: Exception):
|
|
172
|
-
"""
|
|
172
|
+
"""Roll back and close the session, log the error and raise an HTTP-friendly exception.
|
|
173
173
|
|
|
174
174
|
An ``OperationalError`` becomes a ``ServiceUnavailableException``, a
|
|
175
175
|
``NoResultFound`` an ``EntityNotFoundException``, a ``DataError`` or an
|
|
176
176
|
``IntegrityError`` a ``BadRequestException``; any other exception is re-raised as is.
|
|
177
177
|
|
|
178
|
+
``close`` alone already rolls back the database transaction. What the explicit
|
|
179
|
+
``rollback`` adds is the expiry of the ORM instances: an entity still held by the
|
|
180
|
+
caller raises ``DetachedInstanceError`` on access instead of exposing values that
|
|
181
|
+
were flushed but never committed. It runs on every error, a failed SELECT included,
|
|
182
|
+
since on PostgreSQL that aborts the transaction as well. An external session is
|
|
183
|
+
rolled back and closed too, so the caller's transaction is lost. A failure of the
|
|
184
|
+
rollback itself is logged and does not replace ``e``, and the session is closed
|
|
185
|
+
anyway.
|
|
186
|
+
|
|
178
187
|
Args:
|
|
179
|
-
session (Session): Session to close.
|
|
188
|
+
session (Session): Session to roll back and close.
|
|
180
189
|
e (Exception): Caught exception to handle.
|
|
181
190
|
|
|
182
191
|
Raises:
|
|
@@ -184,6 +193,11 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
184
193
|
EntityNotFoundException: If no record matches.
|
|
185
194
|
BadRequestException: If the data is malformed or violates a constraint.
|
|
186
195
|
"""
|
|
196
|
+
try:
|
|
197
|
+
session.rollback()
|
|
198
|
+
except Exception:
|
|
199
|
+
# un rollback fallito non deve sostituire l'errore originale, né saltare la close
|
|
200
|
+
logging.exception("Rollback failed")
|
|
187
201
|
session.close()
|
|
188
202
|
logging.error(e)
|
|
189
203
|
raise_http_exception(e)
|
|
@@ -195,12 +209,13 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
195
209
|
session (Session): Session to commit.
|
|
196
210
|
|
|
197
211
|
Raises:
|
|
198
|
-
ServiceUnavailableException | BadRequestException: On error during the commit
|
|
212
|
+
ServiceUnavailableException | BadRequestException: On error during the commit,
|
|
213
|
+
after rolling back and closing the session.
|
|
199
214
|
"""
|
|
200
215
|
try:
|
|
201
216
|
session.commit()
|
|
202
217
|
except Exception as e:
|
|
203
|
-
self._handle_exception(session, e)
|
|
218
|
+
self._handle_exception(session=session, e=e)
|
|
204
219
|
|
|
205
220
|
def _flush(self, session: Session):
|
|
206
221
|
"""Flush the session, handling the possible exceptions.
|
|
@@ -214,12 +229,13 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
214
229
|
session (Session): Session to flush.
|
|
215
230
|
|
|
216
231
|
Raises:
|
|
217
|
-
ServiceUnavailableException | BadRequestException: On error during the flush
|
|
232
|
+
ServiceUnavailableException | BadRequestException: On error during the flush,
|
|
233
|
+
after rolling back and closing the session.
|
|
218
234
|
"""
|
|
219
235
|
try:
|
|
220
236
|
session.flush()
|
|
221
237
|
except Exception as e:
|
|
222
|
-
self._handle_exception(session, e)
|
|
238
|
+
self._handle_exception(session=session, e=e)
|
|
223
239
|
|
|
224
240
|
def _entity_has_columns(self, *columns: str, entity: Type[Base] | Base = None) -> bool:
|
|
225
241
|
"""Check that every given name is a column of the entity.
|
|
@@ -441,7 +457,7 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
441
457
|
try:
|
|
442
458
|
entity = session.get(self.entity, values)
|
|
443
459
|
except Exception as e:
|
|
444
|
-
self._handle_exception(session, e)
|
|
460
|
+
self._handle_exception(session=session, e=e)
|
|
445
461
|
else:
|
|
446
462
|
return [entity] if entity is not None else []
|
|
447
463
|
|
|
@@ -607,7 +623,7 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
607
623
|
try:
|
|
608
624
|
session.add_all(entities)
|
|
609
625
|
except Exception as e:
|
|
610
|
-
self._handle_exception(session, e)
|
|
626
|
+
self._handle_exception(session=session, e=e)
|
|
611
627
|
return self._return(session=session, entities=entities, keep_open=keep_open, commit=True, parsing_model=parsing_model)
|
|
612
628
|
|
|
613
629
|
def update(self, session: Session = None, where: dict[str, Any] = None, returning: bool = True, parsing_model: Type[BaseModel] | BaseModel = None, **kwargs) -> list[Entity] | list[BaseModel]:
|
|
@@ -1049,9 +1065,9 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
1049
1065
|
"""Execute a SQLAlchemy statement and return the result as it is.
|
|
1050
1066
|
|
|
1051
1067
|
The method owns the error handling and nothing else: every exception goes to
|
|
1052
|
-
``_handle_exception``, which closes the session and maps the error
|
|
1053
|
-
status. Reading the result is left to the caller, which is the only one
|
|
1054
|
-
shape it needs — ``.scalars().all()`` for entities, ``.scalar()`` for an aggregate,
|
|
1068
|
+
``_handle_exception``, which rolls back and closes the session and maps the error
|
|
1069
|
+
to an HTTP status. Reading the result is left to the caller, which is the only one
|
|
1070
|
+
knowing the shape it needs — ``.scalars().all()`` for entities, ``.scalar()`` for an aggregate,
|
|
1055
1071
|
``.all()`` for the multi-column rows of a statement built with ``add_columns``,
|
|
1056
1072
|
``.rowcount`` for a DML without ``RETURNING``. The result is bound to the session,
|
|
1057
1073
|
so it has to be consumed before the session is closed. ``Session.execute`` returns
|
|
@@ -1076,6 +1092,6 @@ class CrudRepository[Entity: Base | Type[Base]]:
|
|
|
1076
1092
|
try:
|
|
1077
1093
|
result = session.execute(statement=stmt, params=values)
|
|
1078
1094
|
except Exception as e:
|
|
1079
|
-
self._handle_exception(session, e)
|
|
1095
|
+
self._handle_exception(session=session, e=e)
|
|
1080
1096
|
else:
|
|
1081
1097
|
return result
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-general-be-lib
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.1
|
|
4
4
|
Summary: General purpose backend library — SQLAlchemy CRUD/Geometry repositories, FastAPI exceptions, Pydantic base models, Keycloak JWT auth, logger utilities.
|
|
5
5
|
Author-email: Andrea Di Placido <a.diplacido@arpes.it>, "Arpes S.r.l." <it.admin@arpes.it>
|
|
6
6
|
License: MIT
|
|
@@ -24,7 +24,7 @@ general/interface/mixin/audit_mixin.py,sha256=N2JDD9JxXDMeBqu0yAlhVWFOK3EeUA2b21
|
|
|
24
24
|
general/interface/mixin/softdelete_mixin.py,sha256=526luzM4DBCorcq99kZ6BYqtQKKJCpnxX9rSEigfyIU,2148
|
|
25
25
|
general/interface/mixin/timestamp_mixin.py,sha256=wmcIx2Y8jgVqg9A-1E61BvkcKCo52ZjKNHeKfXJmUl0,2220
|
|
26
26
|
general/interface/repository/__init__.py,sha256=QQD6okLfRozC0uOZPGrwOUDKJyZTgpObvwJ3OOSJdbM,1813
|
|
27
|
-
general/interface/repository/crud_repository.py,sha256=
|
|
27
|
+
general/interface/repository/crud_repository.py,sha256=Z7IgLz7dtfIyzZMJO7T_IDunHH1qTDYRApdWlbMkE2A,57031
|
|
28
28
|
general/interface/repository/geometry_repository.py,sha256=Fmv0qhfqumnU5fiETMMAmiB0UyG43b19jlPXQ8cJ9CU,11289
|
|
29
29
|
general/interface/repository/many_to_many_repository.py,sha256=KRJ2SMUGDYNoGV-ea541wlWg0FW4NQ_Ry85aJBarmC8,11183
|
|
30
30
|
general/interface/repository/view_repository.py,sha256=wxDGw7kenuVrDd9nfh7-omw2m9Jex5WzF_lhEiqPoA0,7902
|
|
@@ -40,8 +40,8 @@ general/interface/repository/handler/soft_delete_handler.py,sha256=1WD1n6q5plyJ0
|
|
|
40
40
|
general/interface/repository/handler/statement_manager.py,sha256=JSj6K-iQJ06kLdsMTOqK62cIvR87ioOA1LmLTGpqrB0,8205
|
|
41
41
|
general/utils/__init__.py,sha256=_SPe88reIZ0JxwK7mp-u_p-9c4hCcZ-daUihi0gymNk,103
|
|
42
42
|
general/utils/consts.py,sha256=nE75Ud7sVuDw9K_xmIJNjL_5f_BVJmwGNPGFYc26H3Y,264
|
|
43
|
-
python_general_be_lib-0.12.
|
|
44
|
-
python_general_be_lib-0.12.
|
|
45
|
-
python_general_be_lib-0.12.
|
|
46
|
-
python_general_be_lib-0.12.
|
|
47
|
-
python_general_be_lib-0.12.
|
|
43
|
+
python_general_be_lib-0.12.1.dist-info/licenses/LICENSE,sha256=iUaO1XZyB9P3Tmog0OILuTisP6vXGe3QKz-4yRTxOFk,1069
|
|
44
|
+
python_general_be_lib-0.12.1.dist-info/METADATA,sha256=8T5p8u9J9MUHT1xZjRf_Ss29Y97hEeJX5wZD71aVTyI,3995
|
|
45
|
+
python_general_be_lib-0.12.1.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
|
|
46
|
+
python_general_be_lib-0.12.1.dist-info/top_level.txt,sha256=tTZePW8_CNUqSgKFd2SEH72ZbnhS0OYjRsgcv0ikSFY,8
|
|
47
|
+
python_general_be_lib-0.12.1.dist-info/RECORD,,
|
{python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{python_general_be_lib-0.12.0.dist-info → python_general_be_lib-0.12.1.dist-info}/top_level.txt
RENAMED
|
File without changes
|