Skip to content

Commit 017e1ef

Browse files
committed
Merge branch 'master' of github.com:mongodb/mongo-python-driver
2 parents de3fed9 + 044d92c commit 017e1ef

26 files changed

+1813
-161
lines changed

.evergreen/config.yml

Lines changed: 61 additions & 91 deletions
Large diffs are not rendered by default.

.evergreen/hatch.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,17 @@ if [ -z "$PYTHON_BINARY" ]; then
88
PYTHON_BINARY=$(find_python3)
99
fi
1010

11-
if $PYTHON_BINARY -m hatch --version; then
11+
# Check if we should skip hatch and run the tests directly.
12+
if [ -n "$SKIP_HATCH" ]; then
13+
ENV_NAME=testenv-$RANDOM
14+
createvirtualenv "$PYTHON_BINARY" $ENV_NAME
15+
# shellcheck disable=SC2064
16+
trap "deactivate; rm -rf $ENV_NAME" EXIT HUP
17+
python -m pip install -e ".[test]"
18+
run_hatch() {
19+
bash ./.evergreen/run-tests.sh
20+
}
21+
elif $PYTHON_BINARY -m hatch --version; then
1222
run_hatch() {
1323
$PYTHON_BINARY -m hatch run "$@"
1424
}

.evergreen/scripts/configure-env.sh

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#!/bin/bash -ex
2+
3+
# Get the current unique version of this checkout
4+
# shellcheck disable=SC2154
5+
if [ "$is_patch" = "true" ]; then
6+
# shellcheck disable=SC2154
7+
CURRENT_VERSION="$(git describe)-patch-$version_id"
8+
else
9+
CURRENT_VERSION=latest
10+
fi
11+
12+
PROJECT_DIRECTORY="$(pwd)"
13+
DRIVERS_TOOLS="$(dirname $PROJECT_DIRECTORY)/drivers-tools"
14+
15+
# Python has cygwin path problems on Windows. Detect prospective mongo-orchestration home directory
16+
if [ "Windows_NT" = "$OS" ]; then # Magic variable in cygwin
17+
DRIVERS_TOOLS=$(cygpath -m $DRIVERS_TOOLS)
18+
PROJECT_DIRECTORY=$(cygpath -m $PROJECT_DIRECTORY)
19+
fi
20+
21+
SCRIPT_DIR="$PROJECT_DIRECTORY/.evergreen/scripts"
22+
23+
if [ -f "$SCRIPT_DIR/env.sh" ]; then
24+
echo "Reading $SCRIPT_DIR/env.sh file"
25+
. "$SCRIPT_DIR/env.sh"
26+
exit 0
27+
fi
28+
29+
export MONGO_ORCHESTRATION_HOME="$DRIVERS_TOOLS/.evergreen/orchestration"
30+
export MONGODB_BINARIES="$DRIVERS_TOOLS/mongodb/bin"
31+
32+
cat <<EOT > $SCRIPT_DIR/env.sh
33+
set -o errexit
34+
export PROJECT_DIRECTORY="$PROJECT_DIRECTORY"
35+
export CURRENT_VERSION="$CURRENT_VERSION"
36+
export SKIP_LEGACY_SHELL=1
37+
export DRIVERS_TOOLS="$DRIVERS_TOOLS"
38+
export MONGO_ORCHESTRATION_HOME="$MONGO_ORCHESTRATION_HOME"
39+
export MONGODB_BINARIES="$MONGODB_BINARIES"
40+
export PROJECT_DIRECTORY="$PROJECT_DIRECTORY"
41+
42+
export TMPDIR="$MONGO_ORCHESTRATION_HOME/db"
43+
export PATH="$MONGODB_BINARIES:$PATH"
44+
# shellcheck disable=SC2154
45+
export PROJECT="$project"
46+
export PIP_QUIET=1
47+
EOT
48+
49+
# Add these expansions to make it easier to call out tests scripts from the EVG yaml
50+
cat <<EOT > expansion.yml
51+
DRIVERS_TOOLS: "$DRIVERS_TOOLS"
52+
PROJECT_DIRECTORY: "$PROJECT_DIRECTORY"
53+
EOT

