Download source/tests/test_suite.py from gcoderw/DEG-5B-E2B-1019: direct link, hf CLI and curl.
- Browser
- Download file 8.37 kB
-
https://huggingface.co/gcoderw/DEG-5B-E2B-1019/resolve/main/source/tests/test_suite.py
- Command line
-
hf download hf://gcoderw/DEG-5B-E2B-1019/source/tests/test_suite.py
-
curl -L -o test_suite.py https://huggingface.co/gcoderw/DEG-5B-E2B-1019/resolve/main/source/tests/test_suite.py
8.37 kB
| """deg-suite v1 aggregation, validity gate, judge cache and training guard (CPU only).""" | |
| from __future__ import annotations | |
| import json | |
| import pytest | |
| from deg.bench import suite | |
| from deg.bench.score import Prediction | |
| from deg.bench.suite import SOURCES, Source, SuiteGuard, aggregate_suite, score_source | |
| from deg.bench.suite_judge import Item, Judge, grade_score, parse_grade | |
| def test_headline_is_mean_of_capability_means(): | |
| comps = {"decide": {"a": 1.0, "b": 0.0, "c": 0.5, "d": 0.5}, # 4 sources -> 0.5 | |
| "extract": {"a": 0.9}, # 1 source -> 0.9 | |
| "generate": {"a": 0.2, "b": 0.4}} # 2 sources -> 0.3 | |
| out = aggregate_suite(comps) | |
| assert out["capabilities"] == pytest.approx({"decide": 0.5, "extract": 0.9, "generate": 0.3}) | |
| assert out["headline"] == pytest.approx((0.5 + 0.9 + 0.3) / 3) | |
| def test_adding_a_source_cannot_swamp_other_capabilities(): | |
| base = {"decide": {"a": 0.8}, "extract": {"a": 0.6}, "generate": {"a": 0.4}} | |
| more = {**base, "decide": {"a": 0.8, **{f"x{i}": 1.0 for i in range(50)}}} | |
| h0, h1 = aggregate_suite(base)["headline"], aggregate_suite(more)["headline"] | |
| # 50 perfect decide sources move only the DECIDE third of the headline | |
| assert h1 - h0 <= (1.0 - 0.8) / 3 + 1e-9 | |
| assert aggregate_suite(more)["capabilities"]["extract"] == pytest.approx(0.6) | |
| def test_missing_capability_gives_no_headline(): | |
| out = aggregate_suite({"decide": {"a": 0.9, "b": None}, "extract": {}, "generate": {}}) | |
| assert out["headline"] is None | |
| assert out["capabilities"]["decide"] == pytest.approx(0.9) | |
| assert out["missing_capabilities"] == ["extract", "generate"] | |
| def test_component_out_of_range_rejected(): | |
| with pytest.raises(ValueError): | |
| aggregate_suite({"decide": {"a": 1.5}, "extract": {"a": 0}, "generate": {"a": 0}}) | |
| def test_every_capability_has_sources(): | |
| for cap in suite.CAPABILITIES: | |
| assert sum(cap in s.caps for s in SOURCES) >= 2 | |
| def test_jev_intelligence_chance_corrected_and_tier_weighted(): | |
| # easy: 2/2 correct on noul (chance .5) -> 1.0; hard: 1/2 on noul -> 0.0 | |
| rows = [("easy", True, 2), ("easy", True, 2), ("hard", True, 2), ("hard", False, 2)] | |
| w = suite.JEV_TIER_WEIGHTS | |
| assert suite.jev_intelligence(rows) == pytest.approx(w["easy"] / (w["easy"] + w["hard"])) | |
| assert suite.jev_intelligence([("standard", False, 4)]) == 0.0 # clipped at 0 | |
| SCHEMA = {"type": "object", "properties": { | |
| "kind": {"enum": ["a", "b"]}, | |
| "name": {"type": "string"}, | |
| "items": {"type": "array", "items": {"type": "string"}}, | |
| "note": {"type": "string", "x-generate": True, "maxLength": 20}}, | |
| "required": ["kind", "name", "items", "note"], "additionalProperties": False} | |
| REC = {"uid": "r1", "context": "Name: Ada. Items: x, y.", "schema": SCHEMA, | |
| "value": {"kind": "a", "name": "Ada", "items": ["x", "y"], "note": "ok"}} | |
| class FixedJudge: | |
| model = "fixed" | |
| calls = 0 | |
| def score_many(self, items): | |
| return [0.5 for _ in items] | |
| def test_fields_scores_and_validity_gate(): | |
| src = Source("t", "fields", ("decide", "extract", "generate")) | |
| good = Prediction("r1", value={"kind": "a", "name": "Ada", "items": ["x", "y"], | |
| "note": "fine"}) | |
| out = score_source(src, [REC], [good], ("decide", "extract", "generate"), FixedJudge()) | |
| assert out["components"]["decide"] == 1.0 | |
| assert out["components"]["extract"] == 1.0 # mean(norm 1.0, count 1.0) | |
| assert out["components"]["generate"] == 0.5 | |
| # the same correct fields with one schema violation (note over maxLength): all zero | |
| bad = Prediction("r1", value={"kind": "a", "name": "Ada", "items": ["x", "y"], | |
| "note": "x" * 30}) | |
| out = score_source(src, [REC], [bad], ("decide", "extract", "generate"), FixedJudge()) | |
| assert out["valid_rate"] == 0.0 | |
| assert out["components"] == {"decide": 0.0, "extract": 0.0, "generate": 0.0} | |
| err = Prediction("r1", error="OutOfMemoryError: ...") | |
| out = score_source(src, [REC], [err], ("decide", "extract", "generate"), FixedJudge()) | |
| assert out["components"] == {"decide": 0.0, "extract": 0.0, "generate": 0.0} | |
| def test_decide_only_system_is_not_gated_by_validity(): | |
| src = Source("t", "fields", ("decide", "extract", "generate")) | |
| out = score_source(src, [REC], [Prediction("r1", value={"kind": "a"})], ("decide",), None) | |
| assert out["components"] == {"decide": 1.0} | |
| def test_squad_balances_answerable_and_unanswerable(): | |
| rec = {"uid": "s", "context": "Paris is in France.", | |
| "schema": {"type": "object", "properties": { | |
| "q1": {"type": ["string", "null"]}, "q2": {"type": ["string", "null"]}}, | |
| "required": ["q1", "q2"], "additionalProperties": False}, | |
| "value": {"q1": "France", "q2": None}, "alternatives": {"/q1": ["France"], "/q2": []}} | |
| src = Source("squad2", "squad", ("extract",)) | |
| always_null = Prediction("s", value={"q1": None, "q2": None}) | |
| out = score_source(src, [rec], [always_null], ("decide", "extract", "generate"), None) | |
| assert out["components"]["extract"] == pytest.approx(0.5) | |
| right = Prediction("s", value={"q1": "france.", "q2": None}) | |
| out = score_source(src, [rec], [right], ("decide", "extract", "generate"), None) | |
| assert out["components"]["extract"] == pytest.approx(1.0) | |
| def test_judge_cache_is_deterministic(tmp_path): | |
| calls = [] | |
| def call(prompt): | |
| calls.append(prompt) | |
| return '{"faithful": 2, "responsive": 1}' | |
| item = Item("ctx", "note", "a note", 40, "text") | |
| j = Judge(tmp_path / "c.jsonl", call=call, model="m") | |
| assert j.score_many([item, item]) == [0.75, 0.75] | |
| j2 = Judge(tmp_path / "c.jsonl", call=lambda p: pytest.fail("cache miss"), model="m") | |
| assert j2.score_many([item]) == [0.75] | |
| assert len(calls) <= 2 # concurrent duplicates may both call; the cache keeps the result | |
| other = Item("ctx", "note", "a note", 40, "other text") | |
| assert other.key("m") != item.key("m") and item.key("m") != item.key("m2") | |
| def test_parse_grade(): | |
| assert grade_score(parse_grade('ok {"faithful": 1, "responsive": 2}')) == 0.75 | |
| with pytest.raises(ValueError): | |
| parse_grade('{"faithful": 3, "responsive": 2}') | |
| def test_suite_guard_and_path_guard(): | |
| long_ctx = ("The quarterly report says revenue grew eleven percent while operating " | |
| "margins narrowed because of freight costs and a weaker euro this year") | |
| g = SuiteGuard(texts=[long_ctx, "How do I locate my card?"]) | |
| assert g.match("prefix text. " + long_ctx + " suffix") is not None | |
| assert g.match("how do I locate my card") is not None | |
| assert g.match("Where can I locate my new card after moving house last week?") is None | |
| assert g.match("A completely unrelated document about gardening tools.") is None | |
| with pytest.raises(ValueError): | |
| suite.guard_path("/data/deg/suite-v1/mixed.jsonl") | |
| suite.guard_path("/data/deg/datagen/full-off/records.jsonl") | |
| def test_frozen_files_match_manifest_when_present(): | |
| if not (suite.RESULTS / "MANIFEST.json").exists(): | |
| pytest.skip("suite not built on this host") | |
| for name in json.loads((suite.RESULTS / "MANIFEST.json").read_text())["sources"]: | |
| if (suite.SUITE_DIR / f"{name}.jsonl").exists(): | |
| assert suite.load_source(name) | |
| def test_missing_source_withholds_headline(tmp_path, monkeypatch): | |
| """A built source without predictions must not silently reweight its capability.""" | |
| recs = {"datagen-test": [REC]} | |
| monkeypatch.setattr(suite, "manifest", lambda: {"sources": { | |
| "datagen-test": {"sha256": "x"}, "extractbench": {"sha256": "y"}}}) | |
| monkeypatch.setattr(suite, "load_source", lambda name, verify=True: recs[name]) | |
| sdir = tmp_path / "sys" | |
| sdir.mkdir() | |
| good = Prediction("r1", value={"kind": "a", "name": "Ada", "items": ["x", "y"], | |
| "note": "fine"}) | |
| (sdir / "datagen-test.preds.jsonl").write_text(json.dumps(good.to_json()) + "\n") | |
| card = suite.score_system(tmp_path, "sys", ("decide", "extract", "generate"), FixedJudge()) | |
| assert card["incomplete_sources"] == ["extractbench"] | |
| assert card["headline"] is None and card["capabilities"]["extract"] is None | |
| assert card["capabilities"]["decide"] == 1.0 | |