Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Reuse cached core schemas for parametrized generic Pydantic models#11434

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Viicos merged 1 commit intopydantic:mainfromMarkusSintonen:allow-generic-ref
Feb 13, 2025

Conversation

MarkusSintonen
Copy link
Contributor

@MarkusSintonenMarkusSintonen commentedFeb 12, 2025
edited
Loading

Change Summary

Speeds up generics initialization significantly in the codspeed benchmark (+67.4%).

Related issue number

Many of the model init slowness related issues eg.#6768

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

davidhewitt, sydney-runkle, gamgi, scottzach1, and rishabhc32 reacted with heart emojisamuelcolvin, dolfinus, sydney-runkle, Viicos, scottzach1, and rishabhc32 reacted with rocket emojidmontagu reacted with eyes emoji
@github-actionsgithub-actionsbot added the relnotes-fixUsed for bugfixes. labelFeb 12, 2025
@github-actionsGitHub Actions
Copy link
Contributor

github-actionsbot commentedFeb 12, 2025
edited
Loading

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  pydantic
  main.py752
  pydantic/_internal
  _generate_schema.py
Project Total 

This report was generated bypython-coverage-comment-action

@codspeed-hqCodSpeed HQ
Copy link

codspeed-hqbot commentedFeb 12, 2025
edited
Loading

CodSpeed Performance Report

Merging#11434 willimprove performances by 67.14%

ComparingMarkusSintonen:allow-generic-ref (7e7c6dd) withmain (ff3789d)

Summary

⚡ 1 improvements
✅ 45 untouched benchmarks

Benchmarks breakdown

BenchmarkBASEHEADChange
test_fastapi_startup_perf142.5 ms85.3 ms+67.14%

@MarkusSintonenMarkusSintonen changed the titleAllow definition_reference_schemas for generics without reconstructingSpeed up generics initialization by allowing definition_reference_schemas without reconstructingFeb 12, 2025
Comment on lines -717 to -719
# Due to the way generic classes are built, it's possible that an invalid schema may be temporarily
# set on generic classes. Probably we could resolve this to ensure that we get proper schema caching
# for generics, but for simplicity for now, we just always rebuild if the class has a generic origin:
Copy link
ContributorAuthor

@MarkusSintonenMarkusSintonenFeb 12, 2025
edited
Loading

Choose a reason for hiding this comment

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

This is pretty weird stuff here... All tests pass fine. Looking at git blame this has been copied over through different refactorings. Most likely not a relevant thing anymore as everything works fine...

sydney-runkle reacted with eyes emoji
Copy link
Contributor

Choose a reason for hiding this comment

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

Makes me a bit nervous, but given you are probably one of the heaviest users of pydantic generics, my guess is that if you aren't seeing bugs, it's probably working okay? 😅 Admittedly this code has gotten a lot of refactoring since I was last looking at it heavily

MarkusSintonen and Mazyod reacted with laugh emojisydney-runkle reacted with heart emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

I can do some integration testing to stuff on our end. But I think the existing unit tests around here cover everything already.

Copy link
Contributor

Choose a reason for hiding this comment

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

An integration test on your end would be great 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Given the example I shared below I'm a little more confident it's safe

sydney-runkle reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

An integration test on your end would be great 👍

Run the tests on our end and everything works. Did it on 2.10.6 with this change on top.

@MarkusSintonen
Copy link
ContributorAuthor

please review

pydantic-hooky[bot] and sydney-runkle reacted with thumbs up emoji

@sydney-runkle
Copy link
Contributor

sydney-runkle commentedFeb 12, 2025
edited
Loading

@MarkusSintonen,

Woah, super small diff, incredible perf boost. We need to look into consequences here, but all tests passing seems quite promising. I've pinged@dmontagu to double check this (he did a lot of the initial work on generics), and@Viicos will also probably want to have a look.

I'm running third party tests to see if any integrations fail.

@sydney-runklesydney-runkle added relnotes-performanceUsed for performance improvements. third-party-testsAdd this label on a PR to trigger 3rd party tests and removed relnotes-fixUsed for bugfixes. labelsFeb 12, 2025
Copy link
Contributor

@dmontagudmontagu left a comment

Choose a reason for hiding this comment

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

I'll note that if this were going to introduce any issues, it would be with complex recursive generics

sydney-runkle reacted with thumbs up emoji
@sydney-runkle
Copy link
Contributor

Third party tests passing seems like a promising start.

@dmontagu
Copy link
Contributor

dmontagu commentedFeb 12, 2025
edited
Loading

I'll just share that I wrote an (in-my-opinion) complex recursive generic and tried to get validation to pass when it should not, and was not able to:

