Skip to content

Commit 2c1a160

Browse files
PYTHON-5169 - Deprecate Hedged Reads option (#2213)
Co-authored-by: Shane Harvey <[email protected]>
1 parent eea8a37 commit 2c1a160

File tree

4 files changed

+98
-53
lines changed

4 files changed

+98
-53
lines changed

doc/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ PyMongo 4.12 brings a number of changes including:
1414
- Added index hinting support to the
1515
:meth:`~pymongo.asynchronous.collection.AsyncCollection.distinct` and
1616
:meth:`~pymongo.collection.Collection.distinct` commands.
17+
- Deprecated the ``hedge`` parameter for
18+
:class:`~pymongo.read_preferences.PrimaryPreferred`,
19+
:class:`~pymongo.read_preferences.Secondary`,
20+
:class:`~pymongo.read_preferences.SecondaryPreferred`,
21+
:class:`~pymongo.read_preferences.Nearest`. Support for ``hedge`` will be removed in PyMongo 5.0.
1722

1823
Issues Resolved
1924
...............

pymongo/read_preferences.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from __future__ import annotations
2121

22+
import warnings
2223
from collections import abc
2324
from typing import TYPE_CHECKING, Any, Mapping, Optional, Sequence
2425

@@ -103,6 +104,11 @@ def _validate_hedge(hedge: Optional[_Hedge]) -> Optional[_Hedge]:
103104
if not isinstance(hedge, dict):
104105
raise TypeError(f"hedge must be a dictionary, not {hedge!r}")
105106

107+
warnings.warn(
108+
"The read preference 'hedge' option is deprecated in PyMongo 4.12+ because hedged reads are deprecated in MongoDB version 8.0+. Support for 'hedge' will be removed in PyMongo 5.0.",
109+
DeprecationWarning,
110+
stacklevel=4,
111+
)
106112
return hedge
107113

108114

@@ -183,7 +189,9 @@ def max_staleness(self) -> int:
183189

184190
@property
185191
def hedge(self) -> Optional[_Hedge]:
186-
"""The read preference ``hedge`` parameter.
192+
"""**DEPRECATED** - The read preference 'hedge' option is deprecated in PyMongo 4.12+ because hedged reads are deprecated in MongoDB version 8.0+. Support for 'hedge' will be removed in PyMongo 5.0.
193+
194+
The read preference ``hedge`` parameter.
187195
188196
A dictionary that configures how the server will perform hedged reads.
189197
It consists of the following keys:
@@ -203,6 +211,12 @@ def hedge(self) -> Optional[_Hedge]:
203211
204212
.. versionadded:: 3.11
205213
"""
214+
if self.__hedge is not None:
215+
warnings.warn(
216+
"The read preference 'hedge' option is deprecated in PyMongo 4.12+ because hedged reads are deprecated in MongoDB version 8.0+. Support for 'hedge' will be removed in PyMongo 5.0.",
217+
DeprecationWarning,
218+
stacklevel=2,
219+
)
206220
return self.__hedge
207221

208222
@property
@@ -312,7 +326,7 @@ class PrimaryPreferred(_ServerMode):
312326
replication before it will no longer be selected for operations.
313327
Default -1, meaning no maximum. If it is set, it must be at least
314328
90 seconds.
315-
:param hedge: The :attr:`~hedge` to use if the primary is not available.
329+
:param hedge: **DEPRECATED** - The :attr:`~hedge` for this read preference.
316330
317331
.. versionchanged:: 3.11
318332
Added ``hedge`` parameter.
@@ -354,7 +368,7 @@ class Secondary(_ServerMode):
354368
replication before it will no longer be selected for operations.
355369
Default -1, meaning no maximum. If it is set, it must be at least
356370
90 seconds.
357-
:param hedge: The :attr:`~hedge` for this read preference.
371+
:param hedge: **DEPRECATED** - The :attr:`~hedge` for this read preference.
358372
359373
.. versionchanged:: 3.11
360374
Added ``hedge`` parameter.
@@ -397,7 +411,7 @@ class SecondaryPreferred(_ServerMode):
397411
replication before it will no longer be selected for operations.
398412
Default -1, meaning no maximum. If it is set, it must be at least
399413
90 seconds.
400-
:param hedge: The :attr:`~hedge` for this read preference.
414+
:param hedge: **DEPRECATED** - The :attr:`~hedge` for this read preference.
401415
402416
.. versionchanged:: 3.11
403417
Added ``hedge`` parameter.
@@ -441,7 +455,7 @@ class Nearest(_ServerMode):
441455
replication before it will no longer be selected for operations.
442456
Default -1, meaning no maximum. If it is set, it must be at least
443457
90 seconds.
444-
:param hedge: The :attr:`~hedge` for this read preference.
458+
:param hedge: **DEPRECATED** - The :attr:`~hedge` for this read preference.
445459
446460
.. versionchanged:: 3.11
447461
Added ``hedge`` parameter.

test/asynchronous/test_read_preferences.py

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
)
3636
from test.utils_shared import (
3737
OvertCommandListener,
38+
_ignore_deprecations,
3839
async_wait_until,
3940
one,
4041
)
@@ -542,33 +543,44 @@ def test_read_preference_document_hedge(self):
542543
for mode, cls in cases.items():
543544
with self.assertRaises(TypeError):
544545
cls(hedge=[]) # type: ignore
545-
546-
pref = cls(hedge={})
547-
self.assertEqual(pref.document, {"mode": mode})
548-
out = _maybe_add_read_preference({}, pref)
549-
if cls == SecondaryPreferred:
550-
# SecondaryPreferred without hedge doesn't add $readPreference.
551-
self.assertEqual(out, {})
552-
else:
546+
with _ignore_deprecations():
547+
pref = cls(hedge={})
548+
self.assertEqual(pref.document, {"mode": mode})
549+
out = _maybe_add_read_preference({}, pref)
550+
if cls == SecondaryPreferred:
551+
# SecondaryPreferred without hedge doesn't add $readPreference.
552+
self.assertEqual(out, {})
553+
else:
554+
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
555+
556+
hedge: dict[str, Any] = {"enabled": True}
557+
pref = cls(hedge=hedge)
558+
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
559+
out = _maybe_add_read_preference({}, pref)
553560
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
554561

555-
hedge: dict[str, Any] = {"enabled": True}
556-
pref = cls(hedge=hedge)
557-
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
558-
out = _maybe_add_read_preference({}, pref)
559-
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
562+
hedge = {"enabled": False}
563+
pref = cls(hedge=hedge)
564+
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
565+
out = _maybe_add_read_preference({}, pref)
566+
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
560567

561-
hedge = {"enabled": False}
562-
pref = cls(hedge=hedge)
563-
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
564-
out = _maybe_add_read_preference({}, pref)
565-
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
568+
hedge = {"enabled": False, "extra": "option"}
569+
pref = cls(hedge=hedge)
570+
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
571+
out = _maybe_add_read_preference({}, pref)
572+
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
566573

567-
hedge = {"enabled": False, "extra": "option"}
568-
pref = cls(hedge=hedge)
569-
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
570-
out = _maybe_add_read_preference({}, pref)
571-
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
574+
def test_read_preference_hedge_deprecated(self):
575+
cases = {
576+
"primaryPreferred": PrimaryPreferred,
577+
"secondary": Secondary,
578+
"secondaryPreferred": SecondaryPreferred,
579+
"nearest": Nearest,
580+
}
581+
for _, cls in cases.items():
582+
with self.assertRaises(DeprecationWarning):
583+
cls(hedge={"enabled": True})
572584

573585
async def test_send_hedge(self):
574586
cases = {
@@ -582,7 +594,8 @@ async def test_send_hedge(self):
582594
client = await self.async_rs_client(event_listeners=[listener])
583595
await client.admin.command("ping")
584596
for _mode, cls in cases.items():
585-
pref = cls(hedge={"enabled": True})
597+
with _ignore_deprecations():
598+
pref = cls(hedge={"enabled": True})
586599
coll = client.test.get_collection("test", read_preference=pref)
587600
listener.reset()
588601
await coll.find_one()

test/test_read_preferences.py

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
)
3636
from test.utils_shared import (
3737
OvertCommandListener,
38+
_ignore_deprecations,
3839
one,
3940
wait_until,
4041
)
@@ -522,33 +523,44 @@ def test_read_preference_document_hedge(self):
522523
for mode, cls in cases.items():
523524
with self.assertRaises(TypeError):
524525
cls(hedge=[]) # type: ignore
525-
526-
pref = cls(hedge={})
527-
self.assertEqual(pref.document, {"mode": mode})
528-
out = _maybe_add_read_preference({}, pref)
529-
if cls == SecondaryPreferred:
530-
# SecondaryPreferred without hedge doesn't add $readPreference.
531-
self.assertEqual(out, {})
532-
else:
526+
with _ignore_deprecations():
527+
pref = cls(hedge={})
528+
self.assertEqual(pref.document, {"mode": mode})
529+
out = _maybe_add_read_preference({}, pref)
530+
if cls == SecondaryPreferred:
531+
# SecondaryPreferred without hedge doesn't add $readPreference.
532+
self.assertEqual(out, {})
533+
else:
534+
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
535+
536+
hedge: dict[str, Any] = {"enabled": True}
537+
pref = cls(hedge=hedge)
538+
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
539+
out = _maybe_add_read_preference({}, pref)
533540
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
534541

535-
hedge: dict[str, Any] = {"enabled": True}
536-
pref = cls(hedge=hedge)
537-
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
538-
out = _maybe_add_read_preference({}, pref)
539-
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
542+
hedge = {"enabled": False}
543+
pref = cls(hedge=hedge)
544+
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
545+
out = _maybe_add_read_preference({}, pref)
546+
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
540547

541-
hedge = {"enabled": False}
542-
pref = cls(hedge=hedge)
543-
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
544-
out = _maybe_add_read_preference({}, pref)
545-
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
548+
hedge = {"enabled": False, "extra": "option"}
549+
pref = cls(hedge=hedge)
550+
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
551+
out = _maybe_add_read_preference({}, pref)
552+
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
546553

547-
hedge = {"enabled": False, "extra": "option"}
548-
pref = cls(hedge=hedge)
549-
self.assertEqual(pref.document, {"mode": mode, "hedge": hedge})
550-
out = _maybe_add_read_preference({}, pref)
551-
self.assertEqual(out, SON([("$query", {}), ("$readPreference", pref.document)]))
554+
def test_read_preference_hedge_deprecated(self):
555+
cases = {
556+
"primaryPreferred": PrimaryPreferred,
557+
"secondary": Secondary,
558+
"secondaryPreferred": SecondaryPreferred,
559+
"nearest": Nearest,
560+
}
561+
for _, cls in cases.items():
562+
with self.assertRaises(DeprecationWarning):
563+
cls(hedge={"enabled": True})
552564

553565
def test_send_hedge(self):
554566
cases = {
@@ -562,7 +574,8 @@ def test_send_hedge(self):
562574
client = self.rs_client(event_listeners=[listener])
563575
client.admin.command("ping")
564576
for _mode, cls in cases.items():
565-
pref = cls(hedge={"enabled": True})
577+
with _ignore_deprecations():
578+
pref = cls(hedge={"enabled": True})
566579
coll = client.test.get_collection("test", read_preference=pref)
567580
listener.reset()
568581
coll.find_one()

0 commit comments

Comments
 (0)