From ba02c8ed122410e04e84e848bedd39c468b98dc4 Mon Sep 17 00:00:00 2001 From: Ed_ Date: Tue, 24 Feb 2026 22:04:14 -0500 Subject: [PATCH] feat(project): Segregate discussion history into sibling TOML file --- project_manager.py | 49 +++++++++++++++++++++++++++-- tests/test_history_migration.py | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 tests/test_history_migration.py diff --git a/project_manager.py b/project_manager.py index 5727874..9545b50 100644 --- a/project_manager.py +++ b/project_manager.py @@ -121,14 +121,59 @@ def default_project(name: str = "unnamed") -> dict: # ── load / save ────────────────────────────────────────────────────────────── +def get_history_path(project_path: str | Path) -> Path: + p = Path(project_path) + return p.parent / f"{p.stem}_history.toml" + + def load_project(path) -> dict: with open(path, "rb") as f: - return tomllib.load(f) + proj = tomllib.load(f) + + # Automatic Migration: move legacy 'discussion' to sibling file + hist_path = get_history_path(path) + if "discussion" in proj: + disc = proj.pop("discussion") + # Save to history file if it doesn't exist yet (or overwrite to migrate) + with open(hist_path, "wb") as f: + tomli_w.dump(disc, f) + # Save the stripped project file + save_project(proj, path) + # Restore for the returned dict so GUI works as before + proj["discussion"] = disc + else: + # Load from sibling if it exists + if hist_path.exists(): + proj["discussion"] = load_history(path) + + return proj -def save_project(proj: dict, path): +def load_history(project_path: str | Path) -> dict: + hist_path = get_history_path(project_path) + if hist_path.exists(): + with open(hist_path, "rb") as f: + return tomllib.load(f) + return {} + + +def save_project(proj: dict, path, disc_data: dict | None = None): + # Ensure 'discussion' is NOT in the main project dict + if "discussion" in proj: + # If disc_data wasn't provided, use the one from proj + if disc_data is None: + disc_data = proj["discussion"] + # Remove it so it doesn't get saved to the main file + proj = dict(proj) # shallow copy to avoid mutating caller's dict + del proj["discussion"] + with open(path, "wb") as f: tomli_w.dump(proj, f) + + if disc_data: + hist_path = get_history_path(path) + with open(hist_path, "wb") as f: + tomli_w.dump(disc_data, f) # ── migration helper ───────────────────────────────────────────────────────── diff --git a/tests/test_history_migration.py b/tests/test_history_migration.py new file mode 100644 index 0000000..a7970a0 --- /dev/null +++ b/tests/test_history_migration.py @@ -0,0 +1,56 @@ +import pytest +import tomli_w +import tomllib +from pathlib import Path +from project_manager import load_project, save_project, default_project + +def test_migration_on_load(tmp_path): + # Setup legacy project file with discussion + proj_path = tmp_path / "manual_slop.toml" + hist_path = tmp_path / "manual_slop_history.toml" + + legacy_data = default_project("test-project") + legacy_data["discussion"]["discussions"]["main"]["history"] = ["Hello", "World"] + + with open(proj_path, "wb") as f: + tomli_w.dump(legacy_data, f) + + # Load project - should trigger migration + loaded_data = load_project(proj_path) + + # Assertions + assert "discussion" in loaded_data + assert loaded_data["discussion"]["discussions"]["main"]["history"] == ["Hello", "World"] + + # Check that it's NOT in the main file on disk anymore + with open(proj_path, "rb") as f: + on_disk = tomllib.load(f) + assert "discussion" not in on_disk + + # Check history file + assert hist_path.exists() + with open(hist_path, "rb") as f: + hist_data = tomllib.load(f) + assert hist_data["discussions"]["main"]["history"] == ["Hello", "World"] + +def test_save_separation(tmp_path): + # Setup fresh project data + proj_path = tmp_path / "manual_slop.toml" + hist_path = tmp_path / "manual_slop_history.toml" + + proj_data = default_project("test-project") + proj_data["discussion"]["discussions"]["main"]["history"] = ["Saved", "Separately"] + + # Save project - should save both files + save_project(proj_data, proj_path) + + assert proj_path.exists() + assert hist_path.exists() + + with open(proj_path, "rb") as f: + p = tomllib.load(f) + assert "discussion" not in p + + with open(hist_path, "rb") as f: + h = tomllib.load(f) + assert h["discussions"]["main"]["history"] == ["Saved", "Separately"]