Skip to content

Commit a48d26c

Browse files
committed
PYTHON-2680 Make breaking changes to DBRef BSON+JSON encoding/decoding TODO: C extensions
PYTHON-2841 resync bson corpus tests
1 parent 9dc7758 commit a48d26c

File tree

4 files changed

+8
-12
lines changed

4 files changed

+8
-12
lines changed

bson/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ def _get_object(data, view, position, obj_end, opts, dummy):
202202
obj = _elements_to_dict(data, view, position + 4, end, opts)
203203

204204
position += obj_size
205-
if "$ref" in obj:
205+
# If DBRef validation fails, return a normal doc.
206+
if isinstance(obj.get('$ref'), str) and "$id" in obj and isinstance(obj.get('$db'), (str, type(None))):
206207
return (DBRef(obj.pop("$ref"), obj.pop("$id", None),
207208
obj.pop("$db", None), obj), position)
208209
return obj, position

bson/json_util.py

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,6 @@
121121
"x": re.X,
122122
}
123123

124-
# Dollar-prefixed keys which may appear in DBRefs.
125-
_DBREF_KEYS = frozenset(['$id', '$ref', '$db'])
126-
127124

128125
class DatetimeRepresentation:
129126
LEGACY = 0
@@ -436,7 +433,7 @@ def object_pairs_hook(pairs, json_options=DEFAULT_JSON_OPTIONS):
436433
def object_hook(dct, json_options=DEFAULT_JSON_OPTIONS):
437434
if "$oid" in dct:
438435
return _parse_canonical_oid(dct)
439-
if "$ref" in dct:
436+
if isinstance(dct.get('$ref'), str) and "$id" in dct and isinstance(dct.get('$db'), (str, type(None))):
440437
return _parse_canonical_dbref(dct)
441438
if "$date" in dct:
442439
return _parse_canonical_datetime(dct, json_options)
@@ -649,10 +646,6 @@ def _parse_canonical_regex(doc):
649646

650647
def _parse_canonical_dbref(doc):
651648
"""Decode a JSON DBRef to bson.dbref.DBRef."""
652-
for key in doc:
653-
if key.startswith('$') and key not in _DBREF_KEYS:
654-
# Other keys start with $, so dct cannot be parsed as a DBRef.
655-
return doc
656649
return DBRef(doc.pop('$ref'), doc.pop('$id'),
657650
database=doc.pop('$db', None), **doc)
658651

test/bson_corpus/dbref.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@
2525
{
2626
"description": "Document with key names similar to those of a DBRef",
2727
"canonical_bson": "3e0000000224726566000c0000006e6f742d612d646272656600072469640058921b3e6e32ab156a22b59e022462616e616e6100050000007065656c0000",
28-
"canonical_extjson": "{\"$ref\": \"not-a-dbref\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$banana\": \"peel\"}"
28+
"canonical_extjson": "{\"$ref\": \"not-a-dbref\", \"$id\": {\"$oid\": \"58921b3e6e32ab156a22b59e\"}, \"$banana\": \"peel\"}",
29+
"lossy": true
2930
},
3031
{
3132
"description": "DBRef with additional dollar-prefixed and dotted fields",

test/test_bson_corpus.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ def run_test(self):
135135
# Make sure we can parse the legacy (default) JSON format.
136136
legacy_json = json_util.dumps(
137137
decoded_bson, json_options=json_util.LEGACY_JSON_OPTIONS)
138-
self.assertEqual(decode_extjson(legacy_json), decoded_bson)
138+
self.assertEqual(
139+
decode_extjson(legacy_json), decoded_bson, description)
139140

140141
if deprecated:
141142
if 'converted_bson' in valid_case:
@@ -157,7 +158,7 @@ def run_test(self):
157158
if not (sys.platform.startswith("java") and
158159
description == 'NaN with payload'):
159160
# Test round-tripping canonical bson.
160-
self.assertEqual(encode_bson(decoded_bson), cB)
161+
self.assertEqual(encode_bson(decoded_bson), cB, description)
161162
self.assertJsonEqual(encode_extjson(decoded_bson), cEJ)
162163

163164
# Test round-tripping canonical extended json.

0 commit comments

Comments
 (0)