From 8e17e42e26d944d90bdd16bfacb8d07879768055 Mon Sep 17 00:00:00 2001 From: Agustin Date: Fri, 24 Jan 2020 13:11:07 -0300 Subject: [PATCH 01/10] Allow setting read_concern --- mongoengine/context_managers.py | 8 ++++++ mongoengine/queryset/base.py | 31 +++++++++++++++++---- tests/queryset/test_queryset.py | 49 +++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 6 deletions(-) diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index 1592ceef..0f6c8698 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -257,3 +257,11 @@ def set_write_concern(collection, write_concerns): combined_concerns = dict(collection.write_concern.document.items()) combined_concerns.update(write_concerns) yield collection.with_options(write_concern=WriteConcern(**combined_concerns)) + + +@contextmanager +def set_read_write_concern(collection, write_concerns, read_concern): + combined_write_concerns = dict(collection.write_concern.document.items()) + combined_write_concerns.update(write_concerns) + + yield collection.with_options(write_concern=WriteConcern(**combined_write_concerns), read_concern=read_concern) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 50cb37ac..0b76235c 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -11,6 +11,7 @@ import pymongo import pymongo.errors from pymongo.collection import ReturnDocument from pymongo.common import validate_read_preference +from pymongo.read_concern import ReadConcern import six from six import iteritems @@ -18,7 +19,7 @@ from mongoengine import signals from mongoengine.base import get_document from mongoengine.common import _import_class from mongoengine.connection import get_db -from mongoengine.context_managers import set_write_concern, switch_db +from mongoengine.context_managers import set_write_concern, set_read_write_concern, switch_db from mongoengine.errors import ( BulkWriteError, InvalidQueryError, @@ -62,6 +63,7 @@ class BaseQuerySet(object): self._timeout = True self._slave_okay = False self._read_preference = None + self._read_concern = None self._iter = False self._scalar = [] self._none = False @@ -490,7 +492,7 @@ class BaseQuerySet(object): return result.deleted_count def update( - self, upsert=False, multi=True, write_concern=None, full_result=False, **update + self, upsert=False, multi=True, write_concern=None, read_concern=None, full_result=False, **update ): """Perform an atomic update on the fields matched by the query. @@ -502,6 +504,7 @@ class BaseQuerySet(object): ``save(..., write_concern={w: 2, fsync: True}, ...)`` will wait until at least two servers have recorded the write and will force an fsync on the primary server. + :param read_concern: Override the read concern for the operation :param full_result: Return the associated ``pymongo.UpdateResult`` rather than just the number updated items :param update: Django-style update keyword arguments @@ -528,7 +531,7 @@ class BaseQuerySet(object): else: update["$set"] = {"_cls": queryset._document._class_name} try: - with set_write_concern(queryset._collection, write_concern) as collection: + with set_read_write_concern(queryset._collection, write_concern, read_concern) as collection: update_func = collection.update_one if multi: update_func = collection.update_many @@ -545,7 +548,7 @@ class BaseQuerySet(object): raise OperationError(message) raise OperationError(u"Update failed (%s)" % six.text_type(err)) - def upsert_one(self, write_concern=None, **update): + def upsert_one(self, write_concern=None, read_concern=None, **update): """Overwrite or add the first document matched by the query. :param write_concern: Extra keyword arguments are passed down which @@ -554,6 +557,7 @@ class BaseQuerySet(object): ``save(..., write_concern={w: 2, fsync: True}, ...)`` will wait until at least two servers have recorded the write and will force an fsync on the primary server. + :param read_concern: Override the read concern for the operation :param update: Django-style update keyword arguments :returns the new or overwritten document @@ -565,6 +569,7 @@ class BaseQuerySet(object): multi=False, upsert=True, write_concern=write_concern, + read_concern=read_concern, full_result=True, **update ) @@ -1196,6 +1201,20 @@ class BaseQuerySet(object): queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_preference return queryset + def read_concern(self, read_concern): + """Change the read_concern when querying. + + :param read_concern: override ReplicaSetConnection-level + preference. + """ + if read_concern is not None and not isinstance(read_concern, ReadConcern): + raise TypeError("%r is not a read concern." % (read_concern,)) + + queryset = self.clone() + queryset._read_concern = read_concern + queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_concern + return queryset + def scalar(self, *fields): """Instead of returning Document instances, return either a specific value or a tuple of values in order. @@ -1642,9 +1661,9 @@ class BaseQuerySet(object): # XXX In PyMongo 3+, we define the read preference on a collection # level, not a cursor level. Thus, we need to get a cloned collection # object using `with_options` first. - if self._read_preference is not None: + if self._read_preference is not None or self._read_concern is not None: self._cursor_obj = self._collection.with_options( - read_preference=self._read_preference + read_preference=self._read_preference, read_concern=self._read_concern ).find(self._query, **self._cursor_args) else: self._cursor_obj = self._collection.find(self._query, **self._cursor_args) diff --git a/tests/queryset/test_queryset.py b/tests/queryset/test_queryset.py index b30350e6..c238752d 100644 --- a/tests/queryset/test_queryset.py +++ b/tests/queryset/test_queryset.py @@ -7,6 +7,7 @@ from decimal import Decimal from bson import DBRef, ObjectId import pymongo +from pymongo.read_concern import ReadConcern from pymongo.read_preferences import ReadPreference from pymongo.results import UpdateResult import pytest @@ -4658,6 +4659,54 @@ class TestQueryset(unittest.TestCase): ) assert_read_pref(bars, ReadPreference.SECONDARY_PREFERRED) + def test_read_concern(self): + class Bar(Document): + txt = StringField() + + meta = {"indexes": ["txt"]} + + Bar.drop_collection() + bar = Bar.objects.create(txt="xyz") + + bars = list(Bar.objects.read_concern(None)) + assert bars == [bar] + + bars = Bar.objects.read_concern(ReadConcern(level='local')) + assert bars._read_concern == ReadConcern(level='local') + assert ( + bars._cursor.collection.read_concern + == ReadConcern(level='local') + ) + + # Make sure that `.read_concern(...)` does accept string values. + with pytest.raises(TypeError): + Bar.objects.read_concern('local') + + def assert_read_concern(qs, expected_read_concern): + assert qs._read_concern == expected_read_concern + assert qs._cursor.collection.read_concern == expected_read_concern + + # Make sure read concern is respected after a `.skip(...)`. + bars = Bar.objects.skip(1).read_concern(ReadConcern('majority')) + assert_read_concern(bars, ReadConcern('majority')) + + # Make sure read concern is respected after a `.limit(...)`. + bars = Bar.objects.limit(1).read_concern(ReadConcern('majority')) + assert_read_concern(bars, ReadConcern('majority')) + + # Make sure read concern is respected after an `.order_by(...)`. + bars = Bar.objects.order_by("txt").read_concern( + ReadConcern('majority') + ) + assert_read_concern(bars, ReadConcern('majority')) + + # Make sure read concern is respected after a `.hint(...)`. + bars = Bar.objects.hint([("txt", 1)]).read_concern( + ReadConcern('majority') + ) + assert_read_concern(bars, ReadConcern('majority')) + + def test_json_simple(self): class Embedded(EmbeddedDocument): string = StringField() From ff4d57032ad366fb766b9625ead6df66bd989675 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Tue, 3 Mar 2020 23:51:11 +0100 Subject: [PATCH 02/10] reformat w black --- mongoengine/context_managers.py | 4 +++- mongoengine/queryset/base.py | 20 ++++++++++++++++---- tests/queryset/test_queryset.py | 32 ++++++++++++-------------------- 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index 0f6c8698..0c58b57c 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -264,4 +264,6 @@ def set_read_write_concern(collection, write_concerns, read_concern): combined_write_concerns = dict(collection.write_concern.document.items()) combined_write_concerns.update(write_concerns) - yield collection.with_options(write_concern=WriteConcern(**combined_write_concerns), read_concern=read_concern) + yield collection.with_options( + write_concern=WriteConcern(**combined_write_concerns), read_concern=read_concern + ) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 0b76235c..0743429c 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -19,7 +19,11 @@ from mongoengine import signals from mongoengine.base import get_document from mongoengine.common import _import_class from mongoengine.connection import get_db -from mongoengine.context_managers import set_write_concern, set_read_write_concern, switch_db +from mongoengine.context_managers import ( + set_write_concern, + set_read_write_concern, + switch_db, +) from mongoengine.errors import ( BulkWriteError, InvalidQueryError, @@ -492,7 +496,13 @@ class BaseQuerySet(object): return result.deleted_count def update( - self, upsert=False, multi=True, write_concern=None, read_concern=None, full_result=False, **update + self, + upsert=False, + multi=True, + write_concern=None, + read_concern=None, + full_result=False, + **update ): """Perform an atomic update on the fields matched by the query. @@ -531,7 +541,9 @@ class BaseQuerySet(object): else: update["$set"] = {"_cls": queryset._document._class_name} try: - with set_read_write_concern(queryset._collection, write_concern, read_concern) as collection: + with set_read_write_concern( + queryset._collection, write_concern, read_concern + ) as collection: update_func = collection.update_one if multi: update_func = collection.update_many @@ -1214,7 +1226,7 @@ class BaseQuerySet(object): queryset._read_concern = read_concern queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_concern return queryset - + def scalar(self, *fields): """Instead of returning Document instances, return either a specific value or a tuple of values in order. diff --git a/tests/queryset/test_queryset.py b/tests/queryset/test_queryset.py index c238752d..708033f4 100644 --- a/tests/queryset/test_queryset.py +++ b/tests/queryset/test_queryset.py @@ -4671,41 +4671,33 @@ class TestQueryset(unittest.TestCase): bars = list(Bar.objects.read_concern(None)) assert bars == [bar] - bars = Bar.objects.read_concern(ReadConcern(level='local')) - assert bars._read_concern == ReadConcern(level='local') - assert ( - bars._cursor.collection.read_concern - == ReadConcern(level='local') - ) + bars = Bar.objects.read_concern(ReadConcern(level="local")) + assert bars._read_concern == ReadConcern(level="local") + assert bars._cursor.collection.read_concern == ReadConcern(level="local") # Make sure that `.read_concern(...)` does accept string values. with pytest.raises(TypeError): - Bar.objects.read_concern('local') + Bar.objects.read_concern("local") def assert_read_concern(qs, expected_read_concern): assert qs._read_concern == expected_read_concern assert qs._cursor.collection.read_concern == expected_read_concern # Make sure read concern is respected after a `.skip(...)`. - bars = Bar.objects.skip(1).read_concern(ReadConcern('majority')) - assert_read_concern(bars, ReadConcern('majority')) + bars = Bar.objects.skip(1).read_concern(ReadConcern("majority")) + assert_read_concern(bars, ReadConcern("majority")) # Make sure read concern is respected after a `.limit(...)`. - bars = Bar.objects.limit(1).read_concern(ReadConcern('majority')) - assert_read_concern(bars, ReadConcern('majority')) + bars = Bar.objects.limit(1).read_concern(ReadConcern("majority")) + assert_read_concern(bars, ReadConcern("majority")) # Make sure read concern is respected after an `.order_by(...)`. - bars = Bar.objects.order_by("txt").read_concern( - ReadConcern('majority') - ) - assert_read_concern(bars, ReadConcern('majority')) + bars = Bar.objects.order_by("txt").read_concern(ReadConcern("majority")) + assert_read_concern(bars, ReadConcern("majority")) # Make sure read concern is respected after a `.hint(...)`. - bars = Bar.objects.hint([("txt", 1)]).read_concern( - ReadConcern('majority') - ) - assert_read_concern(bars, ReadConcern('majority')) - + bars = Bar.objects.hint([("txt", 1)]).read_concern(ReadConcern("majority")) + assert_read_concern(bars, ReadConcern("majority")) def test_json_simple(self): class Embedded(EmbeddedDocument): From a3f9016ae938a91871657373ade2970a0fc157d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Sun, 15 Mar 2020 22:27:19 +0100 Subject: [PATCH 03/10] reformat import for flake8 --- mongoengine/context_managers.py | 1 + mongoengine/queryset/base.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index 0c58b57c..6891e21d 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -14,6 +14,7 @@ __all__ = ( "no_sub_classes", "query_counter", "set_write_concern", + "set_read_write_concern", ) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 0788f563..d8a4b96f 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -20,8 +20,8 @@ from mongoengine.base import get_document from mongoengine.common import _import_class from mongoengine.connection import get_db from mongoengine.context_managers import ( - set_write_concern, set_read_write_concern, + set_write_concern, switch_db, ) from mongoengine.errors import ( From 3d80637fa414354b2d05b0ca6ac3afb71222d8f1 Mon Sep 17 00:00:00 2001 From: Agustin Barto Date: Tue, 17 Mar 2020 19:08:43 -0300 Subject: [PATCH 04/10] Refactor set_read_write_concern so read_conern is consistent with the write_concerns argument. --- mongoengine/context_managers.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index 6891e21d..a87c9bb3 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -261,10 +261,14 @@ def set_write_concern(collection, write_concerns): @contextmanager -def set_read_write_concern(collection, write_concerns, read_concern): +def set_read_write_concern(collection, write_concerns, read_concerns): combined_write_concerns = dict(collection.write_concern.document.items()) combined_write_concerns.update(write_concerns) + combined_read_concerns = dict(collection.read_concern.document.items()) + combined_read_concerns.update(read_concerns) + yield collection.with_options( - write_concern=WriteConcern(**combined_write_concerns), read_concern=read_concern + write_concern=WriteConcern(**combined_write_concerns), + read_concern=ReadConcern(**combined_read_concerns) ) From 4c62a060f0c460b1d68ebba861eb7a3fd9f9e14c Mon Sep 17 00:00:00 2001 From: Agustin Barto Date: Tue, 17 Mar 2020 19:37:21 -0300 Subject: [PATCH 05/10] Add tests for set_write_conern and set_read_write_concern --- tests/test_context_managers.py | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/test_context_managers.py b/tests/test_context_managers.py index fa3f5960..f445cf57 100644 --- a/tests/test_context_managers.py +++ b/tests/test_context_managers.py @@ -10,11 +10,59 @@ from mongoengine.context_managers import ( query_counter, switch_collection, switch_db, + set_write_concern, + set_read_write_concern, ) from mongoengine.pymongo_support import count_documents class TestContextManagers: + def test_set_write_concern(self): + connect("mongoenginetest") + + class User(Document): + name = StringField() + + collection = User._get_collection() + original_write_concern = collection.write_concern + + with set_write_concern( + collection, {"w": "majority", "j": True, "wtimeout": 1234} + ) as updated_collection: + assert updated_collection.write_concern.document == { + "w": "majority", + "j": True, + "wtimeout": 1234, + } + + assert original_write_concern.document == collection.write_concern.document + + def test_set_read_write_concern(self): + connect("mongoenginetest") + + class User(Document): + name = StringField() + + collection = User._get_collection() + + original_read_concern = collection.read_concern + original_write_concern = collection.write_concern + + with set_read_write_concern( + collection, + {"w": "majority", "j": True, "wtimeout": 1234}, + {"level": "local"}, + ) as update_collection: + assert update_collection.read_concern.document == {"level": "local"} + assert update_collection.write_concern.document == { + "w": "majority", + "j": True, + "wtimeout": 1234, + } + + assert original_read_concern.document == collection.read_concern.document + assert original_write_concern.document == collection.write_concern.document + def test_switch_db_context_manager(self): connect("mongoenginetest") register_connection("testdb-1", "mongoenginetest2") From af35b25d155e050cba3e4925bf76529f7ae52137 Mon Sep 17 00:00:00 2001 From: Agustin Barto Date: Tue, 17 Mar 2020 21:28:08 -0300 Subject: [PATCH 06/10] Refactor read_preference to accept a dictionary instead of a ReadPreference instance. --- mongoengine/queryset/base.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index d8a4b96f..f8671f8f 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -5,6 +5,8 @@ import itertools import re import warnings +from collections.abc import Mapping + from bson import SON, json_util from bson.code import Code import pymongo @@ -1221,11 +1223,11 @@ class BaseQuerySet(object): :param read_concern: override ReplicaSetConnection-level preference. """ - if read_concern is not None and not isinstance(read_concern, ReadConcern): - raise TypeError("%r is not a read concern." % (read_concern,)) + if read_concern is not None and not isinstance(read_concern, Mapping): + raise TypeError("%r is not a valid read concern." % (read_concern,)) queryset = self.clone() - queryset._read_concern = read_concern + queryset._read_concern = ReadConcern(**read_concern) queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_concern return queryset From 8913a74a86e01c3a96aaebf3372b1898c4efe060 Mon Sep 17 00:00:00 2001 From: Agustin Barto Date: Tue, 17 Mar 2020 21:31:05 -0300 Subject: [PATCH 07/10] Allow setting the read concern to None --- mongoengine/queryset/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index f8671f8f..76427c89 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -1227,7 +1227,7 @@ class BaseQuerySet(object): raise TypeError("%r is not a valid read concern." % (read_concern,)) queryset = self.clone() - queryset._read_concern = ReadConcern(**read_concern) + queryset._read_concern = ReadConcern(**read_concern) if read_concern is not None else None queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_concern return queryset From bc77322c2f166e28390e1492a5a67440f90af021 Mon Sep 17 00:00:00 2001 From: Agustin Barto Date: Tue, 17 Mar 2020 21:49:17 -0300 Subject: [PATCH 08/10] Update unit tests --- tests/queryset/test_queryset.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/queryset/test_queryset.py b/tests/queryset/test_queryset.py index 8098b137..a8954526 100644 --- a/tests/queryset/test_queryset.py +++ b/tests/queryset/test_queryset.py @@ -4739,33 +4739,33 @@ class TestQueryset(unittest.TestCase): bars = list(Bar.objects.read_concern(None)) assert bars == [bar] - bars = Bar.objects.read_concern(ReadConcern(level="local")) - assert bars._read_concern == ReadConcern(level="local") - assert bars._cursor.collection.read_concern == ReadConcern(level="local") + bars = Bar.objects.read_concern({"level": "local"}) + assert bars._read_concern.document == {"level": "local"} + assert bars._cursor.collection.read_concern.document == {"level": "local"} - # Make sure that `.read_concern(...)` does accept string values. + # Make sure that `.read_concern(...)` does not accept string values. with pytest.raises(TypeError): Bar.objects.read_concern("local") def assert_read_concern(qs, expected_read_concern): - assert qs._read_concern == expected_read_concern - assert qs._cursor.collection.read_concern == expected_read_concern + assert qs._read_concern.document == expected_read_concern + assert qs._cursor.collection.read_concern.document == expected_read_concern # Make sure read concern is respected after a `.skip(...)`. - bars = Bar.objects.skip(1).read_concern(ReadConcern("majority")) - assert_read_concern(bars, ReadConcern("majority")) + bars = Bar.objects.skip(1).read_concern({"level": "local"}) + assert_read_concern(bars, {"level": "local"}) # Make sure read concern is respected after a `.limit(...)`. - bars = Bar.objects.limit(1).read_concern(ReadConcern("majority")) - assert_read_concern(bars, ReadConcern("majority")) + bars = Bar.objects.limit(1).read_concern({"level": "local"}) + assert_read_concern(bars, {"level": "local"}) # Make sure read concern is respected after an `.order_by(...)`. - bars = Bar.objects.order_by("txt").read_concern(ReadConcern("majority")) - assert_read_concern(bars, ReadConcern("majority")) + bars = Bar.objects.order_by("txt").read_concern({"level": "local"}) + assert_read_concern(bars, {"level": "local"}) # Make sure read concern is respected after a `.hint(...)`. - bars = Bar.objects.hint([("txt", 1)]).read_concern(ReadConcern("majority")) - assert_read_concern(bars, ReadConcern("majority")) + bars = Bar.objects.hint([("txt", 1)]).read_concern({"level": "majority"}) + assert_read_concern(bars, {"level": "majority"}) def test_json_simple(self): class Embedded(EmbeddedDocument): From 7cc964c7d86d9e6dccf4f819ad291a4150b1d1ee Mon Sep 17 00:00:00 2001 From: Agustin Barto Date: Tue, 17 Mar 2020 21:58:36 -0300 Subject: [PATCH 09/10] Add missing import --- mongoengine/context_managers.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index a87c9bb3..9319abae 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -1,6 +1,7 @@ from contextlib import contextmanager from pymongo.write_concern import WriteConcern +from pymongo.read_concern import ReadConcern from six import iteritems from mongoengine.common import _import_class @@ -263,10 +264,14 @@ def set_write_concern(collection, write_concerns): @contextmanager def set_read_write_concern(collection, write_concerns, read_concerns): combined_write_concerns = dict(collection.write_concern.document.items()) - combined_write_concerns.update(write_concerns) + + if write_concerns is not None: + combined_write_concerns.update(write_concerns) combined_read_concerns = dict(collection.read_concern.document.items()) - combined_read_concerns.update(read_concerns) + + if read_concerns is not None: + combined_read_concerns.update(read_concerns) yield collection.with_options( write_concern=WriteConcern(**combined_write_concerns), From 78c9e9745d82dff40c0c4e0c5931c4ae557f6374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastien=20G=C3=A9rard?= Date: Sun, 26 Apr 2020 22:51:56 +0200 Subject: [PATCH 10/10] fix linting + update changelog & contributors --- AUTHORS | 1 + docs/changelog.rst | 1 + mongoengine/context_managers.py | 6 +++--- mongoengine/queryset/base.py | 4 +++- tests/test_context_managers.py | 4 ++-- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/AUTHORS b/AUTHORS index 7d3000ce..02e43955 100644 --- a/AUTHORS +++ b/AUTHORS @@ -256,3 +256,4 @@ that much better: * Eric Timmons (https://github.com/daewok) * Matthew Simpson (https://github.com/mcsimps2) * Leonardo Domingues (https://github.com/leodmgs) + * Agustin Barto (https://github.com/abarto) diff --git a/docs/changelog.rst b/docs/changelog.rst index 76545559..625526a3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -21,6 +21,7 @@ Development - ``Queryset._ensure_indexes`` and ``Queryset.ensure_indexes``, the right method to use is ``Document.ensure_indexes`` - Added pre-commit #2212 - Renamed requirements-lint.txt to requirements-dev.txt #2212 +- Support for setting ReadConcern #2255 Changes in 0.19.1 ================= diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index 77e6b55c..5f2b5229 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -1,7 +1,7 @@ from contextlib import contextmanager -from pymongo.write_concern import WriteConcern from pymongo.read_concern import ReadConcern +from pymongo.write_concern import WriteConcern from mongoengine.common import _import_class from mongoengine.connection import DEFAULT_CONNECTION_NAME, get_db @@ -268,11 +268,11 @@ def set_read_write_concern(collection, write_concerns, read_concerns): combined_write_concerns.update(write_concerns) combined_read_concerns = dict(collection.read_concern.document.items()) - + if read_concerns is not None: combined_read_concerns.update(read_concerns) yield collection.with_options( write_concern=WriteConcern(**combined_write_concerns), - read_concern=ReadConcern(**combined_read_concerns) + read_concern=ReadConcern(**combined_read_concerns), ) diff --git a/mongoengine/queryset/base.py b/mongoengine/queryset/base.py index 317ec698..39c44b29 100644 --- a/mongoengine/queryset/base.py +++ b/mongoengine/queryset/base.py @@ -1206,7 +1206,9 @@ class BaseQuerySet: raise TypeError("%r is not a valid read concern." % (read_concern,)) queryset = self.clone() - queryset._read_concern = ReadConcern(**read_concern) if read_concern is not None else None + queryset._read_concern = ( + ReadConcern(**read_concern) if read_concern is not None else None + ) queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_concern return queryset diff --git a/tests/test_context_managers.py b/tests/test_context_managers.py index 8f3dd555..a4864c40 100644 --- a/tests/test_context_managers.py +++ b/tests/test_context_managers.py @@ -8,10 +8,10 @@ from mongoengine.context_managers import ( no_dereference, no_sub_classes, query_counter, + set_read_write_concern, + set_write_concern, switch_collection, switch_db, - set_write_concern, - set_read_write_concern, ) from mongoengine.pymongo_support import count_documents