bson/_cbsonmodule.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -383,10 +383,11 @@ static int millis_from_datetime_ms(PyObject* dt, long long* out){
383383
static PyObject* decode_datetime(PyObject* self, long long millis, const codec_options_t* options){
384384
PyObject* naive = NULL;
385385
PyObject* replace = NULL;
386-
PyObject* args = NULL;
387-
PyObject* kwargs = NULL;
388386
PyObject* value = NULL;
389387
struct module_state *state = GETSTATE(self);
388+
if (!state) {
389+
goto invalid;
390+
}
390391
if (options->datetime_conversion == DATETIME_MS){
391392
return datetime_ms_from_millis(self, millis);
392393
}
@@ -414,8 +415,8 @@ static PyObject* decode_datetime(PyObject* self, long long millis, const codec_o
414415
Py_DECREF(utcoffset);
415416
return 0;
416417
}
417-
min_millis_offset = (PyDateTime_DELTA_GET_DAYS(utcoffset) * 86400 +
418-
PyDateTime_DELTA_GET_SECONDS(utcoffset)) * 1000 +
418+
min_millis_offset = (PyDateTime_DELTA_GET_DAYS(utcoffset) * (int64_t)86400 +
419+
PyDateTime_DELTA_GET_SECONDS(utcoffset)) * (int64_t)1000 +
419420
(PyDateTime_DELTA_GET_MICROSECONDS(utcoffset) / 1000);
420421
}
421422
Py_DECREF(utcoffset);
@@ -433,8 +434,8 @@ static PyObject* decode_datetime(PyObject* self, long long millis, const codec_o
433434
Py_DECREF(utcoffset);
434435
return 0;
435436
}
436-
max_millis_offset = (PyDateTime_DELTA_GET_DAYS(utcoffset) * 86400 +
437-
PyDateTime_DELTA_GET_SECONDS(utcoffset)) * 1000 +
437+
max_millis_offset = (PyDateTime_DELTA_GET_DAYS(utcoffset) * (int64_t)86400 +
438+
PyDateTime_DELTA_GET_SECONDS(utcoffset)) * (int64_t)1000 +
438439
(PyDateTime_DELTA_GET_MICROSECONDS(utcoffset) / 1000);
439440
}
440441
Py_DECREF(utcoffset);
@@ -487,8 +488,6 @@ static PyObject* decode_datetime(PyObject* self, long long millis, const codec_o
487488
invalid:
488489
Py_XDECREF(naive);
489490
Py_XDECREF(replace);
490-
Py_XDECREF(args);
491-
Py_XDECREF(kwargs);
492491
return value;
493492
}
494493

doc/changelog.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,18 @@ Changelog
44
Changes in Version 4.9.0
55
-------------------------
66

7+
.. warning:: Driver support for MongoDB 3.6 reached end of life in April 2024.
8+
PyMongo 4.9 will be the last release to support MongoDB 3.6.
9+
710
PyMongo 4.9 brings a number of improvements including:
811

912
- Added support for MongoDB 8.0.
1013
- A new asynchronous API with full asyncio support.
1114
- Added support for In-Use Encryption range queries with MongoDB 8.0.
1215
Added :attr:`~pymongo.encryption.Algorithm.RANGE`.
1316
``sparsity`` and ``trim_factor`` are now optional in :class:`~pymongo.encryption_options.RangeOpts`.
17+
- Added support for the "delegated" option for the KMIP ``master_key`` in
18+
:meth:`~pymongo.encryption.ClientEncryption.create_data_key`.
1419
- pymongocrypt>=1.10 is now required for :ref:`In-Use Encryption` support.
1520
- Added :meth:`~pymongo.cursor.Cursor.to_list` to :class:`~pymongo.cursor.Cursor`,
1621
:class:`~pymongo.command_cursor.CommandCursor`,

