Source code for ds_common_serde_py_lib._serializable_serialize
"""
**File:** ``_serializable_serialize.py``
**Region:** ``ds_common_serde_py_lib``
Description
-----------
Defines internal serialization helpers for ``Serializable.serialize()``,
including recursive conversion of dataclasses and common JSON-compatible types.
Example
-------
.. code-block:: python
from dataclasses import dataclass
from ds_common_serde_py_lib import Serializable
@dataclass
class Child(Serializable):
count: int
assert Child(count=3).serialize() == {"count": 3}
"""
from __future__ import annotations
from collections.abc import Mapping
from dataclasses import fields as dc_fields
from dataclasses import is_dataclass
from datetime import datetime
from enum import Enum
from typing import Any
from uuid import UUID
from ds_common_logger_py_lib import Logger
logger = Logger.get_logger(__name__, package=True)
[docs]
def _serialize_dataclass(value: Any) -> dict[str, Any]:
"""Serialize a dataclass instance to a dict, respecting serialize/mask metadata.
Args:
value: The dataclass instance to serialize.
Returns:
The serialized dataclass.
"""
result: dict[str, Any] = {}
for f in dc_fields(value):
if f.metadata.get("serialize") is False:
continue
mask = f.metadata.get("mask")
if mask is True:
result[f.name] = "********"
continue
if isinstance(mask, str):
result[f.name] = mask
continue
result[f.name] = _serialize_value(getattr(value, f.name))
return result
[docs]
def _serialize_value(value: Any) -> Any:
"""Recursively serialize common Python types and dataclasses.
Returns a structure comprised of dicts, lists, and primitives that can be
JSON-encoded without custom hooks.
Args:
value: The value to serialize.
Returns:
The serialized value.
"""
if value is None:
return None
if isinstance(value, Enum):
return value.value
if isinstance(value, UUID):
return str(value)
if isinstance(value, datetime):
return value.isoformat()
if is_dataclass(value):
return _serialize_dataclass(value)
if hasattr(value, "serialize") and callable(value.serialize):
try:
return value.serialize()
except Exception as exc:
logger.debug("Failed to serialize object %s: %s", type(value).__name__, exc)
if isinstance(value, Mapping):
return {k: _serialize_value(v) for k, v in value.items()}
if isinstance(value, (list, tuple, set)):
return [_serialize_value(v) for v in value]
return value