Skip to content

Commit 3be0457

Browse files
committed
Roll back with_transaction abstraction back to context mgr
1 parent 2e805d9 commit 3be0457

File tree

4 files changed

+347
-342
lines changed

4 files changed

+347
-342
lines changed

mongoengine/connection.py

Lines changed: 0 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
"get_connection",
2626
"get_db",
2727
"register_connection",
28-
"run_in_transaction",
2928
]
3029

3130

@@ -508,55 +507,3 @@ def _get_session():
508507

509508
def _clear_session():
510509
return _local_sessions.clear_current()
511-
512-
513-
def run_in_transaction(
514-
callback,
515-
alias=DEFAULT_CONNECTION_NAME,
516-
session_kwargs=None,
517-
transaction_kwargs=None,
518-
):
519-
"""Execute queries within a MongoDB transaction.
520-
521-
Usage:
522-
523-
.. code-block:: python
524-
525-
class A(Document):
526-
name = StringField()
527-
528-
def callback(session):
529-
a_doc = A.objects.create(name="a")
530-
a_doc.update(name="b")
531-
run_in_transaction(callback)
532-
533-
# With custom args/kwargs
534-
def callback(session, custom_arg, customer_kwarg=None):
535-
a_doc.update(name=f'{custom_arg}-{custom_kwarg}')
536-
run_in_transaction(
537-
lambda s: callback(s, 'arg', custom_kwarg='kwarg')
538-
)
539-
540-
Be aware that:
541-
- Mongo transactions run inside a session which is bound to a connection. If you attempt to
542-
execute a transaction across a different connection alias, pymongo will raise an exception. In
543-
other words: you cannot create a transaction that crosses different database connections.
544-
545-
For more information regarding pymongo transactions: https://pymongo.readthedocs.io/en/stable/api/pymongo/client_session.html#transactions
546-
"""
547-
548-
if PYMONGO_VERSION < (3, 9):
549-
raise mongoengine.errors.OperationError(
550-
"pymongo>=3.9 is required to use transactions"
551-
)
552-
553-
conn = get_connection(alias)
554-
session_kwargs = session_kwargs or {}
555-
with conn.start_session(**session_kwargs) as session:
556-
transaction_kwargs = transaction_kwargs or {}
557-
transaction_kwargs["callback"] = callback
558-
_set_session(session)
559-
try:
560-
return session.with_transaction(**transaction_kwargs)
561-
finally:
562-
_clear_session()

mongoengine/context_managers.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
from mongoengine.common import _import_class
88
from mongoengine.connection import (
99
DEFAULT_CONNECTION_NAME,
10+
_clear_session,
1011
_get_session,
12+
_set_session,
13+
get_connection,
1114
get_db,
1215
)
1316
from mongoengine.pymongo_support import count_documents
@@ -21,6 +24,7 @@
2124
"set_write_concern",
2225
"set_read_write_concern",
2326
"no_dereferencing_active_for_class",
27+
"run_in_transaction",
2428
)
2529

2630

@@ -321,3 +325,41 @@ def set_read_write_concern(collection, write_concerns, read_concerns):
321325
write_concern=WriteConcern(**combined_write_concerns),
322326
read_concern=ReadConcern(**combined_read_concerns),
323327
)
328+
329+
330+
@contextmanager
331+
def run_in_transaction(
332+
alias=DEFAULT_CONNECTION_NAME, session_kwargs=None, transaction_kwargs=None
333+
):
334+
"""run_in_transaction context manager
335+
Execute queries within the context in a database transaction.
336+
337+
Usage:
338+
339+
.. code-block:: python
340+
341+
class A(Document):
342+
name = StringField()
343+
344+
with run_in_transaction():
345+
a_doc = A.objects.create(name="a")
346+
a_doc.update(name="b")
347+
348+
Be aware that:
349+
- Mongo transactions run inside a session which is bound to a connection. If you attempt to
350+
execute a transaction across a different connection alias, pymongo will raise an exception. In
351+
other words: you cannot create a transaction that crosses different database connections. That
352+
said, multiple transaction can be nested within the same session for particular connection.
353+
354+
For more information regarding pymongo transactions: https://pymongo.readthedocs.io/en/stable/api/pymongo/client_session.html#transactions
355+
"""
356+
conn = get_connection(alias)
357+
session_kwargs = session_kwargs or {}
358+
with conn.start_session(**session_kwargs) as session:
359+
transaction_kwargs = transaction_kwargs or {}
360+
with session.start_transaction(**transaction_kwargs):
361+
try:
362+
_set_session(session)
363+
yield
364+
finally:
365+
_clear_session()

0 commit comments

Comments
 (0)