Skip to content

Model before validator receives model dict representation when validating assignment #11823

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
1 task done
sisp opened this issue May 1, 2025 · 3 comments
Open
1 task done
Labels
bug V2 Bug related to Pydantic V2 pending Is unconfirmed

Comments

@sisp
Copy link

sisp commented May 1, 2025

Initial Checks

  • I confirm that I'm using Pydantic V2

Description

When validating the assignment to a model field with validate_assignment=True, the model before validator receives a dict representation of the model instance and not the instance. This is inconsistent with the model wrap validator which always receives the instance.

Example Code

from typing import Annotated, Any, Self

from pydantic import (
    AfterValidator,
    BaseModel,
    BeforeValidator,
    ModelWrapValidatorHandler,
    ValidatorFunctionWrapHandler,
    WrapValidator,
    model_validator,
)


def _field_before_validator(value: Any) -> Any:
    print("field before validator", value, type(value))
    return value


def _field_after_validator(value: Any) -> Any:
    print("field after validator:", value, type(value))
    return value


def _field_wrap_validator(value: Any, handler: ValidatorFunctionWrapHandler) -> Any:
    print("field wrap validator (before):", value, type(value))
    self = handler(value)
    print("field wrap validator (after):", self, type(self))
    return self


class M(BaseModel, validate_assignment=True):
    x: Annotated[
        str,
        AfterValidator(_field_after_validator),
        BeforeValidator(_field_before_validator),
        WrapValidator(_field_wrap_validator),
    ]

    @model_validator(mode="wrap")
    @classmethod
    def _model_wrap_validator(
        cls, data: Any, handler: ModelWrapValidatorHandler[Self]
    ) -> Self:
        print("model wrap validator (before):", data, type(data))
        self = handler(data)
        print("model wrap validator (after):", self, type(self))
        return self

    @model_validator(mode="before")
    @classmethod
    def _model_before_validator(cls, data: Any) -> Any:
        print("model before validator:", data, type(data))
        return data

    @model_validator(mode="after")
    def _model_after_validator(self) -> Self:
        print("model after validator:", self, type(self))
        return self


m = M(x="foo")
# model wrap validator (before): {'x': 'foo'} <class 'dict'>
# model before validator: {'x': 'foo'} <class 'dict'>
# field wrap validator (before): foo <class 'str'>
# field before validator foo <class 'str'>
# field after validator: foo <class 'str'>
# field wrap validator (after): foo <class 'str'>
# model wrap validator (after): x='foo' <class '__main__.M'>
# model after validator: x='foo' <class '__main__.M'>

m.x = "bar"
# model wrap validator (before): x='foo' <class '__main__.M'>
# model before validator: {'x': 'bar'} <class 'dict'>
# field wrap validator (before): bar <class 'str'>
# field before validator bar <class 'str'>
# field after validator: bar <class 'str'>
# field wrap validator (after): bar <class 'str'>
# model wrap validator (after): x='bar' <class '__main__.M'>
# model after validator: x='bar' <class '__main__.M'>

Python, Pydantic & OS Version

pydantic version: 2.11.3
        pydantic-core version: 2.33.1
          pydantic-core build: profile=release pgo=false
                 install path: .../.venv/lib/python3.13/site-packages/pydantic
               python version: 3.13.0 (main, Oct  8 2024, 01:04:00) [Clang 18.1.8 ]
                     platform: Linux-6.8.0-57-generic-x86_64-with-glibc2.35
             related packages: mypy-1.15.0 typing_extensions-4.13.2
                       commit: unknown
@sisp sisp added bug V2 Bug related to Pydantic V2 pending Is unconfirmed labels May 1, 2025
@Viicos
Copy link
Member

Viicos commented May 1, 2025

This should be expected (see #7454), although I'm not entirely sure why the model before validator has the dict form.

@sisp
Copy link
Author

sisp commented May 1, 2025

Oh, I see. Would you like me to rename the title and rephrase the description to refer to the unexpected model before validator value type?

@Viicos
Copy link
Member

Viicos commented May 1, 2025

Would you like me to rename the title and rephrase the description to refer to the unexpected model before validator value type?

That would be great thanks.

@sisp sisp changed the title Model wrap validator receives model instance when validating assignment Model before validator receives model dict representation when validating assignment May 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug V2 Bug related to Pydantic V2 pending Is unconfirmed
Projects
None yet
Development

No branches or pull requests

2 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy