feat(harness): tht session documents --json read command
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
"""Tests for `tht session documents --json` and build_documents."""
|
||||
import json
|
||||
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from tht.config import DatabaseConfig
|
||||
from tht.session.store import build_documents, create_session
|
||||
from tht.cli.session_cmd import session_app
|
||||
|
||||
|
||||
def _db():
|
||||
return DatabaseConfig(
|
||||
database="testdb", user="u", password="p", # noqa: S106
|
||||
**{"schema": "public"},
|
||||
)
|
||||
|
||||
|
||||
def test_build_documents_always_has_original_question(tmp_path):
|
||||
m = create_session("quante ablazioni nel 2024", _db(), tmp_path)
|
||||
docs = build_documents(m, tmp_path / m.id)
|
||||
keys = [d["key"] for d in docs]
|
||||
assert keys[0] == "question"
|
||||
assert docs[0]["format"] == "text"
|
||||
assert docs[0]["content"] == "quante ablazioni nel 2024"
|
||||
# question.md is written by create_session -> revised_question present
|
||||
assert "revised_question" in keys
|
||||
|
||||
|
||||
def test_build_documents_includes_existing_artifacts_only(tmp_path):
|
||||
m = create_session("q", _db(), tmp_path)
|
||||
sdir = tmp_path / m.id
|
||||
(sdir / "sql_final.sql").write_text("SELECT 1")
|
||||
(sdir / "schema_linking.json").write_text('{"question":"q","candidates":[]}')
|
||||
docs = {d["key"]: d for d in build_documents(m, sdir)}
|
||||
assert docs["sql"]["format"] == "sql"
|
||||
assert docs["sql"]["content"] == "SELECT 1"
|
||||
assert docs["schema_linking"]["format"] == "schema-linking"
|
||||
assert "validation_report" not in docs # not written
|
||||
|
||||
|
||||
def test_cli_documents_json(tmp_path, monkeypatch):
|
||||
m = create_session("q", _db(), tmp_path)
|
||||
from tht.cli import session_cmd
|
||||
|
||||
class FakePaths:
|
||||
sessions = tmp_path
|
||||
|
||||
class FakeCfg:
|
||||
paths = FakePaths()
|
||||
database = _db()
|
||||
|
||||
monkeypatch.setattr(session_cmd, "_load_config_or_exit", lambda _: FakeCfg())
|
||||
res = CliRunner().invoke(session_app, ["documents", m.id, "--json"])
|
||||
assert res.exit_code == 0, res.output
|
||||
docs = json.loads(res.output)
|
||||
assert isinstance(docs, list)
|
||||
assert docs[0]["key"] == "question"
|
||||
@@ -218,6 +218,25 @@ def delete_cmd(session_id: str = typer.Argument(...), config: Path = CONFIG_OPT)
|
||||
typer.secho(f"OK: sessione {session_id} eliminata.", fg=typer.colors.GREEN)
|
||||
|
||||
|
||||
@session_app.command("documents")
|
||||
def documents_cmd(
|
||||
session_id: str = typer.Argument(...),
|
||||
json_out: bool = typer.Option(False, "--json", help="Emetti JSON su stdout (pristine)."),
|
||||
config: Path = CONFIG_OPT,
|
||||
) -> None:
|
||||
"""Documenti di sola lettura della sessione (domanda, rivista, schema, SQL, report, decisioni)."""
|
||||
from tht.session.store import build_documents
|
||||
|
||||
cfg = _load_config_or_exit(config)
|
||||
manifest = load_session_or_exit(cfg, session_id)
|
||||
docs = build_documents(manifest, session_dir(cfg, session_id))
|
||||
if json_out:
|
||||
typer.echo(json.dumps(docs, ensure_ascii=False, indent=2))
|
||||
return
|
||||
for d in docs:
|
||||
typer.echo(f"[{d['phase']}] {d['title']} ({d['format']})")
|
||||
|
||||
|
||||
def session_problems(cfg, session_id: str) -> list[str]:
|
||||
"""Problemi del Blocco 3 (decisioni + schema_linking). Riusato da check e finalize."""
|
||||
import json
|
||||
|
||||
@@ -164,3 +164,27 @@ def delete_session(session_id: str, sessions_root: Path) -> None:
|
||||
"""Hard-delete the session directory. SessionError if it does not exist."""
|
||||
load_session(session_id, sessions_root) # raises SessionError if absent
|
||||
shutil.rmtree(sessions_root / session_id)
|
||||
|
||||
|
||||
def build_documents(manifest: SessionManifest, session_dir: Path) -> list[dict]:
|
||||
"""Ordered, read-only document bundle for the UI panel. Only documents that exist
|
||||
on disk are returned. CTE artifacts (F6) are intentionally excluded (intermediate)."""
|
||||
docs: list[dict] = [{
|
||||
"phase": "—", "key": "question", "title": "Domanda originale",
|
||||
"format": "text", "content": manifest.question,
|
||||
}]
|
||||
spec = [
|
||||
("question.md", "F3", "revised_question", "Domanda rivista", "markdown"),
|
||||
("schema_linking.json", "F4", "schema_linking", "Schema linking", "schema-linking"),
|
||||
("sql_final.sql", "F7", "sql", "SQL finale", "sql"),
|
||||
("validation_report.md", "finalize", "validation_report", "Report di validazione", "markdown"),
|
||||
("review_decisions.jsonl", "—", "decisions", "Decisioni", "decisions"),
|
||||
]
|
||||
for filename, phase, key, title, fmt in spec:
|
||||
path = session_dir / filename
|
||||
if path.exists():
|
||||
docs.append({
|
||||
"phase": phase, "key": key, "title": title,
|
||||
"format": fmt, "content": path.read_text(),
|
||||
})
|
||||
return docs
|
||||
|
||||
Reference in New Issue
Block a user