From c1081633aa8ac03d05136b931bad3bbdd40bd7f0 Mon Sep 17 00:00:00 2001 From: Anionix Date: Fri, 24 Jul 2026 15:08:15 +0900 Subject: [PATCH] fix: accept normalized adapter columns (#495) --- pyproject.toml | 1 + src/format_bench/adapter_contract.py | 9 +++++++-- src/format_bench/formats/__init__.py | 2 ++ tests/test_adapter_contract.py | 7 ++++++- tests/typecheck/adapter_manifest_normalized.py | 14 ++++++++++++++ 5 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 tests/typecheck/adapter_manifest_normalized.py diff --git a/pyproject.toml b/pyproject.toml index a8c41ac..f07f36a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,6 +63,7 @@ include = [ "src/format_bench/adapter_contract.py", "src/format_bench/artifact_digest.py", "src/format_bench/registry.py", + "tests/typecheck/adapter_manifest_normalized.py", "src/format_bench/contracts.py", "src/format_bench/equivalence.py", "src/format_bench/json_contract.py", diff --git a/src/format_bench/adapter_contract.py b/src/format_bench/adapter_contract.py index 8e93fd3..6dc9e78 100644 --- a/src/format_bench/adapter_contract.py +++ b/src/format_bench/adapter_contract.py @@ -1,4 +1,6 @@ -from typing import Literal, NotRequired, TypedDict +from typing import Literal, NotRequired, TypeAlias, TypedDict + +from .contracts import NormalizedColumn class AdapterColumn(TypedDict): @@ -7,9 +9,12 @@ class AdapterColumn(TypedDict): nullable: NotRequired[bool] +AdapterColumns: TypeAlias = list[AdapterColumn] | list[NormalizedColumn] + + class AdapterManifest(TypedDict): rows: int - columns: list[AdapterColumn] + columns: AdapterColumns canonical_hash: str expected_counts: dict[str, int] workloads: NotRequired[dict[str, object]] diff --git a/src/format_bench/formats/__init__.py b/src/format_bench/formats/__init__.py index 8a77d0a..388b7b2 100644 --- a/src/format_bench/formats/__init__.py +++ b/src/format_bench/formats/__init__.py @@ -1,5 +1,6 @@ from format_bench.adapter_contract import ( AdapterColumn, + AdapterColumns, AdapterManifest, VerificationResult, ) @@ -22,6 +23,7 @@ __all__ = [ "Artifact", "AdapterColumn", + "AdapterColumns", "AdapterManifest", "ArrowIpcAdapter", "AvroAdapter", diff --git a/tests/test_adapter_contract.py b/tests/test_adapter_contract.py index 6910f23..ead299d 100644 --- a/tests/test_adapter_contract.py +++ b/tests/test_adapter_contract.py @@ -2,6 +2,7 @@ from pathlib import Path from typing import NotRequired, get_args, get_origin, get_type_hints +from format_bench.contracts import NormalizedColumn from format_bench.formats import ( AdapterColumn, AdapterManifest, @@ -29,7 +30,10 @@ def test_adapter_contract_keys_are_explicit() -> None: assert get_origin(column_hints["nullable"]) is NotRequired assert AdapterColumn.__required_keys__ == {"arrow_type", "name"} assert AdapterColumn.__optional_keys__ == {"nullable"} - assert get_args(manifest_hints["columns"]) == (AdapterColumn,) + assert set(get_args(manifest_hints["columns"])) == { + list[AdapterColumn], + list[NormalizedColumn], + } assert set(manifest_hints) == { "canonical_hash", "columns", @@ -71,3 +75,4 @@ def test_adapter_contract_is_in_the_blocking_strict_frontier() -> None: assert pyright["typeCheckingMode"] == "strict" assert "src/format_bench/adapter_contract.py" in pyright["include"] assert "src/format_bench/registry.py" in pyright["include"] + assert "tests/typecheck/adapter_manifest_normalized.py" in pyright["include"] diff --git a/tests/typecheck/adapter_manifest_normalized.py b/tests/typecheck/adapter_manifest_normalized.py new file mode 100644 index 0000000..64a5416 --- /dev/null +++ b/tests/typecheck/adapter_manifest_normalized.py @@ -0,0 +1,14 @@ +from format_bench.adapter_contract import AdapterManifest +from format_bench.contracts import NormalizedColumn + + +def manifest_with_normalized_columns( + columns: list[NormalizedColumn], +) -> AdapterManifest: + # LLM contract: RAW_COLUMNS -> NORMALIZED_COLUMNS -> ADAPTER_ACCEPTED. + return { + "rows": 0, + "columns": columns, + "canonical_hash": "", + "expected_counts": {}, + }