Skip to content

Commit 3e0232b

Browse files
committed
merge from master
2 parents c606dc8 + a7a645f commit 3e0232b

19 files changed

+636
-428
lines changed

.pre-commit-config.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@ repos:
105105
# - test/test_client.py:188: te ==> the, be, we, to
106106
args: ["-L", "fle,fo,infinit,isnt,nin,te,aks"]
107107

108+
- repo: https://github.com/astral-sh/uv-pre-commit
109+
# uv version.
110+
rev: 0.8.17
111+
hooks:
112+
- id: uv-lock
113+
108114
- repo: local
109115
hooks:
110116
- id: executable-shell

CONTRIBUTING.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,3 +514,11 @@ To profile a test script and generate a flame graph, follow these steps:
514514
(Note: on macOS you will need to run this command using `sudo` to allow `py-spy` to attach to the Python process.)
515515
4. If you need to include native code (for example the C extensions), profiling should be done on a Linux system, as macOS and Windows do not support the `--native` option of `py-spy`.
516516
Creating an ubuntu Evergreen spawn host and using `scp` to copy the flamegraph `.svg` file back to your local machine is the best way to do this.
517+
518+
## Dependabot updates
519+
520+
Dependabot will raise PRs at most once per week, grouped by GitHub Actions updates and Python requirement
521+
file updates. We have a pre-commit hook that will update the `uv.lock` file when requirements change.
522+
To update the lock file on a failing PR, you can use a method like `gh pr checkout <pr number>`, then run
523+
`just lint uv-lock` to update the lock file, and then push the changes. If a typing dependency has changed,
524+
also run `just typing` and handle any new findings.

