from __future__ import annotations import hashlib import json from pathlib import Path from typing import Any ROOT = Path(__file__).resolve().parents[2] TEMP = ROOT / "Temp" def rp(path_str: str | Path) -> Path: path = Path(path_str) return path if path.is_absolute() else ROOT / path def load_json(path: str | Path) -> dict[str, Any]: p = rp(path) if not p.exists(): return {} try: payload = json.loads(p.read_text(encoding="utf-8")) except Exception: return {} return payload if isinstance(payload, dict) else {} def save_json(path: str | Path, payload: dict[str, Any]) -> Path: p = rp(path) p.parent.mkdir(parents=True, exist_ok=True) p.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8") return p def sha256_hex(path: str | Path) -> str: p = rp(path) return hashlib.sha256(p.read_bytes()).hexdigest() def first_non_null(*values: Any) -> Any: for value in values: if value is not None: return value return None def extract_hctx(payload: dict[str, Any]) -> dict[str, Any]: h_apex = payload.get("hApex") data_apex = ((payload.get("data") or {}).get("_harness_context")) if isinstance(payload.get("data"), dict) else None if isinstance(h_apex, dict) and isinstance(data_apex, dict): merged = dict(data_apex) merged.update(h_apex) return merged if isinstance(h_apex, dict): return h_apex if isinstance(data_apex, dict): return data_apex return payload if isinstance(payload, dict) else {} def rows(v: Any) -> list[dict[str, Any]]: if isinstance(v, list): return [x for x in v if isinstance(x, dict)] if isinstance(v, str) and v.strip(): try: parsed = json.loads(v) return rows(parsed) except Exception: return [] if isinstance(v, dict): for key in ("rows", "data", "tickers", "items"): candidate = v.get(key) if isinstance(candidate, list): return [x for x in candidate if isinstance(x, dict)] return [] def temp_json(name: str) -> dict[str, Any]: return load_json(TEMP / name)