lllin000_PaperForge/paperforge/core/io.py
LLLin000 288829bb5b feat: PR 1 — nested structure tree + body_units correctness
- RenderOutput dataclass with heading_events/emitted_block_events tracking
- Stack-algorithm structure tree with own/subtree block IDs
- Recursive body_units builder with role helper + token cap splitting
- Schema v4: section_path_json, section_level, section_title, part_ordinal
- Phase 4/5 reorder in ocr_rebuild.py and ocr.py
- 12 new test cases for tree nesting, own_block_ids, rendered-order intervals
2026-07-06 16:42:08 +08:00

35 lines
1 KiB
Python

from __future__ import annotations
import json
from pathlib import Path
def read_json(path: Path):
"""Read and parse a JSON file."""
return json.loads(path.read_text(encoding="utf-8"))
def write_json_atomic(path: Path, data) -> None:
"""Write JSON atomically using a temp file and replace."""
path.parent.mkdir(parents=True, exist_ok=True)
tmp = path.with_suffix(f"{path.suffix}.tmp")
tmp.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
tmp.replace(path)
def write_json(path: Path, data) -> None:
"""Write data as JSON, creating parent directories as needed."""
write_json_atomic(path, data)
def read_jsonl(path: Path) -> list[dict]:
"""Read a newline-delimited JSON file (one JSON object per line)."""
if not path.exists():
return []
rows: list[dict] = []
with open(path, encoding="utf-8") as f:
for line in f:
line = line.strip()
if line:
rows.append(json.loads(line))
return rows