Preserve kw-only defaults when rebuilding functions for resolved annotations (#3429)

* Preserve kw-only defaults in cloned adapters (🤖 GPT-5.2-Codex)

* Fix ruff format violation in test_types.py
This commit is contained in:
Jeremiah Lowin 2026-03-07 12:10:01 -05:00 committed by GitHub
commit 58e25ccf47
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 21 additions and 0 deletions

View file

@ -88,12 +88,14 @@ def get_cached_typeadapter(cls: T) -> TypeAdapter[T]:
globals_dict = actual_func.__globals__ # ty: ignore[unresolved-attribute]
name = actual_func.__name__ # ty: ignore[unresolved-attribute]
defaults = actual_func.__defaults__ # ty: ignore[unresolved-attribute]
kwdefaults = actual_func.__kwdefaults__ # ty: ignore[unresolved-attribute]
closure = actual_func.__closure__ # ty: ignore[unresolved-attribute]
else:
code = cls.__code__
globals_dict = cls.__globals__
name = cls.__name__
defaults = cls.__defaults__
kwdefaults = cls.__kwdefaults__
closure = cls.__closure__
new_func = types.FunctionType(
@ -107,6 +109,7 @@ def get_cached_typeadapter(cls: T) -> TypeAdapter[T]:
new_func.__module__ = cls.__module__
new_func.__qualname__ = getattr(cls, "__qualname__", cls.__name__)
new_func.__annotations__ = processed_hints
new_func.__kwdefaults__ = kwdefaults
if inspect.ismethod(cls):
new_method = types.MethodType(new_func, cls.__self__)

View file

@ -671,3 +671,21 @@ class TestAnnotationStringDescriptions:
# Should keep the Field description
assert schema["properties"]["name"]["description"] == "Field desc"
def test_kwonly_defaults_preserved_when_annotations_are_processed(self):
"""Keyword-only defaults should survive function cloning during annotation processing."""
def func(*, limit: Annotated[int, "Maximum number of results"] = 5) -> int:
return limit
adapter = get_cached_typeadapter(func)
schema = adapter.json_schema()
assert "required" not in schema
assert schema["properties"]["limit"]["default"] == 5
assert (
schema["properties"]["limit"]["description"] == "Maximum number of results"
)
validated = adapter.validate_python({})
assert validated == 5