Source code for app_utils.json

"""JSON related utilities."""

import datetime as dt
import json
from typing import Any

from pytz import timezone


[docs] class JSONDateTimeDecoder(json.JSONDecoder): """Decoder for the standard json library to decode JSON into datetime. To be used together with ``JSONDateTimeEncoder``. Example: .. code-block:: python message = json.loads(message_json, cls=JSONDateTimeDecoder) """
[docs] def __init__(self, *args, **kwargs) -> None: """ :meta private: """ json.JSONDecoder.__init__( self, object_hook=self._dict_to_object, *args, **kwargs )
def _dict_to_object(self, dct: dict) -> object: if "__type__" not in dct: return dct type_str = dct.pop("__type__") zone, _ = dct.pop("tz") if zone: dct["tzinfo"] = timezone(zone) try: date_obj = dt.datetime(**dct) return date_obj except (ValueError, TypeError): dct["__type__"] = type_str return dct
[docs] class JSONDateTimeEncoder(json.JSONEncoder): """Encoder for the standard json library to encode datetime into JSON. To be used together with ``JSONDateTimeDecoder``. Works with naive and aware datetimes, but only with UTC timezone. Example: .. code-block:: python message_json = json.dumps(message, cls=JSONDateTimeEncoder) """ def default(self, o: Any) -> Any: """ :meta private: """ if isinstance(o, dt.datetime): tz_name = o.tzinfo.tzname(o) if o.tzinfo else None if tz_offset := o.utcoffset(): tz_total_seconds = tz_offset.total_seconds() else: tz_total_seconds = None timezone_info = tz_name, tz_total_seconds return { "__type__": "datetime", "year": o.year, "month": o.month, "day": o.day, "hour": o.hour, "minute": o.minute, "second": o.second, "microsecond": o.microsecond, "tz": timezone_info, } return json.JSONEncoder.default(self, o)