"""Versioned UTF-8 JSON codec used by the serialization API.""" from __future__ import annotations import json from pathlib import Path from typing import Any, Mapping FORMAT_NAME = "json" FILE_FORMAT_VERSION = 1 def load_data(path: Path) -> tuple[int, Mapping[str, Any]]: """Read JSON and return its file-layout version and raw root object. JSON files without ``file_format_version`` are interpreted as version 1. Schema conversion and migrations are intentionally handled by higher layers. """ try: with path.open("r", encoding="utf-8") as stream: data = json.load(stream) except (OSError, UnicodeError, json.JSONDecodeError) as exc: raise ValueError(f"could not read JSON document {path}: {exc}") from exc if not isinstance(data, Mapping): raise ValueError(f"JSON document {path} must contain an object at its root") version = data.get("file_format_version", 1) return version, data def save_data(data: Mapping[str, Any], path: Path) -> None: """Write raw document data as indented UTF-8 JSON at the current version.""" output = {"file_format_version": FILE_FORMAT_VERSION, **data} with path.open("w", encoding="utf-8") as stream: json.dump(output, stream, ensure_ascii=False, indent=2) stream.write("\n")