pymongo/asynchronous/bulk.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ async def write_command(
281281
)
282282
if bwc.publish:
283283
bwc._succeed(request_id, reply, duration) # type: ignore[arg-type]
284+
await client._process_response(reply, bwc.session) # type: ignore[arg-type]
284285
except Exception as exc:
285286
duration = datetime.datetime.now() - bwc.start_time
286287
if isinstance(exc, (NotPrimaryError, OperationFailure)):
@@ -308,6 +309,9 @@ async def write_command(
308309

309310
if bwc.publish:
310311
bwc._fail(request_id, failure, duration)
312+
# Process the response from the server.
313+
if isinstance(exc, (NotPrimaryError, OperationFailure)):
314+
await client._process_response(exc.details, bwc.session) # type: ignore[arg-type]
311315
raise
312316
finally:
313317
bwc.start_time = datetime.datetime.now()
@@ -449,7 +453,6 @@ async def _execute_batch(
449453
else:
450454
request_id, msg, to_send = bwc.batch_command(cmd, ops)
451455
result = await self.write_command(bwc, cmd, request_id, msg, to_send, client) # type: ignore[arg-type]
452-
await client._process_response(result, bwc.session) # type: ignore[arg-type]
453456

454457
return result, to_send # type: ignore[return-value]
455458

pymongo/asynchronous/client_bulk.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ async def write_command(
283283
)
284284
if bwc.publish:
285285
bwc._succeed(request_id, reply, duration) # type: ignore[arg-type]
286+
# Process the response from the server.
287+
await self.client._process_response(reply, bwc.session) # type: ignore[arg-type]
286288
except Exception as exc:
287289
duration = datetime.datetime.now() - bwc.start_time
288290
if isinstance(exc, (NotPrimaryError, OperationFailure)):
@@ -312,6 +314,11 @@ async def write_command(
312314
bwc._fail(request_id, failure, duration)
313315
# Top-level error will be embedded in ClientBulkWriteException.
314316
reply = {"error": exc}
317+
# Process the response from the server.
318+
if isinstance(exc, OperationFailure):
319+
await self.client._process_response(exc.details, bwc.session) # type: ignore[arg-type]
320+
else:
321+
await self.client._process_response({}, bwc.session) # type: ignore[arg-type]
315322
finally:
316323
bwc.start_time = datetime.datetime.now()
317324
return reply # type: ignore[return-value]
@@ -431,7 +438,6 @@ async def _execute_batch(
431438
result = await self.write_command(
432439
bwc, cmd, request_id, msg, to_send_ops, to_send_ns, self.client
433440
) # type: ignore[arg-type]
434-
await self.client._process_response(result, bwc.session) # type: ignore[arg-type]
435441
return result, to_send_ops, to_send_ns # type: ignore[return-value]
436442

437443
async def _process_results_cursor(

pymongo/asynchronous/encryption.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,9 @@ async def create_data_key(
764764
Secret Data managed object.
765765
- `endpoint` (string): Optional. Host with optional
766766
port, e.g. "example.vault.azure.net:".
767+
- `delegated` (bool): Optional. If True (recommended), the
768+
KMIP server will perform encryption and decryption. If
769+
delegated is not provided, defaults to false.
767770
768771
:param key_alt_names: An optional list of string alternate
769772
names used to reference a key. If a key is created with alternate

pymongo/synchronous/bulk.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ def write_command(
281281
)
282282
if bwc.publish:
283283
bwc._succeed(request_id, reply, duration) # type: ignore[arg-type]
284+
client._process_response(reply, bwc.session) # type: ignore[arg-type]
284285
except Exception as exc:
285286
duration = datetime.datetime.now() - bwc.start_time
286287
if isinstance(exc, (NotPrimaryError, OperationFailure)):
@@ -308,6 +309,9 @@ def write_command(
308309

309310
if bwc.publish:
310311
bwc._fail(request_id, failure, duration)
312+
# Process the response from the server.
313+
if isinstance(exc, (NotPrimaryError, OperationFailure)):
314+
client._process_response(exc.details, bwc.session) # type: ignore[arg-type]
311315
raise
312316
finally:
313317
bwc.start_time = datetime.datetime.now()
@@ -449,7 +453,6 @@ def _execute_batch(
449453
else:
450454
request_id, msg, to_send = bwc.batch_command(cmd, ops)
451455
result = self.write_command(bwc, cmd, request_id, msg, to_send, client) # type: ignore[arg-type]
452-
client._process_response(result, bwc.session) # type: ignore[arg-type]
453456

454457
return result, to_send # type: ignore[return-value]
455458

pymongo/synchronous/client_bulk.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,8 @@ def write_command(
283283
)
284284
if bwc.publish:
285285
bwc._succeed(request_id, reply, duration) # type: ignore[arg-type]
286+
# Process the response from the server.
287+
self.client._process_response(reply, bwc.session) # type: ignore[arg-type]
286288
except Exception as exc:
287289
duration = datetime.datetime.now() - bwc.start_time
288290
if isinstance(exc, (NotPrimaryError, OperationFailure)):
@@ -312,6 +314,11 @@ def write_command(
312314
bwc._fail(request_id, failure, duration)
313315
# Top-level error will be embedded in ClientBulkWriteException.
314316
reply = {"error": exc}
317+
# Process the response from the server.
318+
if isinstance(exc, OperationFailure):
319+
self.client._process_response(exc.details, bwc.session) # type: ignore[arg-type]
320+
else:
321+
self.client._process_response({}, bwc.session) # type: ignore[arg-type]
315322
finally:
316323
bwc.start_time = datetime.datetime.now()
317324
return reply # type: ignore[return-value]
@@ -429,7 +436,6 @@ def _execute_batch(
429436
"""Executes a batch of bulkWrite server commands (ack)."""
430437
request_id, msg, to_send_ops, to_send_ns = bwc.batch_command(cmd, ops, namespaces)
431438
result = self.write_command(bwc, cmd, request_id, msg, to_send_ops, to_send_ns, self.client) # type: ignore[arg-type]
432-
self.client._process_response(result, bwc.session) # type: ignore[arg-type]
433439
return result, to_send_ops, to_send_ns # type: ignore[return-value]
434440

435441
def _process_results_cursor(

0 commit comments

Comments
 (0)