Skip to content

duplicate use of the model's wrap serializer #11812

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
ornariece opened this issue Apr 29, 2025 · 4 comments
Open
1 task done

duplicate use of the model's wrap serializer #11812

ornariece opened this issue Apr 29, 2025 · 4 comments
Labels
bug V2 Bug related to Pydantic V2

Comments

@ornariece
Copy link
Contributor

ornariece commented Apr 29, 2025

Initial Checks

  • I confirm that I'm using Pydantic V2

Description

this was introduced by 2.11(.x?).
this is probably related to #11505.

import pydantic
import pydantic_core


class MyModel(pydantic.RootModel):
    root: str

    @pydantic.model_serializer(mode="wrap")
    def my_wrapper_serializer(self, serializer: pydantic.SerializerFunctionWrapHandler):
        return "my_prefix:" + serializer(self)

    @classmethod
    def __get_pydantic_core_schema__(cls, source, handler):
        return pydantic_core.core_schema.union_schema(
            [
                handler(cls),
                # anything goes here, using duplicate schema for the example
                handler(cls),
            ]
        )


class MyParentModel(pydantic.BaseModel):
    nested: MyModel


if __name__ == "__main__":
    my_parent_model = MyParentModel.model_validate({'nested': 'value'})

    print(my_parent_model.model_dump())
    #>expected: {'nested': 'my_prefix:value'}
    #>actual:   {'nested': 'my_prefix:my_prefix:value'}

Example Code

Python, Pydantic & OS Version

pydantic version: 2.11.3
pydantic-core version: 2.33.1
pydantic-core build: profile=release pgo=false
python version: 3.13.0 (tags/v3.13.0:60403a5, Oct  7 2024, 09:38:07) [MSC v.1941 64 bit (AMD64)]
platform: Windows-10-10.0.19045-SP0
related packages: mypy-1.15.0 typing_extensions-4.13.2
commit: unknown
@ornariece ornariece added bug V2 Bug related to Pydantic V2 pending Is unconfirmed labels Apr 29, 2025
@pydanticai-bot
Copy link

PydanticAI Github Bot Found 1 issues similar to this one:

  1. "model_serializer in "wrap" mode called twice when model_dump called with serialize_as_any=True #11139" (90% similar)

@Viicos
Copy link
Member

Viicos commented Apr 30, 2025

Defining a custom __get_pydantic_core_schema__() can lead to unexpected results, and we decided not to explicitly support it.

There's a first issue happening: for Pydantic models, the core schema is cached in the __pydantic_core_schema__ property. For MyModel, you end up with MyModel.__pydantic_core_schema__ = {'type': 'union', 'choices': [...]} (constructed from your __get_pydantic_core_schema__() implementation). Then, when MyParentModel encounters MyModel for field nested, it will call the __get_pydantic_core_schema__() method again. When calling handler(cls), Pydantic will use the cached __pydantic_core_schema__ property (which already contains the 'union' schema). You then end up with a nested schema ({'type': 'union', 'choices': [{'type': 'union', 'choices': [...]}, ...]}).

What you need to do is manually reusing the cached attribute:

    @classmethod
    def __get_pydantic_core_schema__(cls, source, handler):
        schema = cls.__dict__.get('__pydantic_core_schema__')
        if schema is not None and isinstance(schema, dict):
            return cls.__pydantic_core_schema__
        return pydantic_core.core_schema.union_schema(
            [
                handler(cls),
                # anything goes here, using duplicate schema for the example
                handler(cls),
            ]
        )

The main issue still persists though, and I think it is indeed related to #11505. We knew the fix wasn't robust enough, so a different approach needs to be taken.

@Viicos Viicos removed the pending Is unconfirmed label Apr 30, 2025
@ornariece
Copy link
Contributor Author

thank you for the workaround 🙏.

Defining a custom get_pydantic_core_schema() can lead to unexpected results, and we decided not to explicitly support it.

does this mean this will get dropped completely? i'm heavily relying on it, especially for custom types, hence the ask.

@Viicos
Copy link
Member

Viicos commented May 4, 2025

Sorry I meant Defining a custom __get_pydantic_core_schema__() on Pydantic models, it is supported and will stay this way for custom types as documented.

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
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