Skip to content

Commit 995365c

Browse files
authored
PYTHON-4038 [v4.6]: Ensure retryable read OperationFailures re-raise exception when 0 or NoneType error code is provided. (#1425) (#1429)
1 parent 8e25ce1 commit 995365c

File tree

2 files changed

+30
-1
lines changed

2 files changed

+30
-1
lines changed

pymongo/mongo_client.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -2329,7 +2329,8 @@ def run(self) -> T:
23292329
# ConnectionFailures do not supply a code property
23302330
exc_code = getattr(exc, "code", None)
23312331
if self._is_not_eligible_for_retry() or (
2332-
exc_code and exc_code not in helpers._RETRYABLE_ERROR_CODES
2332+
isinstance(exc, OperationFailure)
2333+
and exc_code not in helpers._RETRYABLE_ERROR_CODES
23332334
):
23342335
raise
23352336
self._retrying = True

test/mockupdb/test_cursor.py

+28
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,13 @@
1616
from __future__ import annotations
1717

1818
import unittest
19+
from test import PyMongoTestCase
1920

2021
from mockupdb import MockupDB, OpMsg, going
2122

2223
from bson.objectid import ObjectId
2324
from pymongo import MongoClient
25+
from pymongo.errors import OperationFailure
2426

2527

2628
class TestCursor(unittest.TestCase):
@@ -57,5 +59,31 @@ def test_getmore_load_balanced(self):
5759
request.replies({"cursor": {"id": cursor_id, "nextBatch": [{}]}})
5860

5961

62+
class TestRetryableErrorCodeCatch(PyMongoTestCase):
63+
def _test_fail_on_operation_failure_with_code(self, code):
64+
"""Test reads on error codes that should not be retried"""
65+
server = MockupDB()
66+
server.run()
67+
self.addCleanup(server.stop)
68+
server.autoresponds("ismaster", maxWireVersion=6)
69+
70+
client = MongoClient(server.uri)
71+
72+
with going(lambda: server.receives(OpMsg({"find": "collection"})).command_err(code=code)):
73+
cursor = client.db.collection.find()
74+
with self.assertRaises(OperationFailure) as ctx:
75+
cursor.next()
76+
self.assertEqual(ctx.exception.code, code)
77+
78+
def test_fail_on_operation_failure_none(self):
79+
self._test_fail_on_operation_failure_with_code(None)
80+
81+
def test_fail_on_operation_failure_zero(self):
82+
self._test_fail_on_operation_failure_with_code(0)
83+
84+
def test_fail_on_operation_failure_one(self):
85+
self._test_fail_on_operation_failure_with_code(1)
86+
87+
6088
if __name__ == "__main__":
6189
unittest.main()

0 commit comments

Comments
 (0)