from __future__ import annotations import io import json import os import subprocess import sys from deberta_ime.evaluation_cli import run def test_evaluation_cli_import_does_not_require_model_runtime() -> None: script = """ import builtins real_import = builtins.__import__ def guarded_import(name, *args, **kwargs): if name == "torch" or name.startswith("transformers"): raise AssertionError(f"unexpected model runtime import: {name}") return real_import(name, *args, **kwargs) builtins.__import__ = guarded_import from deberta_ime.evaluation_cli import run assert callable(run) """ environment = {**os.environ, "PYTHONPATH": "src"} completed = subprocess.run( [sys.executable, "-c", script], cwd=os.getcwd(), env=environment, capture_output=True, text=True, check=False, ) assert completed.returncode == 0, completed.stderr def test_evaluation_cli_scores_finite_predictions_and_writes_receipts(tmp_path) -> None: items_path = tmp_path / "items.json" predictions_path = tmp_path / "predictions.json" items_path.write_text( json.dumps( [ { "id": "clean", "input": "猫です", "references": ["猫です"], "label": "clean", }, { "id": "typo", "input": "犬でし", "references": ["犬です"], "label": "typo", }, ], ensure_ascii=False, ), encoding="utf-8", ) predictions_path.write_text( json.dumps( [ { "id": "clean", "candidates": [], "provenance": "provider", "reason": "baseline_best", "margin": 0.0, }, { "id": "typo", "candidates": ["犬です"], "provenance": "deberta", "reason": "accepted", "margin": 1.25, }, ], ensure_ascii=False, ), encoding="utf-8", ) stdout = io.StringIO() exit_code = run( [ "--items", str(items_path), "--predictions", str(predictions_path), "--dataset-name", "fixture-clean-typo", "--dataset-revision", "fixture-v1", "--dataset-license", "test-only", "--output-dir", str(tmp_path / "outputs"), "--stem", "fixture", ], stdout=stdout, ) summary = json.loads(stdout.getvalue()) report = json.loads((tmp_path / "outputs" / "fixture.json").read_text("utf-8")) assert exit_code == 0 assert summary["ok"] is True assert report["schema_version"] == 2 assert report["status"] == "LOCAL_FINITE_CANDIDATE_EVALUATION" assert report["evaluation"]["metrics"]["effective_acc_at_1"] == 1.0 assert report["evaluation"]["metrics"]["overcorrection_rate"] == 0.0 assert report["evaluation"]["metrics"]["declared_provenance_counts"] == { "deberta": 1, "provider": 1, } assert report["evaluation"]["metrics"]["mean_reported_margin"] == 0.625 assert report["dataset"] == { "name": "fixture-clean-typo", "revision": "fixture-v1", "license": "test-only", } assert len(report["artifacts"]["items"]["sha256"]) == 64 markdown = (tmp_path / "outputs" / "fixture.md").read_text("utf-8") assert "fixture-clean-typo" in markdown assert "Accepted candidate misses: 0" in markdown assert "Selection errors: 0" in markdown def test_evaluation_cli_adapts_ajimee_without_inventing_clean_labels(tmp_path) -> None: items_path = tmp_path / "ajimee.json" predictions_path = tmp_path / "predictions.json" items_path.write_text( json.dumps( [ { "index": "7", "input": "セイネンシ", "expected_output": ["青年誌"], } ], ensure_ascii=False, ), encoding="utf-8", ) predictions_path.write_text( json.dumps([{"index": "7", "candidates": ["青年誌"]}], ensure_ascii=False), encoding="utf-8", ) run( [ "--items", str(items_path), "--predictions", str(predictions_path), "--format", "ajimee", "--output-dir", str(tmp_path / "outputs"), ], stdout=io.StringIO(), ) report = json.loads( (tmp_path / "outputs" / "finite_candidate_evaluation.json").read_text("utf-8") ) assert report["evaluation"]["metrics"]["effective_acc_at_1"] == 1.0 assert report["evaluation"]["metrics"]["overcorrection_rate"] is None assert report["evaluation"]["metrics"]["clean_rows"] == 0 assert report["dataset"] == { "name": "AJIMEE-compatible input", "revision": "unverified-by-sha256", "license": "unspecified", }