Files
skill-template/tools/ui_inspector/models/serialize.py
chendelian 633ecff4e2 chore: archive tools/ui_inspector snapshot before migration removal.
Keep the last in-template copy on main so history can restore it; product continues in jiangchang-ui-recorder.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-07 11:19:14 +08:00

65 lines
1.9 KiB
Python

"""Stable JSON serialization helpers for v2 models."""
from __future__ import annotations
import json
from dataclasses import asdict, is_dataclass
from datetime import datetime
from pathlib import Path
from typing import Any, TypeVar
T = TypeVar("T")
def _normalize(obj: Any) -> Any:
if obj is None or isinstance(obj, (str, int, float, bool)):
return obj
if isinstance(obj, datetime):
return obj.isoformat()
if isinstance(obj, Path):
return str(obj).replace("\\", "/")
if is_dataclass(obj) and not isinstance(obj, type):
return {k: _normalize(v) for k, v in asdict(obj).items()}
if isinstance(obj, dict):
return {str(k): _normalize(v) for k, v in obj.items()}
if isinstance(obj, (list, tuple)):
return [_normalize(x) for x in obj]
return str(obj)
def to_dict(obj: Any) -> dict[str, Any]:
data = _normalize(obj)
if not isinstance(data, dict):
raise TypeError(f"expected dataclass/dict, got {type(obj)!r}")
return data
def from_dict(cls: type[T], data: dict[str, Any]) -> T:
"""Best-effort dataclass reconstruction (ignores unknown keys)."""
if not is_dataclass(cls):
raise TypeError(f"{cls!r} is not a dataclass")
import dataclasses
fields = {f.name for f in dataclasses.fields(cls)}
kwargs = {k: v for k, v in (data or {}).items() if k in fields}
return cls(**kwargs) # type: ignore[call-arg]
def dumps_json(obj: Any, *, indent: int = 2) -> str:
return json.dumps(
to_dict(obj) if is_dataclass(obj) and not isinstance(obj, type) else _normalize(obj),
ensure_ascii=False,
indent=indent,
sort_keys=False,
) + "\n"
def write_model_json(path: Path, obj: Any) -> None:
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(dumps_json(obj), encoding="utf-8")
def read_json(path: Path) -> Any:
return json.loads(Path(path).read_text(encoding="utf-8"))