Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions bson/json_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,8 @@ def _parse_binary(doc: Any, json_options: JSONOptions) -> Union[Binary, uuid.UUI

def _parse_timestamp(doc: Any, dummy0: Any) -> Timestamp:
tsp = doc["$timestamp"]
if set(tsp) != {"t", "i"}:
raise TypeError(f'$timestamp must include exactly "t" and "i" components: {doc}')
return Timestamp(tsp["t"], tsp["i"])


Expand Down
2 changes: 2 additions & 0 deletions doc/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ PyMongo 4.18 brings a number of changes including:
the bytes remaining in the array now raises
:class:`~bson.errors.InvalidBSON` instead of reading past the end of the
buffer.
- Fixed :func:`bson.json_util.loads` to reject ``$timestamp`` values containing
fields other than ``t`` and ``i``.

Changes in Version 4.17.0 (2026/04/20)
--------------------------------------
Expand Down
1 change: 1 addition & 0 deletions doc/contributors.rst
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,4 @@ The following is a list of people who have contributed to
- Noah Stapp (NoahStapp)
- Cal Jacobson (cj81499)
- Sophia Yang (sophiayangDB)
- Madan Kumar (winklemad)
12 changes: 12 additions & 0 deletions test/test_json_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,18 @@ def test_timestamp(self):
self.assertEqual(dct, rtdct)
self.assertEqual('{"ts": {"$timestamp": {"t": 4, "i": 13}}}', res)

def test_timestamp_with_invalid_fields(self):
invalid_values = [
'{"t": 4, "i": 13, "extra": 1}',
'{"t": 4, "unexpected": 13}',
]
for value in invalid_values:
with self.subTest(value=value):
with self.assertRaisesRegex(
TypeError, r'\$timestamp must include exactly "t" and "i" components'
):
json_util.loads(f'{{"ts": {{"$timestamp": {value}}}}}')

def test_uuid_default(self):
# Cannot directly encode native UUIDs with the default
# uuid_representation.
Expand Down