File field-name-validator-core-schemas.patch of Package python-pydantic
From cd0d37c4c18f24b5624ae86cfe5288cd82edf2c1 Mon Sep 17 00:00:00 2001
From: Douwe Maan <hi@douwe.me>
Date: Wed, 16 Apr 2025 18:01:58 +0000
Subject: [PATCH 1/4] Stop using deprecated field_name argument on validation
function schemas
---
docs/concepts/types.md | 2 +-
pydantic/_internal/_generate_schema.py | 45 ++++++++++----------------
pydantic/functional_validators.py | 5 +--
tests/test_validators.py | 2 +-
4 files changed, 20 insertions(+), 34 deletions(-)
Index: pydantic-2.11.7/docs/concepts/types.md
===================================================================
--- pydantic-2.11.7.orig/docs/concepts/types.md
+++ pydantic-2.11.7/docs/concepts/types.md
@@ -979,7 +979,7 @@ class CustomType:
cls, source_type: Any, handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.with_info_after_validator_function(
- cls.validate, handler(int), field_name=handler.field_name
+ cls.validate, handler(int)
)
Index: pydantic-2.11.7/pydantic/_internal/_generate_schema.py
===================================================================
--- pydantic-2.11.7.orig/pydantic/_internal/_generate_schema.py
+++ pydantic-2.11.7/pydantic/_internal/_generate_schema.py
@@ -222,7 +222,6 @@ def filter_field_decorator_info_by_field
def apply_each_item_validators(
schema: core_schema.CoreSchema,
each_item_validators: list[Decorator[ValidatorDecoratorInfo]],
- field_name: str | None,
) -> core_schema.CoreSchema:
# This V1 compatibility shim should eventually be removed
@@ -234,21 +233,20 @@ def apply_each_item_validators(
# note that this won't work for any Annotated types that get wrapped by a function validator
# but that's okay because that didn't exist in V1
if schema['type'] == 'nullable':
- schema['schema'] = apply_each_item_validators(schema['schema'], each_item_validators, field_name)
+ schema['schema'] = apply_each_item_validators(schema['schema'], each_item_validators)
return schema
elif schema['type'] == 'tuple':
if (variadic_item_index := schema.get('variadic_item_index')) is not None:
schema['items_schema'][variadic_item_index] = apply_validators(
schema['items_schema'][variadic_item_index],
each_item_validators,
- field_name,
)
elif is_list_like_schema_with_items_schema(schema):
inner_schema = schema.get('items_schema', core_schema.any_schema())
- schema['items_schema'] = apply_validators(inner_schema, each_item_validators, field_name)
+ schema['items_schema'] = apply_validators(inner_schema, each_item_validators)
elif schema['type'] == 'dict':
inner_schema = schema.get('values_schema', core_schema.any_schema())
- schema['values_schema'] = apply_validators(inner_schema, each_item_validators, field_name)
+ schema['values_schema'] = apply_validators(inner_schema, each_item_validators)
else:
raise TypeError(
f'`@validator(..., each_item=True)` cannot be applied to fields with a schema of {schema["type"]}'
@@ -840,7 +838,7 @@ class GenerateSchema:
extras_keys_schema=extras_keys_schema,
model_name=cls.__name__,
)
- inner_schema = apply_validators(fields_schema, decorators.root_validators.values(), None)
+ inner_schema = apply_validators(fields_schema, decorators.root_validators.values())
inner_schema = apply_model_validators(inner_schema, model_validators, 'inner')
model_schema = core_schema.model_schema(
@@ -1380,9 +1378,9 @@ class GenerateSchema:
field_info.validate_default = True
each_item_validators = [v for v in this_field_validators if v.info.each_item is True]
this_field_validators = [v for v in this_field_validators if v not in each_item_validators]
- schema = apply_each_item_validators(schema, each_item_validators, name)
+ schema = apply_each_item_validators(schema, each_item_validators)
- schema = apply_validators(schema, this_field_validators, name)
+ schema = apply_validators(schema, this_field_validators)
# the default validator needs to go outside of any other validators
# so that it is the topmost validator for the field validator
@@ -1972,7 +1970,7 @@ class GenerateSchema:
collect_init_only=has_post_init,
)
- inner_schema = apply_validators(args_schema, decorators.root_validators.values(), None)
+ inner_schema = apply_validators(args_schema, decorators.root_validators.values())
model_validators = decorators.model_validators.values()
inner_schema = apply_model_validators(inner_schema, model_validators, 'inner')
@@ -2484,24 +2482,16 @@ class GenerateSchema:
_VALIDATOR_F_MATCH: Mapping[
tuple[FieldValidatorModes, Literal['no-info', 'with-info']],
- Callable[[Callable[..., Any], core_schema.CoreSchema, str | None], core_schema.CoreSchema],
+ Callable[[Callable[..., Any], core_schema.CoreSchema], core_schema.CoreSchema],
] = {
- ('before', 'no-info'): lambda f, schema, _: core_schema.no_info_before_validator_function(f, schema),
- ('after', 'no-info'): lambda f, schema, _: core_schema.no_info_after_validator_function(f, schema),
- ('plain', 'no-info'): lambda f, _1, _2: core_schema.no_info_plain_validator_function(f),
- ('wrap', 'no-info'): lambda f, schema, _: core_schema.no_info_wrap_validator_function(f, schema),
- ('before', 'with-info'): lambda f, schema, field_name: core_schema.with_info_before_validator_function(
- f, schema, field_name=field_name
- ),
- ('after', 'with-info'): lambda f, schema, field_name: core_schema.with_info_after_validator_function(
- f, schema, field_name=field_name
- ),
- ('plain', 'with-info'): lambda f, _, field_name: core_schema.with_info_plain_validator_function(
- f, field_name=field_name
- ),
- ('wrap', 'with-info'): lambda f, schema, field_name: core_schema.with_info_wrap_validator_function(
- f, schema, field_name=field_name
- ),
+ ('before', 'no-info'): lambda f, schema: core_schema.no_info_before_validator_function(f, schema),
+ ('after', 'no-info'): lambda f, schema: core_schema.no_info_after_validator_function(f, schema),
+ ('plain', 'no-info'): lambda f, _: core_schema.no_info_plain_validator_function(f),
+ ('wrap', 'no-info'): lambda f, schema: core_schema.no_info_wrap_validator_function(f, schema),
+ ('before', 'with-info'): lambda f, schema: core_schema.with_info_before_validator_function(f, schema),
+ ('after', 'with-info'): lambda f, schema: core_schema.with_info_after_validator_function(f, schema),
+ ('plain', 'with-info'): lambda f, _: core_schema.with_info_plain_validator_function(f),
+ ('wrap', 'with-info'): lambda f, schema: core_schema.with_info_wrap_validator_function(f, schema),
}
@@ -2512,7 +2502,6 @@ def apply_validators(
validators: Iterable[Decorator[RootValidatorDecoratorInfo]]
| Iterable[Decorator[ValidatorDecoratorInfo]]
| Iterable[Decorator[FieldValidatorDecoratorInfo]],
- field_name: str | None,
) -> core_schema.CoreSchema:
"""Apply validators to a schema.
@@ -2528,7 +2517,7 @@ def apply_validators(
info_arg = inspect_validator(validator.func, validator.info.mode)
val_type = 'with-info' if info_arg else 'no-info'
- schema = _VALIDATOR_F_MATCH[(validator.info.mode, val_type)](validator.func, schema, field_name)
+ schema = _VALIDATOR_F_MATCH[(validator.info.mode, val_type)](validator.func, schema)
return schema
Index: pydantic-2.11.7/pydantic/functional_validators.py
===================================================================
--- pydantic-2.11.7.orig/pydantic/functional_validators.py
+++ pydantic-2.11.7/pydantic/functional_validators.py
@@ -75,7 +75,7 @@ class AfterValidator:
info_arg = _inspect_validator(self.func, 'after')
if info_arg:
func = cast(core_schema.WithInfoValidatorFunction, self.func)
- return core_schema.with_info_after_validator_function(func, schema=schema, field_name=handler.field_name)
+ return core_schema.with_info_after_validator_function(func, schema=schema)
else:
func = cast(core_schema.NoInfoValidatorFunction, self.func)
return core_schema.no_info_after_validator_function(func, schema=schema)
@@ -136,7 +136,6 @@ class BeforeValidator:
return core_schema.with_info_before_validator_function(
func,
schema=schema,
- field_name=handler.field_name,
json_schema_input_schema=input_schema,
)
else:
@@ -230,7 +229,6 @@ class PlainValidator:
func = cast(core_schema.WithInfoValidatorFunction, self.func)
return core_schema.with_info_plain_validator_function(
func,
- field_name=handler.field_name,
serialization=serialization, # pyright: ignore[reportArgumentType]
json_schema_input_schema=input_schema,
)
@@ -307,7 +305,6 @@ class WrapValidator:
return core_schema.with_info_wrap_validator_function(
func,
schema=schema,
- field_name=handler.field_name,
json_schema_input_schema=input_schema,
)
else:
Index: pydantic-2.11.7/tests/test_validators.py
===================================================================
--- pydantic-2.11.7.orig/tests/test_validators.py
+++ pydantic-2.11.7/tests/test_validators.py
@@ -21,7 +21,7 @@ from unittest.mock import MagicMock
import pytest
from dirty_equals import HasRepr, IsInstance
from pydantic_core import core_schema
-from typing_extensions import TypedDict
+from typing_extensions import TypeAliasType, TypedDict
from pydantic import (
BaseModel,
@@ -2684,7 +2684,7 @@ def foobar_validate(value: Any, info: co
class Foobar:
@classmethod
def __get_pydantic_core_schema__(cls, source_type: Any, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema:
- return core_schema.with_info_plain_validator_function(foobar_validate, field_name=handler.field_name)
+ return core_schema.with_info_plain_validator_function(foobar_validate)
def test_custom_type_field_name_model():
@@ -2779,6 +2779,29 @@ def test_plain_validator_field_name():
assert m.foobar == {'value': '1', 'field_name': 'foobar', 'data': {'x': 123}}
+def test_validator_field_name_with_reused_type_alias():
+ calls = []
+
+ def validate_my_field(value: str, info: ValidationInfo):
+ calls.append((info.field_name, value))
+ return value
+
+ MyField = TypeAliasType('MyField', Annotated[str, AfterValidator(validate_my_field)])
+
+ class MyModel(BaseModel):
+ field1: MyField
+ field2: MyField
+
+ MyModel.model_validate(
+ {
+ 'field1': 'value1',
+ 'field2': 'value2',
+ }
+ )
+
+ assert calls == [('field1', 'value1'), ('field2', 'value2')]
+
+
def validate_wrap(value: Any, handler: core_schema.ValidatorFunctionWrapHandler, info: core_schema.ValidationInfo):
data = info.data
if isinstance(data, dict):