Skip to content

Conversation

@davidhewitt
Copy link
Contributor

@davidhewitt davidhewitt commented Nov 11, 2025

Change Summary

(Imported from pydantic/pydantic-core#1881)

Introduced as a possible solution to #12382; the theory is that most uses of serialize_as_any are because users want to respect subtyping properly.

This PR introduces a configuration option and runtime flag polymorphic_serialization which is used to enable serializing subclasses of models and dataclasses as the subclass, not as the base class.

To maintain backwards compatibility, the default is False - models and dataclasses will be serialized as the exact type in the schema.

When the config is set to True, then models and dataclasess will be serialized as their runtime type. This also respects any model serializer the subclass may be using.

Users can also pass polymorphic_serialization as a runtime option to the serialization functions; doing so will override the config value (i.e. can be globally enabled or disabled).


Points of Discussion for this PR

Annotated metadata

Not explored yet in this PR, an additional / alternative possibility could be to expose this as some kind of wrapper so that for foreign types one can use Annotated[ForeignModel, PolymorphicSerialization] to enable this even when the type didn't opt in.

(An Annotated form may remove the need for the global runtime override.)

Non-Pydantic types

This method cannot really ever work for types which Pydantic doesn't know how to serialize, e.g. subclass of int will not be serialized polymorphically. If the subclass had a __pydantic_serializer__ attribute it could in theory work, but I think that's the unlikely case.

More complicated is stdlib dataclasses and TypedDict. It might be reasonable to expect these to work, but I think that would require inspection of the subclass types at runtime and somehow caching a serializer for them. (i.e. a lot of runtime callback into Pydantic.)

Backwards compatibility

For the concern listed above on non-pydantic types, one way to introduce support for them later would be to have the runtime flag accept a set of types to serialize, e.g. polymorphic_serialization = {BaseModel, BaseDataClass, int}

... but another way to avoid the problem entirely would be to not have the global runtime flag and use the Annotated form to apply this behavior only to supported types.

Related issue number

#12382

Checklist

  • The pull request title is a good summary of the changes - it will be used in the changelog
  • Unit tests for the changes exist
  • Tests pass on CI
  • Documentation reflects the changes where applicable
  • My PR is ready to review, please add a comment including the phrase "please review" to assign reviewers

@github-actions github-actions bot added the relnotes-fix Used for bugfixes. label Nov 11, 2025
@davidhewitt davidhewitt added relnotes-feature backport-2.12 Needs backport to 2.12 and removed relnotes-fix Used for bugfixes. labels Nov 11, 2025
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Nov 11, 2025

Deploying pydantic-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0f41f58
Status:🚫  Build failed.

View logs

@codspeed-hq
Copy link

codspeed-hq bot commented Nov 11, 2025

CodSpeed Performance Report

Merging #12518 will degrade performances by 5.05%

Comparing dh/polymorphic-serialization (3e0b894) with main (979b05f)

Summary

⚡ 3 improvements
❌ 1 regression
✅ 207 untouched

⚠️ Please fix the performance issues or acknowledge them on CodSpeed.

Benchmarks breakdown

Benchmark BASE HEAD Change
test_list_of_ints_core_json 781.2 µs 730 µs +7.02%
test_list_of_strs_json_cached 330.3 µs 296.5 µs +11.4%
test_list_of_strs_json_uncached 448.8 µs 414.9 µs +8.18%
test_validators_build 1 ms 1.1 ms -5.05%

@github-actions
Copy link
Contributor

github-actions bot commented Nov 21, 2025

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  pydantic
  config.py
  main.py
  pydantic/_internal
  _config.py
  pydantic-core/python/pydantic_core
  core_schema.py 184, 189
Project Total  

This report was generated by python-coverage-comment-action

@Viicos Viicos force-pushed the dh/polymorphic-serialization branch from f062486 to 3f56f5d Compare December 1, 2025 14:52
@Viicos Viicos changed the title add polymorphic_serialization flag Add polymorphic_serialization option Dec 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants