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
Annotated type PlainSerializer not used if placed before PlainValidator #8512
Comments
Thanks for reporting this. This does look like a bug 🐛. We'll work on a fix for this unexpected behavior 👍. |
Thank you for your reply. I've conducted a little experiment, that you might consider interesting: import json
from itertools import combinations, chain, permutations
from typing import Annotated, Any
from pydantic import BaseModel, Field, PlainValidator, PlainSerializer
import pytest
SERIALIZER = PlainSerializer(lambda x: str(int(x)), return_type=str)
VALIDATOR = PlainValidator(lambda x: bool(int(x)))
FIELD = Field(description="some description")
def powerset(item, iterable):
"""Generate all permutations with all combinations containing the ``item``
argument.
"""
s = list(iterable)
return chain.from_iterable(
permutations([item, *combination])
for combination in chain.from_iterable(
(combinations(s, r)
for r in range(len(s)+1))))
IDS_HELPER = {SERIALIZER: "S", VALIDATOR: "V", FIELD: "F"}
def idfn(value):
"""Generate an ID for the annotation combination"""
return str([IDS_HELPER[item] for item in value]).replace("'", "")
def model_dump(obj) -> dict[str, Any]:
return obj.model_dump()
def model_dump_json(obj) -> dict[str, Any]:
"""Call model_dump_json, then reload the string"""
return json.loads(obj.model_dump_json())
@pytest.mark.parametrize(
"annotations", powerset(SERIALIZER, [VALIDATOR, FIELD]), ids=idfn)
@pytest.mark.parametrize(
"dumper", [model_dump, model_dump_json])
def test_unexpected_behaviour(dumper, annotations):
"""Through all combinations and permutations of annotations, validate that
a field typed is correctly serialized.
"""
class Blah(BaseModel):
"""Our regular bogus model"""
x: Annotated[bool, *annotations]
blah = Blah(x=True)
data = dumper(blah)
assert isinstance(data['x'], str), annotations This code tests all permutations of annotations and it produced the following results.
As you can see,
Hope this helps. |
Hello Again. I had too much free time (if such thing exists), so I decided to track down that bug a bit. Here is what I found:
As you can see, the If I understand the code correctly (and please correct me if I wrong), when you have field using Aaaand On this hypothesis I've tested this: Anvil@3acce21 I have no idea if this is stable in the grand scheme of pydantic things, though. Would that be enough ? Should I make a pull request with that ? |
Thanks for taking the time to help us fix this! You're totally on the right track. Will review your PR here shortly - looking forward to it 💯 ! |
Initial Checks
Description
Dear pydantic maintainers and community.
Thank you very much for your time, your code and the documentation that comes along. All of them are very useful to me.
I've encountered a strange behaviour lately: depending of the place of order of PlainValidator and PlainSerializer in a annotated type, the serializer may or may not be used.
Please take a look a the code below. I would expect BRight and BWrong to produce the same results. I've tested with some other functions in the serializer and it had the same outcome.
Is this an intended behaviour ? I could not find any information about that in the documentation, and I apologize in advance if I overlooked.
Example Code
Python, Pydantic & OS Version
The text was updated successfully, but these errors were encountered: