Skip to content

Commit 2a5d819

Browse files
DouweMclaude
andcommitted
fix: add error path coverage and pragma for base class default
- Add tests for process() ValidationError wrapping through no-capability fast path (ObjectOutputProcessor and UnionOutputProcessor) - Mark BaseOutputProcessor.get_output_context() with pragma: no cover (overridden by all subclasses) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 1ec73f9 commit 2a5d819

File tree

2 files changed

+61
-1
lines changed

2 files changed

+61
-1
lines changed

pydantic_ai_slim/pydantic_ai/_output.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ def get_output_context(
688688
mode: OutputMode,
689689
tool_call: _messages.ToolCallPart | None = None,
690690
tool_def: ToolDefinition | None = None,
691-
) -> OutputContext:
691+
) -> OutputContext: # pragma: no cover — overridden by all subclasses
692692
"""Return context information about this processor for output hooks."""
693693
return OutputContext(
694694
mode=mode, output_type=None, object_def=None, has_function=False, tool_call=tool_call, tool_def=tool_def

tests/test_output_hooks.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,66 @@ async def run():
16971697
assert isinstance(result, MyOutput)
16981698
assert result.value == 7
16991699

1700+
def test_no_capability_fast_path_structured_validation_error(self):
1701+
"""When capability is None, process() wraps ValidationError in ToolRetryError."""
1702+
import asyncio
1703+
1704+
from pydantic_ai._output import ObjectOutputProcessor, run_output_with_hooks
1705+
from pydantic_ai._run_context import RunContext
1706+
from pydantic_ai.exceptions import ToolRetryError
1707+
1708+
processor = ObjectOutputProcessor(output=MyOutput)
1709+
1710+
async def run():
1711+
ctx = RunContext(
1712+
deps=None,
1713+
model=None, # type: ignore
1714+
usage=None, # type: ignore
1715+
prompt='test',
1716+
run_step=0,
1717+
retry=0,
1718+
max_retries=3,
1719+
trace_include_content=False,
1720+
tracer=NoOpTracer(),
1721+
instrumentation_version=0,
1722+
)
1723+
return await run_output_with_hooks(
1724+
processor, 'not valid json', run_context=ctx, capability=None, output_mode='prompted'
1725+
)
1726+
1727+
with pytest.raises(ToolRetryError):
1728+
asyncio.get_event_loop().run_until_complete(run())
1729+
1730+
def test_no_capability_fast_path_union_validation_error(self):
1731+
"""When capability is None, UnionOutputProcessor.process() wraps ValidationError in ToolRetryError."""
1732+
import asyncio
1733+
1734+
from pydantic_ai._output import UnionOutputProcessor, run_output_with_hooks
1735+
from pydantic_ai._run_context import RunContext
1736+
from pydantic_ai.exceptions import ToolRetryError
1737+
1738+
processor = UnionOutputProcessor(outputs=[MyOutput])
1739+
1740+
async def run():
1741+
ctx = RunContext(
1742+
deps=None,
1743+
model=None, # type: ignore
1744+
usage=None, # type: ignore
1745+
prompt='test',
1746+
run_step=0,
1747+
retry=0,
1748+
max_retries=3,
1749+
trace_include_content=False,
1750+
tracer=NoOpTracer(),
1751+
instrumentation_version=0,
1752+
)
1753+
return await run_output_with_hooks(
1754+
processor, 'not valid json', run_context=ctx, capability=None, output_mode='prompted'
1755+
)
1756+
1757+
with pytest.raises(ToolRetryError):
1758+
asyncio.get_event_loop().run_until_complete(run())
1759+
17001760
def test_hooks_on_output_execute_via_hooks_class(self):
17011761
"""Test wrap_output_execute via Hooks decorator API."""
17021762

0 commit comments

Comments
 (0)