PYTHON-1949 CodecOptions and JSONOptions should have the same default value for tz_aware (#720)

This commit is contained in:
Julius Park 2021-09-14 16:54:11 -07:00 committed by GitHub
parent fb20975a1f
commit e3771587c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 53 additions and 54 deletions

View File

@ -226,7 +226,7 @@ class JSONOptions(CodecOptions):
- `tz_aware`: If ``True``, MongoDB Extended JSON's *Strict mode* type
`Date` will be decoded to timezone aware instances of
:class:`datetime.datetime`. Otherwise they will be naive. Defaults
to ``True``.
to ``False``.
- `tzinfo`: A :class:`datetime.tzinfo` subclass that specifies the
timezone from which :class:`~datetime.datetime` objects should be
decoded. Defaults to :const:`~bson.tz_util.utc`.
@ -245,14 +245,15 @@ class JSONOptions(CodecOptions):
.. versionchanged:: 3.5
Accepts the optional parameter `json_mode`.
.. versionadded:: 3.4
.. versionchanged:: 4.0
Changed default value of `tz_aware` to False.
"""
def __new__(cls, strict_number_long=None,
datetime_representation=None,
strict_uuid=None, json_mode=JSONMode.RELAXED,
*args, **kwargs):
kwargs["tz_aware"] = kwargs.get("tz_aware", True)
kwargs["tz_aware"] = kwargs.get("tz_aware", False)
if kwargs["tz_aware"]:
kwargs["tzinfo"] = kwargs.get("tzinfo", utc)
if datetime_representation not in (DatetimeRepresentation.LEGACY,

View File

@ -123,6 +123,9 @@ Breaking Changes in 4.0
:class:`~bson.dbref.DBRef`.
- The "tls" install extra is no longer necessary or supported and will be
ignored by pip.
- ``tz_aware``, an argument for :class:`~bson.json_util.JSONOptions`,
now defaults to ``False`` instead of ``True``. ``json_util.loads`` now
decodes datetime as naive by default.
- ``directConnection`` URI option and keyword argument to :class:`~pymongo.mongo_client.MongoClient`
defaults to ``False`` instead of ``None``, allowing for the automatic
discovery of replica sets. This means that if you
@ -132,6 +135,7 @@ Breaking Changes in 4.0
with :meth:`~pymongo.collection.Collection.find`.
- ``name`` is now a required argument for the :class:`pymongo.driver_info.DriverInfo` class.
d
Notable improvements
....................

View File

@ -183,6 +183,14 @@ can be changed to this::
names = client.list_database_names()
``tz_aware`` defaults to ``False``
..................................
``tz_aware``, an argument for :class:`~bson.json_util.JSONOptions`,
now defaults to ``False`` instead of ``True``. ``json_util.loads`` now
decodes datetime as naive by default.
Database
--------

View File

@ -74,6 +74,7 @@ _DEPRECATED_BSON_TYPES = {
# Need to set tz_aware=True in order to use "strict" dates in extended JSON.
codec_options = CodecOptions(tz_aware=True, document_class=SON)
codec_options_no_tzaware = CodecOptions(document_class=SON)
# We normally encode UUID as binary subtype 0x03,
# but we'll need to encode to subtype 0x04 for one of the tests.
codec_options_uuid_04 = codec_options._replace(uuid_representation=STANDARD)
@ -93,7 +94,7 @@ to_relaxed_extjson = functools.partial(
to_bson_uuid_04 = functools.partial(encode,
codec_options=codec_options_uuid_04)
to_bson = functools.partial(encode, codec_options=codec_options)
decode_bson = lambda bbytes: decode(bbytes, codec_options=codec_options)
decode_bson = functools.partial(decode, codec_options=codec_options_no_tzaware)
decode_extjson = functools.partial(
json_util.loads,
json_options=json_util.JSONOptions(json_mode=JSONMode.CANONICAL,

View File

@ -22,7 +22,7 @@ import uuid
sys.path[0:0] = [""]
from bson import json_util, EPOCH_AWARE, SON
from bson import json_util, EPOCH_AWARE, EPOCH_NAIVE, SON
from bson.json_util import (DatetimeRepresentation,
JSONMode,
JSONOptions,
@ -103,61 +103,45 @@ class TestJsonUtil(unittest.TestCase):
json_util.dumps(DBRef('collection', 1, 'db')))
def test_datetime(self):
tz_aware_opts = json_util.DEFAULT_JSON_OPTIONS.with_options(
tz_aware=True)
# only millis, not micros
self.round_trip({"date": datetime.datetime(2009, 12, 9, 15, 49, 45,
191000, utc)}, json_options=tz_aware_opts)
self.round_trip({"date": datetime.datetime(2009, 12, 9, 15,
49, 45, 191000, utc)})
49, 45, 191000)})
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000+0000"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000000+0000"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000+00:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000000+00:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000000+00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000Z"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000000Z"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00Z"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
# No explicit offset
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T00:00:00.000000"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
# Localtime behind UTC
jsn = '{"dt": { "$date" : "1969-12-31T16:00:00.000-0800"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1969-12-31T16:00:00.000000-0800"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1969-12-31T16:00:00.000-08:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1969-12-31T16:00:00.000000-08:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1969-12-31T16:00:00.000000-08"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
# Localtime ahead of UTC
jsn = '{"dt": { "$date" : "1970-01-01T01:00:00.000+0100"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T01:00:00.000000+0100"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T01:00:00.000+01:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T01:00:00.000000+01:00"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
jsn = '{"dt": { "$date" : "1970-01-01T01:00:00.000000+01"}}'
self.assertEqual(EPOCH_AWARE, json_util.loads(jsn)["dt"])
for jsn in ['{"dt": { "$date" : "1970-01-01T00:00:00.000+0000"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000000+0000"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000+00:00"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000000+00:00"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000000+00"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000Z"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000000Z"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00Z"}}',
'{"dt": {"$date": "1970-01-01T00:00:00.000"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00"}}',
'{"dt": { "$date" : "1970-01-01T00:00:00.000000"}}',
'{"dt": { "$date" : "1969-12-31T16:00:00.000-0800"}}',
'{"dt": { "$date" : "1969-12-31T16:00:00.000000-0800"}}',
'{"dt": { "$date" : "1969-12-31T16:00:00.000-08:00"}}',
'{"dt": { "$date" : "1969-12-31T16:00:00.000000-08:00"}}',
'{"dt": { "$date" : "1969-12-31T16:00:00.000000-08"}}',
'{"dt": { "$date" : "1970-01-01T01:00:00.000+0100"}}',
'{"dt": { "$date" : "1970-01-01T01:00:00.000000+0100"}}',
'{"dt": { "$date" : "1970-01-01T01:00:00.000+01:00"}}',
'{"dt": { "$date" : "1970-01-01T01:00:00.000000+01:00"}}',
'{"dt": { "$date" : "1970-01-01T01:00:00.000000+01"}}'
]:
self.assertEqual(EPOCH_AWARE, json_util.loads(
jsn, json_options=tz_aware_opts)["dt"])
self.assertEqual(EPOCH_NAIVE, json_util.loads(jsn)["dt"])
dtm = datetime.datetime(1, 1, 1, 1, 1, 1, 0, utc)
jsn = '{"dt": {"$date": -62135593139000}}'
self.assertEqual(dtm, json_util.loads(jsn)["dt"])
self.assertEqual(dtm, json_util.loads(jsn, json_options=tz_aware_opts)["dt"])
jsn = '{"dt": {"$date": {"$numberLong": "-62135593139000"}}}'
self.assertEqual(dtm, json_util.loads(jsn)["dt"])
self.assertEqual(dtm, json_util.loads(jsn, json_options=tz_aware_opts)["dt"])
# Test dumps format
pre_epoch = {"dt": datetime.datetime(1, 1, 1, 1, 1, 1, 10000, utc)}
@ -207,7 +191,8 @@ class TestJsonUtil(unittest.TestCase):
self.assertEqual(
datetime.datetime(1972, 1, 1, 1, 1, 1, 10000, utc),
json_util.loads(
'{"dt": {"$date": "1972-01-01T01:01:01.010+0000"}}')["dt"])
'{"dt": {"$date": "1972-01-01T01:01:01.010+0000"}}',
json_options=tz_aware_opts)["dt"])
self.assertEqual(
datetime.datetime(1972, 1, 1, 1, 1, 1, 10000, utc),
json_util.loads(