mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
70 lines
2.3 KiB
Python
70 lines
2.3 KiB
Python
"""regenerate_verb_tables._annot_str strips Annotated metadata (#199).
|
|||
|
|
|
||
|
|
The flow schemas type coercion-hardened list fields as
|
||
|
|
``StrList = Annotated[list[str], BeforeValidator(coerce_str_list)]``. The old
|
||
|
|
``_annot_str`` walked ``get_args(Annotated[list[str], BeforeValidator(...)])``
|
||
|
|
and rendered the ``BeforeValidator(...)`` repr into the generated
|
||
|
|
``verbs.md`` / per-role prompts — leaking an internal validator object (with
|
||
|
|
a memory address) into agent-facing prompt text. The fix unwraps
|
||
|
|
``Annotated[T, ...]`` to ``T`` before rendering.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import importlib.util
|
||
|
|
from pathlib import Path
|
||
|
|
from typing import TYPE_CHECKING, Annotated
|
||
|
|
|
||
|
|
from pydantic import BaseModel, BeforeValidator, Field
|
||
|
|
|
||
|
|
if TYPE_CHECKING:
|
||
|
|
from types import ModuleType
|
||
|
|
|
||
|
|
_SCRIPT = Path(__file__).resolve().parents[2] / "scripts" / "regenerate_verb_tables.py"
|
||
|
|
|
||
|
|
|
||
|
|
def _load_module() -> ModuleType:
|
||
|
|
spec = importlib.util.spec_from_file_location("_regen_verb_tables", _SCRIPT)
|
||
|
|
assert spec is not None and spec.loader is not None
|
||
|
|
module = importlib.util.module_from_spec(spec)
|
||
|
|
spec.loader.exec_module(module)
|
||
|
|
return module
|
||
|
|
|
||
|
|
|
||
|
|
def _coerce(x: object) -> list[str]:
|
||
|
|
return [str(x)]
|
||
|
|
|
||
|
|
|
||
|
|
_StrList = Annotated[list[str], BeforeValidator(_coerce)]
|
||
|
|
|
||
|
|
|
||
|
|
def test_annot_str_strips_before_validator_metadata() -> None:
|
||
|
|
mod = _load_module()
|
||
|
|
assert mod._annot_str(_StrList) == "list[str]"
|
||
|
|
|
||
|
|
|
||
|
|
def test_annot_str_strips_metadata_in_optional_union() -> None:
|
||
|
|
# The schemas use ``StrList | None``; the metadata must drop on both arms.
|
||
|
|
mod = _load_module()
|
||
|
|
assert mod._annot_str(_StrList | None) == "list[str] | None"
|
||
|
|
|
||
|
|
|
||
|
|
def test_annot_str_plain_types_unchanged() -> None:
|
||
|
|
mod = _load_module()
|
||
|
|
assert mod._annot_str(list[str]) == "list[str]"
|
||
|
|
assert mod._annot_str(str | None) == "str | None"
|
||
|
|
assert mod._annot_str(None) == "None"
|
||
|
|
|
||
|
|
|
||
|
|
def test_signature_for_schema_has_no_beforevalidator_repr() -> None:
|
||
|
|
# End-to-end: a schema with a StrList | None field renders a clean
|
||
|
|
# signature, no ``BeforeValidator(func=...)`` leak.
|
||
|
|
class _Sample(BaseModel):
|
||
|
|
ac_verdicts: _StrList | None = Field(default=None)
|
||
|
|
notes: str
|
||
|
|
|
||
|
|
mod = _load_module()
|
||
|
|
sig = mod._signature_for_schema(_Sample)
|
||
|
|
assert "BeforeValidator" not in sig
|
||
|
|
assert "list[str] | None" in sig
|