saas_api/actions/data/dict_to_obj.py

82 lines
2.4 KiB
Python

from typing import Any, Mapping, Iterable
class DictToObj:
"""
Converte dicts (aninhados) em objetos com acesso por ponto.
- d["x"] -> o.x
- Listas/tuplas são convertidas recursivamente.
- Mantém método parse() para voltar ao dict original.
"""
__slots__ = ("__data__",)
def __init__(self, data: Mapping[str, Any] | None = None):
object.__setattr__(self, "__data__", {})
if data:
for k, v in data.items():
self.__data__[k] = self._convert(v)
# ===== Conversões =====
@classmethod
def _convert(cls, value: Any) -> Any:
if isinstance(value, Mapping):
return cls(value)
if isinstance(value, list):
return [cls._convert(v) for v in value]
if isinstance(value, tuple):
return tuple(cls._convert(v) for v in value)
return value
def parse(self) -> dict[str, Any]:
def back(v: Any) -> Any:
if isinstance(v, DictToObj):
return v.parse()
if isinstance(v, list):
return [back(i) for i in v]
if isinstance(v, tuple):
return tuple(back(i) for i in v)
return v
return {k: back(v) for k, v in self.__data__.items()}
# ===== Acesso por ponto / item =====
def __getattr__(self, name: str) -> Any:
try:
return self.__data__[name]
except KeyError as e:
raise AttributeError(name) from e
def __setattr__(self, name: str, value: Any) -> None:
# protege o atributo interno
if name == "__data__":
object.__setattr__(self, name, value)
else:
self.__data__[name] = self._convert(value)
def __getitem__(self, key: str) -> Any:
return self.__data__[key]
def __setitem__(self, key: str, value: Any) -> None:
self.__data__[key] = self._convert(value)
def __contains__(self, key: str) -> bool:
return key in self.__data__
def keys(self) -> Iterable[str]:
return self.__data__.keys()
def items(self) -> Iterable[tuple[str, Any]]:
return self.__data__.items()
def values(self) -> Iterable[Any]:
return self.__data__.values()
def __iter__(self):
return iter(self.__data__)
def __len__(self) -> int:
return len(self.__data__)
def __repr__(self) -> str:
return f"DictToObj({self.__data__!r})"