Compare commits

...

13 Commits
master ... v4.6

Author SHA1 Message Date
Steven Silvester
d23ed12467
PYTHON-4305 [v4.6]: Add changelog for 4.6.3 (#1608)
Co-authored-by: Shane Harvey <shnhrv@gmail.com>
2024-04-18 13:29:31 -05:00
Alessio Castrica
d6248e9cf1 PYTHON-4298 Raise ConfigurationError not TypeError when round_trip_time is None in server selection (#1566)
Co-authored-by: Alessio <alessio.castrica@investsuite.com>
(cherry picked from commit 167b9648ca)
2024-04-04 15:10:15 -07:00
Steven Silvester
3f04a62f68
BUMP 4.6.4.dev0 2024-03-27 18:54:02 -05:00
Steven Silvester
8da192f9ca
BUMP 4.6.3 2024-03-27 18:53:29 -05:00
Shane Harvey
56b6b6dbc2
PYTHON-4305 Fix bson size check (#1564)
(cherry picked from commit 372b5d68d5)
2024-03-27 18:52:36 -05:00
Steven Silvester
449d0f316c
BUMP to 4.6.3.dev0 2024-02-21 13:33:09 -06:00
Steven Silvester
e04576de22
DEVPROD-3871 Use teardown_task when there is one function/command (#1533) 2024-02-21 12:04:14 -06:00
Steven Silvester
cf1c6a11f7
PYTHON-4219 Prep for 4.6.2 Release (#1530) 2024-02-20 14:30:46 -06:00
Steven Silvester
d29b2b7cf4
PYTHON-4147 [v4.6]: Silence noisy thread.start() RuntimeError at shutdown (#1532)
Co-authored-by: Jib <jib.adegunloye@mongodb.com>
2024-02-20 14:29:01 -06:00
Steven Silvester
0477b9bc0c
PYTHON-4077 [v4.6]: Ensure there is a MacOS wheel for Python 3.7 (#1527)
Co-authored-by: Casey Clements <caseyclements@users.noreply.github.com>
Co-authored-by: Shane Harvey <shnhrv@gmail.com>
2024-02-16 14:56:59 -06:00
Steven Silvester
ecad17d24e BUMP 4.6.2.dev0 2023-11-27 13:45:51 -06:00
Steven Silvester
485e0a5e56 BUMP 4.6.1 2023-11-27 13:44:40 -06:00
Jib
995365c712
PYTHON-4038 [v4.6]: Ensure retryable read OperationFailures re-raise exception when 0 or NoneType error code is provided. (#1425) (#1429) 2023-11-16 14:10:42 -05:00
15 changed files with 130 additions and 20 deletions

View File

@ -12,7 +12,7 @@ stepback: true
# Actual testing tasks are marked with `type: test` # Actual testing tasks are marked with `type: test`
command_type: system command_type: system
# Protect ourself against rogue test case, or curl gone wild, that runs forever # Protect ourselves against rogue test case, or curl gone wild, that runs forever
# Good rule of thumb: the averageish length a task takes, times 5 # Good rule of thumb: the averageish length a task takes, times 5
# That roughly accounts for variable system performance for various buildvariants # That roughly accounts for variable system performance for various buildvariants
exec_timeout_secs: 3600 # 60 minutes is the longest we'll ever run (primarily exec_timeout_secs: 3600 # 60 minutes is the longest we'll ever run (primarily
@ -1058,7 +1058,7 @@ task_groups:
- command: expansions.update - command: expansions.update
params: params:
file: src/atlas-expansion.yml file: src/atlas-expansion.yml
teardown_group: teardown_task:
- command: subprocess.exec - command: subprocess.exec
params: params:
working_dir: src working_dir: src
@ -1098,7 +1098,7 @@ task_groups:
- command: expansions.update - command: expansions.update
params: params:
file: src/atlas-expansion.yml file: src/atlas-expansion.yml
teardown_group: teardown_task:
- command: subprocess.exec - command: subprocess.exec
params: params:
working_dir: src working_dir: src
@ -1174,6 +1174,7 @@ tasks:
- func: "build release" - func: "build release"
vars: vars:
VERSION: "3.7" VERSION: "3.7"
- func: "upload release"
- name: "release-windows" - name: "release-windows"
tags: ["release_tag"] tags: ["release_tag"]

View File

@ -2405,6 +2405,7 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
uint32_t c_w_s_size; uint32_t c_w_s_size;
uint32_t code_size; uint32_t code_size;
uint32_t scope_size; uint32_t scope_size;
uint32_t len;
PyObject* code; PyObject* code;
PyObject* scope; PyObject* scope;
PyObject* code_type; PyObject* code_type;
@ -2424,7 +2425,8 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
memcpy(&code_size, buffer + *position, 4); memcpy(&code_size, buffer + *position, 4);
code_size = BSON_UINT32_FROM_LE(code_size); code_size = BSON_UINT32_FROM_LE(code_size);
/* code_w_scope length + code length + code + scope length */ /* code_w_scope length + code length + code + scope length */
if (!code_size || max < code_size || max < 4 + 4 + code_size + 4) { len = 4 + 4 + code_size + 4;
if (!code_size || max < code_size || max < len || len < code_size) {
goto invalid; goto invalid;
} }
*position += 4; *position += 4;
@ -2442,12 +2444,9 @@ static PyObject* get_value(PyObject* self, PyObject* name, const char* buffer,
memcpy(&scope_size, buffer + *position, 4); memcpy(&scope_size, buffer + *position, 4);
scope_size = BSON_UINT32_FROM_LE(scope_size); scope_size = BSON_UINT32_FROM_LE(scope_size);
if (scope_size < BSON_MIN_SIZE) {
Py_DECREF(code);
goto invalid;
}
/* code length + code + scope length + scope */ /* code length + code + scope length + scope */
if ((4 + code_size + 4 + scope_size) != c_w_s_size) { len = 4 + 4 + code_size + scope_size;
if (scope_size < BSON_MIN_SIZE || len != c_w_s_size || len < scope_size) {
Py_DECREF(code); Py_DECREF(code);
goto invalid; goto invalid;
} }

View File

@ -35,7 +35,7 @@ Connections to Atlas require TLS/SSL.
You can read more about TLS versions and their security implications here: You can read more about TLS versions and their security implications here:
`<https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html#only-support-strong-protocols>`_ `<https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html#only-support-strong-protocols>`_
.. _python.org: https://www.python.org/downloads/ .. _python.org: https://www.python.org/downloads/
.. _homebrew: https://brew.sh/ .. _homebrew: https://brew.sh/

View File

@ -1,6 +1,52 @@
Changelog Changelog
========= =========
Changes in Version 4.6.3
------------------------
PyMongo 4.6.3 fixes the following bug:
- Fixed a potential memory access violation when decoding invalid bson.
Issues Resolved
...............
See the `PyMongo 4.6.3 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _PyMongo 4.6.3 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=38360
Changes in Version 4.6.2
------------------------
PyMongo 4.6.2 fixes the following bug:
- Fixed a bug appearing in Python 3.12 where "RuntimeError: can't create new thread at interpreter shutdown"
could be written to stderr when a MongoClient's thread starts as the python interpreter is shutting down.
Issues Resolved
...............
See the `PyMongo 4.6.2 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _PyMongo 4.6.2 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=37906
Changes in Version 4.6.1
------------------------
PyMongo 4.6.1 fixes the following bug:
- Ensure retryable read ``OperationFailure`` errors re-raise exception when 0 or NoneType error code is provided.
Issues Resolved
...............
See the `PyMongo 4.6.1 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _PyMongo 4.6.1 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=37138
Changes in Version 4.6 Changes in Version 4.6
---------------------- ----------------------
@ -33,6 +79,14 @@ PyMongo 4.6 brings a number of improvements including:
- Added the :ref:`network-compression-example` documentation page. - Added the :ref:`network-compression-example` documentation page.
- Added more timeout information to network errors. - Added more timeout information to network errors.
Issues Resolved
...............
See the `PyMongo 4.6 release notes in JIRA`_ for the list of resolved issues
in this release.
.. _PyMongo 4.6 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=36542
Changes in Version 4.5 Changes in Version 4.5
---------------------- ----------------------

View File

@ -59,4 +59,4 @@ deprecated PyMongo features.
.. _the warnings module: https://docs.python.org/3/library/warnings.html .. _the warnings module: https://docs.python.org/3/library/warnings.html
.. _the -W command line option: https://docs.python.org/3/using/cmdline.html#cmdoption-w .. _the -W command line option: https://docs.python.org/3/using/cmdline.html#cmdoption-W

View File

@ -32,7 +32,7 @@ MongoDB.
You can read more about TLS versions and their security implications here: You can read more about TLS versions and their security implications here:
`<https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html#only-support-strong-protocols>`_ `<https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Security_Cheat_Sheet.html#only-support-strong-protocols>`_
.. _python.org: https://www.python.org/downloads/ .. _python.org: https://www.python.org/downloads/
.. _homebrew: https://brew.sh/ .. _homebrew: https://brew.sh/

View File

@ -44,7 +44,7 @@ MincePy
workflow as possible. workflow as possible.
Ming Ming
`Ming <http://merciless.sourceforge.net/>`_ (the Merciless) is a `Ming <https://ming.readthedocs.io/en/latest/>`_ is a
library that allows you to enforce schemas on a MongoDB database in library that allows you to enforce schemas on a MongoDB database in
your Python application. It was developed by `SourceForge your Python application. It was developed by `SourceForge
<http://sourceforge.net/>`_ in the course of their migration to <http://sourceforge.net/>`_ in the course of their migration to

View File

@ -17,7 +17,7 @@ from __future__ import annotations
from typing import Tuple, Union from typing import Tuple, Union
version_tuple: Tuple[Union[int, str], ...] = (4, 6, 0) version_tuple: Tuple[Union[int, str], ...] = (4, 6, 4, ".dev0")
def get_version_string() -> str: def get_version_string() -> str:

View File

@ -2898,7 +2898,7 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
.. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_. .. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_.
.. _change streams specification: .. _change streams specification:
https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md
""" """
return CollectionChangeStream( return CollectionChangeStream(
self, self,

View File

@ -666,7 +666,7 @@ class Database(common.BaseObject, Generic[_DocumentType]):
.. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_. .. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_.
.. _change streams specification: .. _change streams specification:
https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md
""" """
return DatabaseChangeStream( return DatabaseChangeStream(
self, self,

View File

@ -1030,7 +1030,7 @@ class MongoClient(common.BaseObject, Generic[_DocumentType]):
.. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_. .. seealso:: The MongoDB documentation on `changeStreams <https://mongodb.com/docs/manual/changeStreams/>`_.
.. _change streams specification: .. _change streams specification:
https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.rst https://github.com/mongodb/specifications/blob/master/source/change-streams/change-streams.md
""" """
return ClusterChangeStream( return ClusterChangeStream(
self.admin, self.admin,
@ -2329,7 +2329,8 @@ class _ClientConnectionRetryable(Generic[T]):
# ConnectionFailures do not supply a code property # ConnectionFailures do not supply a code property
exc_code = getattr(exc, "code", None) exc_code = getattr(exc, "code", None)
if self._is_not_eligible_for_retry() or ( if self._is_not_eligible_for_retry() or (
exc_code and exc_code not in helpers._RETRYABLE_ERROR_CODES isinstance(exc, OperationFailure)
and exc_code not in helpers._RETRYABLE_ERROR_CODES
): ):
raise raise
self._retrying = True self._retrying = True

View File

@ -16,6 +16,7 @@
from __future__ import annotations from __future__ import annotations
import sys
import threading import threading
import time import time
import weakref import weakref
@ -92,7 +93,15 @@ class PeriodicExecutor:
thread.daemon = True thread.daemon = True
self._thread = weakref.proxy(thread) self._thread = weakref.proxy(thread)
_register_executor(self) _register_executor(self)
thread.start() # Mitigation to RuntimeError firing when thread starts on shutdown
# https://github.com/python/cpython/issues/114570
try:
thread.start()
except RuntimeError as e:
if "interpreter shutdown" in str(e) or sys.is_finalizing():
self._thread = None
return
raise
def close(self, dummy: Any = None) -> None: def close(self, dummy: Any = None) -> None:
"""Stop. To restart, call open(). """Stop. To restart, call open().

View File

@ -266,8 +266,14 @@ class TopologyDescription:
def _apply_local_threshold(self, selection: Optional[Selection]) -> list[ServerDescription]: def _apply_local_threshold(self, selection: Optional[Selection]) -> list[ServerDescription]:
if not selection: if not selection:
return [] return []
round_trip_times: list[float] = []
for server in selection.server_descriptions:
if server.round_trip_time is None:
config_err_msg = f"round_trip_time for server {server.address} is unexpectedly None: {self}, servers: {selection.server_descriptions}"
raise ConfigurationError(config_err_msg)
round_trip_times.append(server.round_trip_time)
# Round trip time in seconds. # Round trip time in seconds.
fastest = min(cast(float, s.round_trip_time) for s in selection.server_descriptions) fastest = min(round_trip_times)
threshold = self._topology_settings.local_threshold_ms / 1000.0 threshold = self._topology_settings.local_threshold_ms / 1000.0
return [ return [
s s

View File

@ -16,11 +16,13 @@
from __future__ import annotations from __future__ import annotations
import unittest import unittest
from test import PyMongoTestCase
from mockupdb import MockupDB, OpMsg, going from mockupdb import MockupDB, OpMsg, going
from bson.objectid import ObjectId from bson.objectid import ObjectId
from pymongo import MongoClient from pymongo import MongoClient
from pymongo.errors import OperationFailure
class TestCursor(unittest.TestCase): class TestCursor(unittest.TestCase):
@ -57,5 +59,31 @@ class TestCursor(unittest.TestCase):
request.replies({"cursor": {"id": cursor_id, "nextBatch": [{}]}}) request.replies({"cursor": {"id": cursor_id, "nextBatch": [{}]}})
class TestRetryableErrorCodeCatch(PyMongoTestCase):
def _test_fail_on_operation_failure_with_code(self, code):
"""Test reads on error codes that should not be retried"""
server = MockupDB()
server.run()
self.addCleanup(server.stop)
server.autoresponds("ismaster", maxWireVersion=6)
client = MongoClient(server.uri)
with going(lambda: server.receives(OpMsg({"find": "collection"})).command_err(code=code)):
cursor = client.db.collection.find()
with self.assertRaises(OperationFailure) as ctx:
cursor.next()
self.assertEqual(ctx.exception.code, code)
def test_fail_on_operation_failure_none(self):
self._test_fail_on_operation_failure_with_code(None)
def test_fail_on_operation_failure_zero(self):
self._test_fail_on_operation_failure_with_code(0)
def test_fail_on_operation_failure_one(self):
self._test_fail_on_operation_failure_with_code(1)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()

View File

@ -16,6 +16,7 @@
from __future__ import annotations from __future__ import annotations
import gc import gc
import subprocess
import sys import sys
from functools import partial from functools import partial
@ -79,6 +80,17 @@ class TestMonitor(IntegrationTest):
for executor in executors: for executor in executors:
wait_until(lambda: executor._stopped, f"closed executor: {executor._name}", timeout=5) wait_until(lambda: executor._stopped, f"closed executor: {executor._name}", timeout=5)
def test_no_thread_start_runtime_err_on_shutdown(self):
"""Test we silence noisy runtime errors fired when the MongoClient spawns a new thread
on process shutdown."""
command = [sys.executable, "-c", "from pymongo import MongoClient; c = MongoClient()"]
completed_process: subprocess.CompletedProcess = subprocess.run(
command, capture_output=True
)
self.assertFalse(completed_process.stderr)
self.assertFalse(completed_process.stdout)
if __name__ == "__main__": if __name__ == "__main__":
unittest.main() unittest.main()