Ferramentas/RCVinculaPartesLivroAntigo/actions/file/json_file_loader.py
2025-12-02 10:37:13 -03:00

69 lines
2.1 KiB
Python

import json
from json import JSONDecodeError
from types import SimpleNamespace
from pathlib import Path
from typing import Any, Optional, Union
class JsonFileLoader:
"""
Carrega arquivos JSON e retorna como objeto (SimpleNamespace) ou dict.
Retorna None quando não houver arquivo ou dados.
"""
def __init__(self, file_path: Union[str, Path], encoding: str = "utf-8"):
self.path = Path(file_path)
self.encoding = encoding
def load(
self, as_namespace: bool = True, empty_as_none: bool = True
) -> Optional[Any]:
"""
Lê o JSON do disco.
- as_namespace=True: retorna SimpleNamespace (com conversão recursiva).
- as_namespace=False: retorna dict/list nativos.
- empty_as_none=True: {}, [] ou None são tratados como "sem dados" e retornam None.
"""
# 1) Arquivo inexistente ou não regular
if not self.path.exists() or not self.path.is_file():
return None
# 2) Arquivo vazio
if self.path.stat().st_size == 0:
return None
# 3) Leitura + limpeza
try:
with self.path.open("r", encoding=self.encoding) as f:
raw = f.read()
except OSError:
return None
raw = (raw or "").strip()
if not raw:
return None
# 4) Parse do JSON
try:
data = json.loads(raw)
except JSONDecodeError:
return None
# 5) Tratar dados vazios
if empty_as_none and (data is None or data == {} or data == []):
return None
# 6) Converter (opcional) para SimpleNamespace
return self._to_namespace(data) if as_namespace else data
# ---------- helpers ----------
@classmethod
def _to_namespace(cls, value: Any) -> Any:
"""Converte recursivamente dict/list em SimpleNamespace/list."""
if isinstance(value, dict):
return SimpleNamespace(
**{k: cls._to_namespace(v) for k, v in value.items()}
)
if isinstance(value, list):
return [cls._to_namespace(v) for v in value]
return value