From 3e58d583760ec32eec408345bfaf232c39124f6c Mon Sep 17 00:00:00 2001 From: chris-colinsky Date: Mon, 4 May 2026 23:24:05 -0700 Subject: [PATCH] test: handle model instances in discriminators MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pydantic invokes the Discriminator callable on both validate and serialize paths. The two harness discriminators only inspected dicts, so on dump they fell through to the first variant and emitted PydanticSerializationUnexpectedValue warnings — ~25 per round-trip pass. Adding isinstance arms before the dict check routes serialization to the correct variant and silences the warnings, with the validate path unchanged. --- tests/conformance/harness/expectations.py | 14 ++++++++++++++ tests/conformance/harness/fixtures.py | 10 ++++++++++ 2 files changed, 24 insertions(+) diff --git a/tests/conformance/harness/expectations.py b/tests/conformance/harness/expectations.py index dddfbbc..6f03853 100644 --- a/tests/conformance/harness/expectations.py +++ b/tests/conformance/harness/expectations.py @@ -224,7 +224,21 @@ def _discriminate_expected( blocks themselves don't know that, so we discriminate on the keys that ARE distinctive and fall back to graph-engine for plain ``final_state``-only fixtures. + + Pydantic invokes this callable on both the validation and + serialization paths. On serialization the value is already one of the + concrete variants, so route by ``isinstance`` first; otherwise the + dump path falls through to ``graph_engine`` and warns that the + serialized variant doesn't match the union's first arm. """ + if isinstance(value, GraphEngineExpected): + return "graph_engine" + if isinstance(value, LlmProviderExpected): + return "llm_provider" + if isinstance(value, PipelineUtilitiesExpected): + return "pipeline_utilities" + if isinstance(value, ObservabilityExpected): + return "observability" if not isinstance(value, dict): return "graph_engine" keys: set[str] = {str(k) for k in cast("dict[str, Any]", value)} diff --git a/tests/conformance/harness/fixtures.py b/tests/conformance/harness/fixtures.py index d53212f..e14da05 100644 --- a/tests/conformance/harness/fixtures.py +++ b/tests/conformance/harness/fixtures.py @@ -241,7 +241,17 @@ def _discriminate_fixture(value: Any) -> Literal["llm_provider", "cases", "graph llm-provider fixtures (e.g. 003-message-validation) have BOTH — ``mock_provider`` is the load-bearing discriminator, ``cases`` is just the table style for sub-cases. + + Also handle the serialization path (where the value is a concrete + variant) so a future ``model_dump`` through the top-level union + doesn't fall through to ``graph`` and warn. """ + if isinstance(value, LlmProviderFixture): + return "llm_provider" + if isinstance(value, CasesFixture): + return "cases" + if isinstance(value, GraphFixture): + return "graph" if isinstance(value, dict): if "mock_provider" in value: return "llm_provider"