bson/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,7 @@ def decode_iter(
13271327
elements = data[position : position + obj_size]
13281328
position += obj_size
13291329

1330-
yield _bson_to_dict(elements, opts) # type:ignore[misc]
1330+
yield _bson_to_dict(elements, opts)
13311331

13321332

13331333
@overload
@@ -1373,7 +1373,7 @@ def decode_file_iter(
13731373
raise InvalidBSON("cut off in middle of objsize")
13741374
obj_size = _UNPACK_INT_FROM(size_data, 0)[0] - 4
13751375
elements = size_data + file_obj.read(max(0, obj_size))
1376-
yield _bson_to_dict(elements, opts) # type:ignore[arg-type, misc]
1376+
yield _bson_to_dict(elements, opts) # type:ignore[misc]
13771377

13781378

13791379
def is_valid(bson: bytes) -> bool:

doc/changelog.rst

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,27 @@
11
Changelog
22
=========
33

4-
Changes in Version 4.15.1 (XXXX/XX/XX)
4+
Changes in Version 4.15.1 (2025/09/16)
55
--------------------------------------
66

77
Version 4.15.1 is a bug fix release.
88

9-
- Fixed a bug in ``AsyncMongoClient`` that caused a
10-
``ServerSelectionTimeoutError`` when used with ``uvicorn``, ``FastAPI``, or ``uvloop``.
9+
- Fixed a bug in :meth:`~pymongo.synchronous.encryption.ClientEncryption.encrypt`
10+
and :meth:`~pymongo.asynchronous.encryption.AsyncClientEncryption.encrypt`
11+
that would cause a ``TypeError`` when using ``pymongocrypt<1.16`` by passing
12+
an unsupported ``type_opts`` parameter even if Queryable Encryption text
13+
queries beta was not used.
14+
15+
- Fixed a bug in ``AsyncMongoClient`` that caused a ``ServerSelectionTimeoutError``
16+
when used with ``uvicorn``, ``FastAPI``, or ``uvloop``.
17+
18+
Issues Resolved
19+
...............
20+
21+
See the `PyMongo 4.15.1 release notes in JIRA`_ for the list of resolved issues
22+
in this release.
23+
24+
.. _PyMongo 4.15.1 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=46486
1125

1226
Changes in Version 4.15.0 (2025/09/10)
1327
--------------------------------------
@@ -21,17 +35,20 @@ PyMongo 4.15 brings a number of changes including:
2135
:attr:`~pymongo.encryption.QueryType.SUBSTRINGPREVIEW`,
2236
as part of the experimental Queryable Encryption text queries beta.
2337
``pymongocrypt>=1.16`` is required for text query support.
24-
- Added :class:`bson.decimal128.DecimalEncoder` and :class:`bson.decimal128.DecimalDecoder`
25-
to support encoding and decoding of BSON Decimal128 values to decimal.Decimal values using the TypeRegistry API.
38+
- Added :class:`bson.decimal128.DecimalEncoder` and
39+
:class:`bson.decimal128.DecimalDecoder`
40+
to support encoding and decoding of BSON Decimal128 values to
41+
decimal.Decimal values using the TypeRegistry API.
2642
- Added support for Windows ``arm64`` wheels.
2743

2844
Changes in Version 4.14.1 (2025/08/19)
2945
--------------------------------------
3046

3147
Version 4.14.1 is a bug fix release.
3248

33-
- Fixed a bug in ``MongoClient.append_metadata()`` and ``AsyncMongoClient.append_metadata()``
34-
that allowed duplicate ``DriverInfo.name`` to be appended to the metadata.
49+
- Fixed a bug in ``MongoClient.append_metadata()`` and
50+
``AsyncMongoClient.append_metadata()``
51+
that allowed duplicate ``DriverInfo.name`` to be appended to the metadata.
3552

3653
Issues Resolved
3754
...............

justfile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,12 @@ typing-pyright: && resync
5050
{{typing_run}} pyright -p strict_pyrightconfig.json test/test_typing_strict.py
5151

5252
[group('lint')]
53-
lint: && resync
54-
uv run pre-commit run --all-files
53+
lint *args="": && resync
54+
uv run pre-commit run --all-files {{args}}
5555

5656
[group('lint')]
57-
lint-manual: && resync
58-
uv run pre-commit run --all-files --hook-stage manual
57+
lint-manual *args="": && resync
58+
uv run pre-commit run --all-files --hook-stage manual {{args}}
5959

6060
[group('test')]
6161
test *args="-v --durations=5 --maxfail=10": && resync

pymongo/asynchronous/encryption.py

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@
6464
from pymongo.asynchronous.cursor import AsyncCursor
6565
from pymongo.asynchronous.database import AsyncDatabase
6666
from pymongo.asynchronous.mongo_client import AsyncMongoClient
67-
from pymongo.asynchronous.pool import AsyncBaseConnection
6867
from pymongo.common import CONNECT_TIMEOUT
6968
from pymongo.daemon import _spawn_daemon
7069
from pymongo.encryption_options import AutoEncryptionOpts, RangeOpts, TextOpts
@@ -77,11 +76,11 @@
7776
ServerSelectionTimeoutError,
7877
)
7978
from pymongo.helpers_shared import _get_timeout_details
80-
from pymongo.network_layer import PyMongoKMSProtocol, async_receive_kms, async_sendall
79+
from pymongo.network_layer import async_socket_sendall
8180
from pymongo.operations import UpdateOne
8281
from pymongo.pool_options import PoolOptions
8382
from pymongo.pool_shared import (
84-
_configured_protocol_interface,
83+
_async_configured_socket,
8584
_raise_connection_failure,
8685
)
8786
from pymongo.read_concern import ReadConcern
@@ -94,8 +93,10 @@
9493
if TYPE_CHECKING:
9594
from pymongocrypt.mongocrypt import MongoCryptKmsContext
9695

96+
from pymongo.pyopenssl_context import _sslConn
9797
from pymongo.typings import _Address
9898

99+
99100
_IS_SYNC = False
100101

101102
_HTTPS_PORT = 443
@@ -110,10 +111,9 @@
110111
_KEY_VAULT_OPTS = CodecOptions(document_class=RawBSONDocument)
111112

112113

113-
async def _connect_kms(address: _Address, opts: PoolOptions) -> AsyncBaseConnection:
114+
async def _connect_kms(address: _Address, opts: PoolOptions) -> Union[socket.socket, _sslConn]:
114115
try:
115-
interface = await _configured_protocol_interface(address, opts, PyMongoKMSProtocol)
116-
return AsyncBaseConnection(interface, opts)
116+
return await _async_configured_socket(address, opts)
117117
except Exception as exc:
118118
_raise_connection_failure(address, exc, timeout_details=_get_timeout_details(opts))
119119

@@ -198,11 +198,19 @@ async def kms_request(self, kms_context: MongoCryptKmsContext) -> None:
198198
try:
199199
conn = await _connect_kms(address, opts)
200200
try:
201-
await async_sendall(conn.conn.get_conn, message)
201+
await async_socket_sendall(conn, message)
202202
while kms_context.bytes_needed > 0:
203203
# CSOT: update timeout.
204-
conn.set_conn_timeout(max(_csot.clamp_remaining(_KMS_CONNECT_TIMEOUT), 0))
205-
data = await async_receive_kms(conn, kms_context.bytes_needed)
204+
conn.settimeout(max(_csot.clamp_remaining(_KMS_CONNECT_TIMEOUT), 0))
205+
data: memoryview | bytes
206+
if _IS_SYNC:
207+
data = conn.recv(kms_context.bytes_needed)
208+
else:
209+
from pymongo.network_layer import ( # type: ignore[attr-defined]
210+
async_receive_data_socket,
211+
)
212+
213+
data = await async_receive_data_socket(conn, kms_context.bytes_needed)
206214
if not data:
207215
raise OSError("KMS connection closed")
208216
kms_context.feed(data)
@@ -221,7 +229,7 @@ async def kms_request(self, kms_context: MongoCryptKmsContext) -> None:
221229
address, exc, msg_prefix=msg_prefix, timeout_details=_get_timeout_details(opts)
222230
)
223231
finally:
224-
await conn.close_conn(None)
232+
conn.close()
225233
except MongoCryptError:
226234
raise # Propagate MongoCryptError errors directly.
227235
except Exception as exc:

0 commit comments

Comments
 (0)