17
17
This module provides two helper methods `dumps` and `loads` that wrap the
18
18
native :mod:`json` methods and provide explicit BSON conversion to and from
19
19
JSON. :class:`~bson.json_util.JSONOptions` provides a way to control how JSON
20
- is emitted and parsed, with the default being the legacy PyMongo format.
21
- :mod:`~bson.json_util` can also generate Canonical or Relaxed `Extended JSON`_
22
- when :const:`CANONICAL_JSON_OPTIONS` or :const:`RELAXED_JSON_OPTIONS ` is
20
+ is emitted and parsed, with the default being the Relaxed Extended JSON format.
21
+ :mod:`~bson.json_util` can also generate Canonical or legacy `Extended JSON`_
22
+ when :const:`CANONICAL_JSON_OPTIONS` or :const:`LEGACY_JSON_OPTIONS ` is
23
23
provided, respectively.
24
24
25
25
.. _Extended JSON: https://github.com/mongodb/specifications/blob/master/source/extended-json.rst
32
32
>>> loads('[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$scope": {}, "$code": "function x() { return 1; }"}}, {"bin": {"$type": "80", "$binary": "AQIDBA=="}}]')
33
33
[{'foo': [1, 2]}, {'bar': {'hello': 'world'}}, {'code': Code('function x() { return 1; }', {})}, {'bin': Binary(b'...', 128)}]
34
34
35
- Example usage (serialization ):
35
+ Example usage with :const:`RELAXED_JSON_OPTIONS` (the default ):
36
36
37
37
.. doctest::
38
38
39
39
>>> from bson import Binary, Code
40
40
>>> from bson.json_util import dumps
41
41
>>> dumps([{'foo': [1, 2]},
42
42
... {'bar': {'hello': 'world'}},
43
- ... {'code': Code("function x() { return 1; }", {} )},
43
+ ... {'code': Code("function x() { return 1; }")},
44
44
... {'bin': Binary(b"\x01 \x02 \x03 \x04 ")}])
45
- '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}} , {"bin": {"$binary": " AQIDBA==", "$type ": "00"}}]'
45
+ '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}} , {"bin": {"$binary": {"base64": " AQIDBA==", "subType ": "00"} }}]'
46
46
47
47
Example usage (with :const:`CANONICAL_JSON_OPTIONS`):
48
48
57
57
... json_options=CANONICAL_JSON_OPTIONS)
58
58
'[{"foo": [{"$numberInt": "1"}, {"$numberInt": "2"}]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}}, {"bin": {"$binary": {"base64": "AQIDBA==", "subType": "00"}}}]'
59
59
60
- Example usage (with :const:`RELAXED_JSON_OPTIONS `):
60
+ Example usage (with :const:`LEGACY_JSON_OPTIONS `):
61
61
62
62
.. doctest::
63
63
64
64
>>> from bson import Binary, Code
65
- >>> from bson.json_util import dumps, RELAXED_JSON_OPTIONS
65
+ >>> from bson.json_util import dumps, LEGACY_JSON_OPTIONS
66
66
>>> dumps([{'foo': [1, 2]},
67
67
... {'bar': {'hello': 'world'}},
68
- ... {'code': Code("function x() { return 1; }")},
68
+ ... {'code': Code("function x() { return 1; }", {} )},
69
69
... {'bin': Binary(b"\x01 \x02 \x03 \x04 ")}],
70
- ... json_options=RELAXED_JSON_OPTIONS )
71
- '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }"}} , {"bin": {"$binary": {"base64": " AQIDBA==", "subType ": "00"} }}]'
70
+ ... json_options=LEGACY_JSON_OPTIONS )
71
+ '[{"foo": [1, 2]}, {"bar": {"hello": "world"}}, {"code": {"$code": "function x() { return 1; }", "$scope": {}}} , {"bin": {"$binary": " AQIDBA==", "$type ": "00"}}]'
72
72
73
73
Alternatively, you can manually pass the `default` to :func:`json.dumps`.
74
74
It won't handle :class:`~bson.binary.Binary` and :class:`~bson.code.Code`
@@ -238,23 +238,27 @@ class JSONOptions(CodecOptions):
238
238
239
239
.. seealso:: The specification for Relaxed and Canonical `Extended JSON`_.
240
240
241
- .. versionadded:: 3.4
241
+ .. versionchanged:: 4.0
242
+ The default for `json_mode` was changed from :const:`JSONMode.LEGACY`
243
+ to :const:`JSONMode.RELAXED`.
242
244
243
245
.. versionchanged:: 3.5
244
246
Accepts the optional parameter `json_mode`.
245
247
248
+ .. versionadded:: 3.4
246
249
"""
247
250
248
- def __new__ (cls , strict_number_long = False ,
249
- datetime_representation = DatetimeRepresentation . LEGACY ,
250
- strict_uuid = False , json_mode = JSONMode .LEGACY ,
251
+ def __new__ (cls , strict_number_long = None ,
252
+ datetime_representation = None ,
253
+ strict_uuid = None , json_mode = JSONMode .RELAXED ,
251
254
* args , ** kwargs ):
252
255
kwargs ["tz_aware" ] = kwargs .get ("tz_aware" , True )
253
256
if kwargs ["tz_aware" ]:
254
257
kwargs ["tzinfo" ] = kwargs .get ("tzinfo" , utc )
255
258
if datetime_representation not in (DatetimeRepresentation .LEGACY ,
256
259
DatetimeRepresentation .NUMBERLONG ,
257
- DatetimeRepresentation .ISO8601 ):
260
+ DatetimeRepresentation .ISO8601 ,
261
+ None ):
258
262
raise ConfigurationError (
259
263
"JSONOptions.datetime_representation must be one of LEGACY, "
260
264
"NUMBERLONG, or ISO8601 from DatetimeRepresentation." )
@@ -267,17 +271,47 @@ def __new__(cls, strict_number_long=False,
267
271
"or CANONICAL from JSONMode." )
268
272
self .json_mode = json_mode
269
273
if self .json_mode == JSONMode .RELAXED :
274
+ if strict_number_long :
275
+ raise ConfigurationError (
276
+ "Cannot specify strict_number_long=True with"
277
+ " JSONMode.RELAXED" )
278
+ if datetime_representation not in (None ,
279
+ DatetimeRepresentation .ISO8601 ):
280
+ raise ConfigurationError (
281
+ "datetime_representation must be DatetimeRepresentation."
282
+ "ISO8601 or omitted with JSONMode.RELAXED" )
283
+ if strict_uuid not in (None , True ):
284
+ raise ConfigurationError (
285
+ "Cannot specify strict_uuid=False with JSONMode.RELAXED" )
270
286
self .strict_number_long = False
271
287
self .datetime_representation = DatetimeRepresentation .ISO8601
272
288
self .strict_uuid = True
273
289
elif self .json_mode == JSONMode .CANONICAL :
290
+ if strict_number_long not in (None , True ):
291
+ raise ConfigurationError (
292
+ "Cannot specify strict_number_long=False with"
293
+ " JSONMode.RELAXED" )
294
+ if datetime_representation not in (
295
+ None , DatetimeRepresentation .NUMBERLONG ):
296
+ raise ConfigurationError (
297
+ "datetime_representation must be DatetimeRepresentation."
298
+ "NUMBERLONG or omitted with JSONMode.RELAXED" )
299
+ if strict_uuid not in (None , True ):
300
+ raise ConfigurationError (
301
+ "Cannot specify strict_uuid=False with JSONMode.RELAXED" )
274
302
self .strict_number_long = True
275
303
self .datetime_representation = DatetimeRepresentation .NUMBERLONG
276
304
self .strict_uuid = True
277
- else :
278
- self .strict_number_long = strict_number_long
279
- self .datetime_representation = datetime_representation
280
- self .strict_uuid = strict_uuid
305
+ else : # JSONMode.LEGACY
306
+ self .strict_number_long = False
307
+ self .datetime_representation = DatetimeRepresentation .LEGACY
308
+ self .strict_uuid = False
309
+ if strict_number_long is not None :
310
+ self .strict_number_long = strict_number_long
311
+ if datetime_representation is not None :
312
+ self .datetime_representation = datetime_representation
313
+ if strict_uuid is not None :
314
+ self .strict_uuid = strict_uuid
281
315
return self
282
316
283
317
def _arguments_repr (self ):
@@ -307,7 +341,7 @@ def with_options(self, **kwargs):
307
341
>>> from bson.json_util import CANONICAL_JSON_OPTIONS
308
342
>>> CANONICAL_JSON_OPTIONS.tz_aware
309
343
True
310
- >>> json_options = CANONICAL_JSON_OPTIONS.with_options(tz_aware=False)
344
+ >>> json_options = CANONICAL_JSON_OPTIONS.with_options(tz_aware=False, tzinfo=None )
311
345
>>> json_options.tz_aware
312
346
False
313
347
@@ -329,15 +363,6 @@ def with_options(self, **kwargs):
329
363
.. versionadded:: 3.5
330
364
"""
331
365
332
- DEFAULT_JSON_OPTIONS = LEGACY_JSON_OPTIONS
333
- """The default :class:`JSONOptions` for JSON encoding/decoding.
334
-
335
- The same as :const:`LEGACY_JSON_OPTIONS`. This will change to
336
- :const:`RELAXED_JSON_OPTIONS` in a future release.
337
-
338
- .. versionadded:: 3.4
339
- """
340
-
341
366
CANONICAL_JSON_OPTIONS = JSONOptions (json_mode = JSONMode .CANONICAL )
342
367
""":class:`JSONOptions` for Canonical Extended JSON.
343
368
@@ -354,18 +379,16 @@ def with_options(self, **kwargs):
354
379
.. versionadded:: 3.5
355
380
"""
356
381
357
- STRICT_JSON_OPTIONS = JSONOptions (
358
- strict_number_long = True ,
359
- datetime_representation = DatetimeRepresentation .ISO8601 ,
360
- strict_uuid = True )
361
- """**DEPRECATED** - :class:`JSONOptions` for MongoDB Extended JSON's *Strict
362
- mode* encoding.
382
+ DEFAULT_JSON_OPTIONS = RELAXED_JSON_OPTIONS
383
+ """The default :class:`JSONOptions` for JSON encoding/decoding.
363
384
364
- .. versionadded:: 3.4
385
+ The same as :const:`RELAXED_JSON_OPTIONS`.
386
+
387
+ .. versionchanged:: 4.0
388
+ Changed from :const:`LEGACY_JSON_OPTIONS` to
389
+ :const:`RELAXED_JSON_OPTIONS`.
365
390
366
- .. versionchanged:: 3.5
367
- Deprecated. Use :const:`RELAXED_JSON_OPTIONS` or
368
- :const:`CANONICAL_JSON_OPTIONS` instead.
391
+ .. versionadded:: 3.4
369
392
"""
370
393
371
394
@@ -380,6 +403,10 @@ def dumps(obj, *args, **kwargs):
380
403
encoding of MongoDB Extended JSON types. Defaults to
381
404
:const:`DEFAULT_JSON_OPTIONS`.
382
405
406
+ .. versionchanged:: 4.0
407
+ Now outputs MongoDB Relaxed Extended JSON by default (using
408
+ :const:`DEFAULT_JSON_OPTIONS`).
409
+
383
410
.. versionchanged:: 3.4
384
411
Accepts optional parameter `json_options`. See :class:`JSONOptions`.
385
412
"""
0 commit comments