Source code for mt940.json

"""JSON serialization for MT940 models.

This module exposes :class:`JSONEncoder`, a :class:`json.JSONEncoder` subclass
that knows how to serialize the model types returned by the parser (balances,
amounts, dates and the transaction collections).

Example:
    >>> import json
    >>> import mt940
    >>> transactions = mt940.models.Transactions()
    >>> json.dumps(transactions, cls=mt940.JSONEncoder)
    '{"transactions": []}'
"""

from __future__ import annotations

import datetime
import decimal
import json
from typing import Any

from . import models


[docs] class JSONEncoder(json.JSONEncoder): """Serialize MT940 model objects to JSON-compatible primitives. Dates, datetimes, timedeltas, timezones and decimals are rendered as strings; :class:`~mt940.models.Transactions`, :class:`~mt940.models.Transaction`, :class:`~mt940.models.Balance` and :class:`~mt940.models.Amount` are rendered as their ``data``/``__dict__`` mappings. Pass it as the ``cls`` argument to :func:`json.dumps`. """
[docs] def default(self, o: Any) -> Any: """Return a JSON-serializable representation of ``o``. Args: o: The object to serialize. ``o`` keeps the permissive ``Any`` type of the overridden :meth:`json.JSONEncoder.default`. Returns: The serialized form of the object. """ # The following types should simply be cast to strings str_types = ( datetime.date, datetime.datetime, datetime.timedelta, datetime.tzinfo, decimal.Decimal, ) dict_types = (models.Balance, models.Amount) # Handle native types that should be converted to strings if isinstance(o, str_types): return str(o) # Handling of the Transaction objects to include the # actual transactions elif isinstance(o, models.Transactions): data: dict[str, Any] = o.data.copy() data['transactions'] = o.transactions return data # If an object has a `data` attribute, return that instead of the # `__dict__` to prevent loops elif hasattr(o, 'data'): return o.data # Handle types that have a `__dict__` containing the data (doesn't work # for classes using `__slots__` such as `datetime`) elif isinstance(o, dict_types): return o.__dict__ else: # pragma: no cover return super().default(o)