Ferramentas/AjustaFundos/actions/file/save_to_disk.py

101 lines
3.3 KiB
Python

import json
import traceback
from datetime import datetime, date
from decimal import Decimal
from types import SimpleNamespace
from pathlib import Path
from typing import Any, Optional, Literal, Union
from pydantic import BaseModel
def save_to_disk(
data: Union[str, bytes, dict, list, Any],
file_path: str,
as_json: Optional[bool] = None,
encoding: str = "utf-8",
indent: int = 4,
add_timestamp: bool = False,
mode: Literal["overwrite", "append"] = "overwrite",
) -> dict:
"""
Salva dados em disco local de forma segura, com tratamento automático
para objetos não serializáveis (ex.: SimpleNamespace, Decimal, datetime, BaseModel).
"""
def convert(obj: Any):
"""Converte qualquer objeto para formato serializável em JSON."""
if obj is None:
return None
if isinstance(obj, (str, int, float, bool)):
return obj
if isinstance(obj, bytes):
return obj.decode("utf-8", errors="ignore")
if isinstance(obj, Decimal):
return float(obj)
if isinstance(obj, (datetime, date)):
return obj.isoformat()
if isinstance(obj, SimpleNamespace):
return {k: convert(v) for k, v in vars(obj).items()}
if isinstance(obj, BaseModel):
return obj.model_dump()
if isinstance(obj, list):
return [convert(i) for i in obj]
if isinstance(obj, dict):
return {k: convert(v) for k, v in obj.items()}
# fallback final — stringifica o objeto
return str(obj)
try:
path = Path(file_path)
# Garante que o diretório existe
path.parent.mkdir(parents=True, exist_ok=True)
# Adiciona timestamp ao nome se necessário
if add_timestamp:
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
stem = path.stem
suffix = path.suffix or ".json"
path = path.with_name(f"{stem}_{timestamp}{suffix}")
# Detecta automaticamente se deve salvar como JSON
if as_json is None:
as_json = isinstance(data, (dict, list, SimpleNamespace, BaseModel))
write_mode = (
"wb" if isinstance(data, bytes) else "a" if mode == "append" else "w"
)
if isinstance(data, bytes):
with open(path, write_mode) as f:
f.write(data)
elif as_json:
# Converte antes de salvar
safe_data = convert(data)
with open(path, write_mode, encoding=encoding) as f:
json.dump(safe_data, f, ensure_ascii=False, indent=indent)
else:
if not isinstance(data, str):
data = str(data)
with open(path, write_mode, encoding=encoding) as f:
f.write(data)
file_size = path.stat().st_size if path.exists() else 0
print(f"[OK] Arquivo salvo: {path} ({file_size} bytes)")
return {
"success": True,
"path": str(path.resolve()),
"size": file_size,
"error": None,
}
except Exception as e:
error_message = f"[ERRO] Falha ao salvar arquivo '{file_path}': {e}\n{traceback.format_exc()}"
print(error_message)
return {
"success": False,
"path": str(file_path),
"size": 0,
"error": str(e),
}