Skip to content

Skip reusing wrap validators / serializers for prebuilt variants #1660

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

Merged
merged 4 commits into from
Mar 4, 2025

Conversation

sydney-runkle
Copy link
Contributor

@sydney-runkle sydney-runkle commented Mar 4, 2025

Reuse of wrap validators / serializers leads to some really odd behavior (double calls).

This PR fixes pydantic/pydantic#11505 and fixes #1651, where you can find some reproducible examples.

This bug was originally introduced by me in #1616 where we added reuse of schema validators and serializers to optimize memory in the case of reused models.

As discussed with DH, perhaps a cleaner approach going forward would be to use a new type of core schema to control reuse of schema validators and serializers. Though this avoids introducing edge case checks like this one in pydantic-core, it just pushes the burden up to pydantic, where things actually may be more complicated (ex - with schema cleaning + discriminator application or parametrized generics).

Note: the failing integration tests are not related to this PR. I think it makes sense to add corresponding tests to pydantic for the realistic use case here - I'll do that when we bump the version after a pydantic-core release.

Comment on lines +21 to +23
if matches!(schema_serializer.get().serializer, CombinedSerializer::FunctionWrap(_)) {
return Ok(None);
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather we check against disallowed variants here rather than all allowed variants - it keeps things cleaner.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we go further and check that schema's type matches the type of the serializer?

e.g. maybe

match &schema_serializer.get().serializer {
    CombinedSerializer::Model(_) => // check schema[type] is model
    ... same for other expected types
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, because I think it would be acceptable to have a PlainSerialier, for example for a model?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we perhaps write a test to demonstrate that case? (We can use the repr to show that a prebuilt serializer is used.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Absolutely, happy to!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done via 6efdfc9

Copy link

codspeed-hq bot commented Mar 4, 2025

CodSpeed Performance Report

Merging #1660 will not alter performance

Comparing double-prebuilt-fix (ff93f1a) with main (66c8c58)

Summary

✅ 157 untouched benchmarks

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These added tests fail on main because two 'modified' additions are made (double call of respective val / ser.

@sydney-runkle sydney-runkle enabled auto-merge (squash) March 4, 2025 19:39
@sydney-runkle sydney-runkle merged commit 72350a1 into main Mar 4, 2025
26 of 28 checks passed
@sydney-runkle sydney-runkle deleted the double-prebuilt-fix branch March 4, 2025 19:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants