82 lines
2.4 KiB
Python
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})"
|