Skip to content

Commit 606eaa6

Browse files
authored
Merge branch 'master' into PYTHON-4927
2 parents 9c0c54b + 9f53f29 commit 606eaa6

34 files changed

+262
-333
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Create Release Branch
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
branch_name:
7+
description: The name of the new branch
8+
required: true
9+
version:
10+
description: The version to set on the branch
11+
required: true
12+
base_ref:
13+
description: The base reference for the branch
14+
push_changes:
15+
description: Whether to push the changes
16+
default: "true"
17+
18+
concurrency:
19+
group: create-branch-${{ github.ref }}
20+
cancel-in-progress: true
21+
22+
defaults:
23+
run:
24+
shell: bash -eux {0}
25+
26+
jobs:
27+
create-branch:
28+
environment: release
29+
runs-on: ubuntu-latest
30+
permissions:
31+
id-token: write
32+
contents: write
33+
outputs:
34+
version: ${{ steps.pre-publish.outputs.version }}
35+
steps:
36+
- uses: mongodb-labs/drivers-github-tools/secure-checkout@v2
37+
with:
38+
app_id: ${{ vars.APP_ID }}
39+
private_key: ${{ secrets.APP_PRIVATE_KEY }}
40+
- uses: mongodb-labs/drivers-github-tools/setup@v2
41+
with:
42+
aws_role_arn: ${{ secrets.AWS_ROLE_ARN }}
43+
aws_region_name: ${{ vars.AWS_REGION_NAME }}
44+
aws_secret_id: ${{ secrets.AWS_SECRET_ID }}
45+
artifactory_username: ${{ vars.ARTIFACTORY_USERNAME }}
46+
- uses: mongodb-labs/drivers-github-tools/create-branch@v2
47+
id: create-branch
48+
with:
49+
branch_name: ${{ inputs.branch_name }}
50+
version: ${{ inputs.version }}
51+
base_ref: ${{ inputs.base_ref }}
52+
push_changes: ${{ inputs.push_changes }}
53+
version_bump_script: hatch version
54+
evergreen_project: mongo-python-driver-release
55+
release_workflow_path: ./.github/workflows/release-python.yml

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ The PyMongo distribution contains tools for interacting with MongoDB
1111
database from Python. The `bson` package is an implementation of the
1212
[BSON format](http://bsonspec.org) for Python. The `pymongo` package is
1313
a native Python driver for MongoDB. The `gridfs` package is a
14-
[gridfs](https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.rst/)
14+
[gridfs](https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.md/)
1515
implementation on top of `pymongo`.
1616

1717
PyMongo supports MongoDB 4.0, 4.2, 4.4, 5.0, 6.0, 7.0, and 8.0.

bson/json_util.py

+24-21
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
when :const:`CANONICAL_JSON_OPTIONS` or :const:`LEGACY_JSON_OPTIONS` is
2323
provided, respectively.
2424
25-
.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json.rst
25+
.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md
2626
2727
Example usage (deserialization):
2828
@@ -617,25 +617,28 @@ def _parse_canonical_datetime(
617617
raise TypeError(f"Bad $date, extra field(s): {doc}")
618618
# mongoexport 2.6 and newer
619619
if isinstance(dtm, str):
620-
# Parse offset
621-
if dtm[-1] == "Z":
622-
dt = dtm[:-1]
623-
offset = "Z"
624-
elif dtm[-6] in ("+", "-") and dtm[-3] == ":":
625-
# (+|-)HH:MM
626-
dt = dtm[:-6]
627-
offset = dtm[-6:]
628-
elif dtm[-5] in ("+", "-"):
629-
# (+|-)HHMM
630-
dt = dtm[:-5]
631-
offset = dtm[-5:]
632-
elif dtm[-3] in ("+", "-"):
633-
# (+|-)HH
634-
dt = dtm[:-3]
635-
offset = dtm[-3:]
636-
else:
637-
dt = dtm
638-
offset = ""
620+
try:
621+
# Parse offset
622+
if dtm[-1] == "Z":
623+
dt = dtm[:-1]
624+
offset = "Z"
625+
elif dtm[-6] in ("+", "-") and dtm[-3] == ":":
626+
# (+|-)HH:MM
627+
dt = dtm[:-6]
628+
offset = dtm[-6:]
629+
elif dtm[-5] in ("+", "-"):
630+
# (+|-)HHMM
631+
dt = dtm[:-5]
632+
offset = dtm[-5:]
633+
elif dtm[-3] in ("+", "-"):
634+
# (+|-)HH
635+
dt = dtm[:-3]
636+
offset = dtm[-3:]
637+
else:
638+
dt = dtm
639+
offset = ""
640+
except IndexError as exc:
641+
raise ValueError(f"time data {dtm!r} does not match ISO-8601 datetime format") from exc
639642

640643
# Parse the optional factional seconds portion.
641644
dot_index = dt.rfind(".")
@@ -848,7 +851,7 @@ def _encode_datetimems(obj: Any, json_options: JSONOptions) -> dict:
848851
):
849852
return _encode_datetime(obj.as_datetime(), json_options)
850853
elif json_options.datetime_representation == DatetimeRepresentation.LEGACY:
851-
return {"$date": str(int(obj))}
854+
return {"$date": int(obj)}
852855
return {"$date": {"$numberLong": str(int(obj))}}
853856

854857

doc/api/index.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ interacting with MongoDB. :mod:`bson` is an implementation of the
66
`BSON format <http://bsonspec.org>`_, :mod:`pymongo` is a
77
full-featured driver for MongoDB, and :mod:`gridfs` is a set of tools
88
for working with the `GridFS
9-
<https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.rst/>`_ storage
9+
<https://github.com/mongodb/specifications/blob/master/source/gridfs/gridfs-spec.md/>`_ storage
1010
specification.
1111

1212
.. toctree::

doc/changelog.rst

+14-4
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ PyMongo 4.11 brings a number of changes including:
1212

1313
- Dropped support for Python 3.8.
1414
- Dropped support for MongoDB 3.6.
15+
- Dropped support for the MONGODB-CR authenticate mechanism, which is no longer supported by MongoDB 4.0+.
1516
- Added support for free-threaded Python with the GIL disabled. For more information see:
1617
`Free-threaded CPython <https://docs.python.org/3.13/whatsnew/3.13.html#whatsnew313-free-threaded-cpython>`_.
1718
- :attr:`~pymongo.asynchronous.mongo_client.AsyncMongoClient.address` and
@@ -23,6 +24,15 @@ PyMongo 4.11 brings a number of changes including:
2324
:meth:`~pymongo.collection.Collection.update_one`, :meth:`~pymongo.collection.Collection.replace_one`,
2425
:class:`~pymongo.operations.UpdateOne`, and
2526
:class:`~pymongo.operations.UpdateMany`,
27+
- :meth:`~pymongo.mongo_client.MongoClient.bulk_write` and
28+
:meth:`~pymongo.asynchronous.mongo_client.AsyncMongoClient.bulk_write` now throw an error
29+
when ``ordered=True`` or ``verboseResults=True`` are used with unacknowledged writes.
30+
These are unavoidable breaking changes.
31+
- Fixed a bug in :const:`bson.json_util.dumps` where a :class:`bson.datetime_ms.DatetimeMS` would
32+
be incorrectly encoded as ``'{"$date": "X"}'`` instead of ``'{"$date": X}'`` when using the
33+
legacy MongoDB Extended JSON datetime representation.
34+
- Fixed a bug where :const:`bson.json_util.loads` would raise an IndexError when parsing an invalid
35+
``"$date"`` instead of a ValueError.
2636

2737
Issues Resolved
2838
...............
@@ -1022,7 +1032,7 @@ See the `PyMongo 4.0 release notes in JIRA`_ for the list of resolved issues
10221032
in this release.
10231033

10241034
.. _PyMongo 4.0 release notes in JIRA: https://jira.mongodb.org/secure/ReleaseNote.jspa?projectId=10004&version=18463
1025-
.. _DBRef specification: https://github.com/mongodb/specifications/blob/5a8c8d7/source/dbref.rst
1035+
.. _DBRef specification: https://github.com/mongodb/specifications/blob/master/source/dbref/dbref.md
10261036

10271037
Changes in Version 3.13.0 (2022/11/01)
10281038
--------------------------------------
@@ -1557,7 +1567,7 @@ Unavoidable breaking changes:
15571567
bumped to 1.16.0. This is a breaking change for applications that use
15581568
PyMongo's SRV support with a version of ``dnspython`` older than 1.16.0.
15591569

1560-
.. _URI options specification: https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.rst
1570+
.. _URI options specification: https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.md
15611571

15621572

15631573
Issues Resolved
@@ -1581,7 +1591,7 @@ Changes in Version 3.8.0 (2019/04/22)
15811591
must upgrade to PyPy3.5+.
15821592

15831593
- :class:`~bson.objectid.ObjectId` now implements the `ObjectID specification
1584-
version 0.2 <https://github.com/mongodb/specifications/blob/master/source/objectid.rst>`_.
1594+
version 0.2 <https://github.com/mongodb/specifications/blob/master/source/bson-objectid/objectid.md>`_.
15851595
- For better performance and to better follow the GridFS spec,
15861596
:class:`~gridfs.grid_file.GridOut` now uses a single cursor to read all the
15871597
chunks in the file. Previously, each chunk in the file was queried
@@ -1943,7 +1953,7 @@ Highlights include:
19431953
:class:`~pymongo.operations.UpdateOne`, and
19441954
:class:`~pymongo.operations.UpdateMany`.
19451955
- Implemented the `MongoDB Extended JSON
1946-
<https://github.com/mongodb/specifications/blob/master/source/extended-json.rst>`_
1956+
<https://github.com/mongodb/specifications/blob/master/source/extended-json/extended-json.md>`_
19471957
specification.
19481958
- :class:`~bson.decimal128.Decimal128` now works when cdecimal is installed.
19491959
- PyMongo is now tested against a wider array of operating systems and CPU

doc/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@
8585
# wiki.centos.org has been flakey.
8686
# sourceforge.net is giving a 403 error, but is still accessible from the browser.
8787
linkcheck_ignore = [
88-
"https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.rst#requesting-an-immediate-check",
88+
"https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.md#requesting-an-immediate-check",
8989
"https://github.com/mongodb/libmongocrypt/blob/master/bindings/python/README.rst#installing-from-source",
9090
r"https://wiki.centos.org/[\w/]*",
9191
r"http://sourceforge.net/",

doc/developer/periodic_executor.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ Thus the current design of periodic executors is surprisingly simple: they
106106
do a simple ``time.sleep`` for a half-second, check if it is time to wake or
107107
terminate, and sleep again.
108108

109-
.. _Server Discovery And Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.rst#requesting-an-immediate-check
109+
.. _Server Discovery And Monitoring Spec: https://github.com/mongodb/specifications/blob/master/source/server-discovery-and-monitoring/server-monitoring.md#requesting-an-immediate-check
110110

111111
.. _PYTHON-863: https://jira.mongodb.org/browse/PYTHON-863
112112

doc/examples/authentication.rst

+1-20
Original file line numberDiff line numberDiff line change
@@ -76,24 +76,6 @@ For best performance on Python versions older than 2.7.8 install `backports.pbkd
7676

7777
.. _backports.pbkdf2: https://pypi.python.org/pypi/backports.pbkdf2/
7878

79-
MONGODB-CR
80-
----------
81-
82-
.. warning:: MONGODB-CR was deprecated with the release of MongoDB 3.6 and
83-
is no longer supported by MongoDB 4.0.
84-
85-
Before MongoDB 3.0 the default authentication mechanism was MONGODB-CR,
86-
the "MongoDB Challenge-Response" protocol::
87-
88-
>>> from pymongo import MongoClient
89-
>>> client = MongoClient('example.com',
90-
... username='user',
91-
... password='password',
92-
... authMechanism='MONGODB-CR')
93-
>>>
94-
>>> uri = "mongodb://user:[email protected]/?authSource=the_database&authMechanism=MONGODB-CR"
95-
>>> client = MongoClient(uri)
96-
9779
Default Authentication Mechanism
9880
--------------------------------
9981

@@ -221,8 +203,7 @@ SASL PLAIN (RFC 4616)
221203

222204
MongoDB Enterprise Edition version 2.6 and newer support the SASL PLAIN
223205
authentication mechanism, initially intended for delegating authentication
224-
to an LDAP server. Using the PLAIN mechanism is very similar to MONGODB-CR.
225-
These examples use the $external virtual database for LDAP support::
206+
to an LDAP server. These examples use the $external virtual database for LDAP support::
226207

227208
>>> from pymongo import MongoClient
228209
>>> uri = "mongodb://user:[email protected]/?authMechanism=PLAIN"

doc/examples/uuid.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ Finally, the same UUID would historically be serialized by the Java driver as::
8484
.. note:: For in-depth information about the the byte-order historically
8585
used by different drivers, see the `Handling of Native UUID Types
8686
Specification
87-
<https://github.com/mongodb/specifications/blob/master/source/uuid.rst>`_.
87+
<https://github.com/mongodb/specifications/blob/master/source/bson-binary-uuid/uuid.md>`_.
8888

8989
This difference in the byte-order of UUIDs encoded by different drivers can
9090
result in highly unintuitive behavior in some scenarios. We detail two such

doc/migrate-to-pymongo4.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ Renamed URI options
118118

119119
Several deprecated URI options have been renamed to the standardized
120120
option names defined in the
121-
`URI options specification <https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.rst>`_.
121+
`URI options specification <https://github.com/mongodb/specifications/blob/master/source/uri-options/uri-options.md>`_.
122122
The old option names and their renamed equivalents are summarized in the table
123123
below. Some renamed options have different semantics from the option being
124124
replaced as noted in the 'Migration Notes' column.
@@ -965,7 +965,7 @@ correct type. Otherwise the document is returned as normal. Previously, any
965965
subdocument containing a ``$ref`` field would be decoded as a
966966
:class:`~bson.dbref.DBRef`.
967967

968-
.. _DBRef specification: https://github.com/mongodb/specifications/blob/5a8c8d7/source/dbref.rst
968+
.. _DBRef specification: https://github.com/mongodb/specifications/blob/master/source/dbref/dbref.md
969969

970970
Encoding a UUID raises an error by default
971971
..........................................

pymongo/asynchronous/auth.py

-16
Original file line numberDiff line numberDiff line change
@@ -329,21 +329,6 @@ async def _authenticate_x509(credentials: MongoCredential, conn: AsyncConnection
329329
await conn.command("$external", cmd)
330330

331331

332-
async def _authenticate_mongo_cr(credentials: MongoCredential, conn: AsyncConnection) -> None:
333-
"""Authenticate using MONGODB-CR."""
334-
source = credentials.source
335-
username = credentials.username
336-
password = credentials.password
337-
# Get a nonce
338-
response = await conn.command(source, {"getnonce": 1})
339-
nonce = response["nonce"]
340-
key = _auth_key(nonce, username, password)
341-
342-
# Actually authenticate
343-
query = {"authenticate": 1, "user": username, "nonce": nonce, "key": key}
344-
await conn.command(source, query)
345-
346-
347332
async def _authenticate_default(credentials: MongoCredential, conn: AsyncConnection) -> None:
348333
if conn.max_wire_version >= 7:
349334
if conn.negotiated_mechs:
@@ -365,7 +350,6 @@ async def _authenticate_default(credentials: MongoCredential, conn: AsyncConnect
365350

366351
_AUTH_MAP: Mapping[str, Callable[..., Coroutine[Any, Any, None]]] = {
367352
"GSSAPI": _authenticate_gssapi,
368-
"MONGODB-CR": _authenticate_mongo_cr,
369353
"MONGODB-X509": _authenticate_x509,
370354
"MONGODB-AWS": _authenticate_aws,
371355
"MONGODB-OIDC": _authenticate_oidc, # type:ignore[dict-item]

pymongo/asynchronous/client_bulk.py

+5-44
Original file line numberDiff line numberDiff line change
@@ -681,11 +681,11 @@ async def retryable_bulk(
681681
_throw_client_bulk_write_exception(full_result, self.verbose_results)
682682
return full_result
683683

684-
async def execute_command_unack_unordered(
684+
async def execute_command_unack(
685685
self,
686686
conn: AsyncConnection,
687687
) -> None:
688-
"""Execute commands with OP_MSG and w=0 writeConcern, unordered."""
688+
"""Execute commands with OP_MSG and w=0 writeConcern. Always unordered."""
689689
db_name = "admin"
690690
cmd_name = "bulkWrite"
691691
listeners = self.client._event_listeners
@@ -704,8 +704,8 @@ async def execute_command_unack_unordered(
704704
while self.idx_offset < self.total_ops:
705705
# Construct the server command, specifying the relevant options.
706706
cmd = {"bulkWrite": 1}
707-
cmd["errorsOnly"] = not self.verbose_results
708-
cmd["ordered"] = self.ordered # type: ignore[assignment]
707+
cmd["errorsOnly"] = True
708+
cmd["ordered"] = False
709709
if self.bypass_doc_val is not None:
710710
cmd["bypassDocumentValidation"] = self.bypass_doc_val
711711
cmd["writeConcern"] = {"w": 0} # type: ignore[assignment]
@@ -723,43 +723,6 @@ async def execute_command_unack_unordered(
723723

724724
self.idx_offset += len(to_send_ops)
725725

726-
async def execute_command_unack_ordered(
727-
self,
728-
conn: AsyncConnection,
729-
) -> None:
730-
"""Execute commands with OP_MSG and w=0 WriteConcern, ordered."""
731-
full_result: MutableMapping[str, Any] = {
732-
"anySuccessful": False,
733-
"error": None,
734-
"writeErrors": [],
735-
"writeConcernErrors": [],
736-
"nInserted": 0,
737-
"nUpserted": 0,
738-
"nMatched": 0,
739-
"nModified": 0,
740-
"nDeleted": 0,
741-
"insertResults": {},
742-
"updateResults": {},
743-
"deleteResults": {},
744-
}
745-
# Ordered bulk writes have to be acknowledged so that we stop
746-
# processing at the first error, even when the application
747-
# specified unacknowledged writeConcern.
748-
initial_write_concern = WriteConcern()
749-
op_id = _randint()
750-
try:
751-
await self._execute_command(
752-
initial_write_concern,
753-
None,
754-
conn,
755-
op_id,
756-
False,
757-
full_result,
758-
self.write_concern,
759-
)
760-
except OperationFailure:
761-
pass
762-
763726
async def execute_no_results(
764727
self,
765728
conn: AsyncConnection,
@@ -775,9 +738,7 @@ async def execute_no_results(
775738
"Cannot set bypass_document_validation with unacknowledged write concern"
776739
)
777740

778-
if self.ordered:
779-
return await self.execute_command_unack_ordered(conn)
780-
return await self.execute_command_unack_unordered(conn)
741+
return await self.execute_command_unack(conn)
781742

782743
async def execute(
783744
self,

0 commit comments

Comments
 (0)