From abb84d9756c4ca5c6dcdcb857c19b33ebd90f8b3 Mon Sep 17 00:00:00 2001 From: Erik Montnemery <erik@montnemery.com> Date: Wed, 27 Oct 2021 19:51:38 +0200 Subject: [PATCH] Serialize dates and times to isoformat (#58157) --- homeassistant/helpers/json.py | 10 +++++++--- tests/helpers/test_json.py | 37 ++++++++++++++++++----------------- 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/homeassistant/helpers/json.py b/homeassistant/helpers/json.py index 738f744194f..c581e5a9361 100644 --- a/homeassistant/helpers/json.py +++ b/homeassistant/helpers/json.py @@ -1,5 +1,5 @@ """Helpers to help with encoding Home Assistant objects in JSON.""" -from datetime import datetime, timedelta +import datetime import json from typing import Any @@ -12,7 +12,7 @@ class JSONEncoder(json.JSONEncoder): Hand other objects to the original method. """ - if isinstance(o, datetime): + if isinstance(o, datetime.datetime): return o.isoformat() if isinstance(o, set): return list(o) @@ -30,8 +30,12 @@ class ExtendedJSONEncoder(JSONEncoder): Fall back to repr(o). """ - if isinstance(o, timedelta): + if isinstance(o, datetime.timedelta): return {"__type": str(type(o)), "total_seconds": o.total_seconds()} + if isinstance(o, datetime.datetime): + return o.isoformat() + if isinstance(o, (datetime.date, datetime.time)): + return {"__type": str(type(o)), "isoformat": o.isoformat()} try: return super().default(o) except TypeError: diff --git a/tests/helpers/test_json.py b/tests/helpers/test_json.py index 076af218676..4968c872946 100644 --- a/tests/helpers/test_json.py +++ b/tests/helpers/test_json.py @@ -1,5 +1,5 @@ """Test Home Assistant remote methods and classes.""" -from datetime import timedelta +import datetime import pytest @@ -8,9 +8,10 @@ from homeassistant.helpers.json import ExtendedJSONEncoder, JSONEncoder from homeassistant.util import dt as dt_util -def test_json_encoder(hass): - """Test the JSON Encoder.""" - ha_json_enc = JSONEncoder() +@pytest.mark.parametrize("encoder", (JSONEncoder, ExtendedJSONEncoder)) +def test_json_encoder(hass, encoder): + """Test the JSON encoders.""" + ha_json_enc = encoder() state = core.State("test.test", "hello") # Test serializing a datetime @@ -24,22 +25,21 @@ def test_json_encoder(hass): # Test serializing an object which implements as_dict assert ha_json_enc.default(state) == state.as_dict() + +def test_json_encoder_raises(hass): + """Test the JSON encoder raises on unsupported types.""" + ha_json_enc = JSONEncoder() + # Default method raises TypeError if non HA object with pytest.raises(TypeError): ha_json_enc.default(1) -def test_trace_json_encoder(hass): - """Test the Trace JSON Encoder.""" +def test_extended_json_encoder(hass): + """Test the extended JSON encoder.""" ha_json_enc = ExtendedJSONEncoder() - state = core.State("test.test", "hello") - - # Test serializing a datetime - now = dt_util.utcnow() - assert ha_json_enc.default(now) == now.isoformat() - # Test serializing a timedelta - data = timedelta( + data = datetime.timedelta( days=50, seconds=27, microseconds=10, @@ -53,12 +53,13 @@ def test_trace_json_encoder(hass): "total_seconds": data.total_seconds(), } - # Test serializing a set() - data = {"milk", "beer"} - assert sorted(ha_json_enc.default(data)) == sorted(data) + # Test serializing a time + o = datetime.time(7, 20) + assert ha_json_enc.default(o) == {"__type": str(type(o)), "isoformat": "07:20:00"} - # Test serializong object which implements as_dict - assert ha_json_enc.default(state) == state.as_dict() + # Test serializing a date + o = datetime.date(2021, 12, 24) + assert ha_json_enc.default(o) == {"__type": str(type(o)), "isoformat": "2021-12-24"} # Default method falls back to repr(o) o = object() -- GitLab