from __future__importannotationsfrompydanticimportBaseModelfromtypingimportTypeVar,GenericT=TypeVar('T')S=TypeVar('S')classA(BaseModel,Generic[T,S]):t_a:T|None=Nones_a:S|None=Noneb:B[T,S]|None=NoneclassB(BaseModel,Generic[T,S]):t_b:T|None=Nones_b:S|None=Nonec:C[T,S]|None=NoneclassC(BaseModel,Generic[T,S]):t_c:T|None=Nones_c:S|None=Nonea:A[T,S]|None=Nonea1=A[B[int,str],C[bool,float]](t_a=B(t_b=2,s_b='b',c=C(t_c=2,s_c='b')),s_a=C(t_c=True,s_c=1.0,a=A(t_a=True,s_a=1.0)),)b1=B[B[int,str],C[bool,float]](t_b=a1.t_a,s_b=a1.s_a,c=C[B[int,str],C[bool,float]](a=a1))data= {'t_b': {'t_b':2,'s_b':'b','c': {'t_c':2,'s_c':'b','a':None}},'s_b': {'t_c':True,'s_c':1.0,'a': {'t_a':True,'s_a':1.0,'b':None}},'c': {'t_c':None,'s_c':None,'a': {'t_a': {'t_b':2,'s_b':'b','c': {'t_c':2,'s_c':'b','a':None}},'s_a': {'t_c':True,'s_c':1.0,'a': {'t_a':True,'s_a':1.0,'b':None}},'b':None,        },    },}b1.model_validate(data)

If I edited any of the stuff indata, it was producing the validation errors I expected, not letting some data through like I feared it might.

So I feel like whatever concerns I had might have been mitigated by improvements to our generics handling in the time since I was responsible for it 😅.

MarkusSintonen reacted with thumbs up emojisydney-runkle and davidhewitt reacted with heart emoji

Copy link
Contributor

@sydney-runklesydney-runkle left a comment
edited
Loading

Choose a reason for hiding this comment

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

Given the above test passing, and all of our current tests, and all of our third party tests, I'm approving this. Great find@MarkusSintonen!! This will pair quite well with our other performance improvements in v2.11.

I'll wait for@Viicos to approve as well.

MarkusSintonen reacted with thumbs up emoji
@dmontagu
Copy link
Contributor

dmontagu commentedFeb 12, 2025
edited
Loading

@MarkusSintonen I'm curious how much of a startup speed improvement you noticed on your own codebase. Was it significantly more/less than the codspeed benchmark here, or comparable? (Basically trying to get an intuition for how representative this codspeed example is of your usage patterns.)

@samuelcolvin
Copy link
Member

this is awesome. Thank you@MarkusSintonen.

MarkusSintonen reacted with thumbs up emojisydney-runkle and Mazyod reacted with rocket emoji

@samuelcolvinsamuelcolvin changed the titleSpeed up generics initialization by allowing definition_reference_schemas without reconstructingSpeed up generics initialization by allowingdefinition_reference_schemas without reconstructingFeb 12, 2025
@ViicosViicos changed the titleSpeed up generics initialization by allowingdefinition_reference_schemas without reconstructingReuse cached core schemas for parametrized generic Pydantic modelsFeb 12, 2025
@MarkusSintonen
Copy link
ContributorAuthor

MarkusSintonen commentedFeb 13, 2025
edited
Loading

@MarkusSintonen I'm curious how much of a startup speed improvement you noticed on your own codebase. Was it significantly more/less than the codspeed benchmark here, or comparable? (Basically trying to get an intuition for how representative this codspeed example is of your usage patterns.)

It is quite close to what we see here from codspeed. I got about +50-60% in the full initialization time of the whole FastAPI stack utilizing generics with different complexities.

sydney-runkle reacted with thumbs up emoji

@MarkusSintonen
Copy link
ContributorAuthor

I'll just share that I wrote an (in-my-opinion) complex recursive generic and tried to get validation to pass when it should not, and was not able to

@dmontagu do you think it would make sense to add your test as part of the unit tests here if you are unsure if the case is covered?

sydney-runkle reacted with thumbs up emoji

@sydney-runkle
Copy link
Contributor

do you think it would make sense to add your test as part of the unit tests here if you are unsure if the case is covered?

Yes, let's!

@Viicos
Copy link
Member

I thinktest_generic_recursive_models_complicated already covers this example, although it could be tweaked a bit?

sydney-runkle reacted with heart emoji

@ViicosViicos merged commit2f3e1ac intopydantic:mainFeb 13, 2025
128 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@dmontagudmontagudmontagu left review comments

@sydney-runklesydney-runklesydney-runkle approved these changes

Assignees

@sydney-runklesydney-runkle

Labels
ready for reviewrelnotes-performanceUsed for performance improvements.third-party-testsAdd this label on a PR to trigger 3rd party tests
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

5 participants
@MarkusSintonen@sydney-runkle@dmontagu@samuelcolvin@Viicos

[8]ページ先頭

©2009-2025 Movatter.jp