Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork2.2k
Only evaluateFieldInfo
annotations if required during schema building#10769
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
Uh oh!
There was an error while loading.Please reload this page.
Conversation
@@ -1215,11 +1215,15 @@ def _common_field_schema( # C901 | |||
) -> _CommonField: | |||
# Update FieldInfo annotation if appropriate: | |||
FieldInfo = import_cached_field_info() | |||
if has_instance_in_type(field_info.annotation, (ForwardRef, str)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
The interesting part is that we remove the call tohas_instance_in_type
here.
cloudflare-workers-and-pagesbot commentedNov 5, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Deploying pydantic-docs with |
Latest commit: | 076da3c |
Status: | ✅ Deploy successful! |
Preview URL: | https://bf7a63be.pydantic-docs.pages.dev |
Branch Preview URL: | https://fieldinfo-evaluated.pydantic-docs.pages.dev |
Uh oh!
There was an error while loading.Please reload this page.
@@ -1338,12 +1342,13 @@ def _type_alias_type_schema(self, obj: TypeAliasType) -> CoreSchema: | |||
return maybe_schema | |||
origin: TypeAliasType = get_origin(obj) or obj | |||
annotation = origin.__value__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Moved below, as accessing the__value__
attribute will trigger the evaluation of the annotation, and thus this can raise aNameError
. Theeval_type
call is still necessary though, as you can have explicit string references inside a a type alias type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe I'm misunderstanding - was this moved below? Or do we not need this specific line anymore?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Basically, here is what can happen with type aliases:
typeA=Intannotation=origin.__value__# NameError, 'Int' is not definedtypeB='Int'annotation=origin.__value__assertannotation=='Int'eval_type(B, ..., ...)# NameError, 'Int' is not defined
So everything was moved in a singletry..except
block:
try:annotation=_typing_extra.eval_type(origin.__value__,*self._types_namespace)except ...: ...
codspeed-hqbot commentedNov 5, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
CodSpeed Performance ReportMerging#10769 willimprove performances by 8.54%Comparing Summary
Benchmarks breakdown
|
Uh oh!
There was an error while loading.Please reload this page.
367f48a
to88aa322
Comparegithub-actionsbot commentedNov 5, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Alrighty, left some initial comments on the implementation.
The tuple return doesn't feel like the cleanest implementation, but I can't come up with anything better off the top of my head. Let's chat first thing tomorrow morning about alternatives. I'm not opposed to this approach, but want to think about other options before we move forward 👍
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
'`eval_type_lenient` is deprecated, use `eval_type` with `lenient=True` instead.', | ||
'`eval_type_lenient` is deprecated, use `try_eval_type` instead.', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Hmm, this feels like an anti-pattern - if we already deprecated this, there's probably a reason why we didn't want to have two functions. Even if we disagree with this deprecation now, seems like a lot of churn to basically reintroduce the function and redirect for the deprecated case...
I believe my suggestion above re always returning a second value,evaluated
, even in the case ofeval_type
withlenient=False
might help, and we can leave this be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
A few more follow ups:
- This is a very internal function - can we just deprecate this?
- If we were to bring back a second function, to reduce churn, can we call it
eval_type_lenient
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
I had to keep this function during the types namespaces refactor because fastapi makes use of it 🫤. I added thedeprecated
decorator so that type checking fails in the fastapi CI and they can use the correct function (or best, do not rely on our internals because I don't think the_typing_extra
module is stable enough, we might apply other changes here in the future).
I believe my suggestion above re always returning a second value,
evaluated
, even in the case ofeval_type
withlenient=False
might help, and we can leave this be?
Same issue ashttps://github.com/pydantic/pydantic/pull/10769/files#r1832947088, we can't have a single function because we want to catch theNameError
to reraisePydanticUndefinedAnnotation
Uh oh!
There was an error while loading.Please reload this page.
Uh oh!
There was an error while loading.Please reload this page.
@@ -1338,12 +1342,13 @@ def _type_alias_type_schema(self, obj: TypeAliasType) -> CoreSchema: | |||
return maybe_schema | |||
origin: TypeAliasType = get_origin(obj) or obj | |||
annotation = origin.__value__ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Maybe I'm misunderstanding - was this moved below? Or do we not need this specific line anymore?
![]() Wow@Viicos, nice work here. Didn't realize this would have that significant of an impact. We can chat about potential other APIs for this, but we should definitely move forward with this change :). Does this unblock the |
sydney-runkle commentedNov 7, 2024 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
Another follow up - what if we returned something like this: frompythonimportTypedDictclassTypeEvaluationResult(TypedDict):evaluated:boolresult:Anyerror:NameError|None Or something like: frompythonimportTypedDict,TypeAliasclassTypeEvaluationSuccess(TypedDict):evaluated:Literal[True]result:AnyclassTypeEvaluationFailure(TypedDict):evaluated:Literal[False]error:NameErrortypeTypeEvaluationResult=TypeEvaluationSuccess|TypeEvaluationFailure Doesn't have to be either of those exactly, but I think you get the point :). Then, we could have one function and preserve relevant errors, but also intuitively handle attempted evals? Maybe this isn't better, but I think it does help us avoid the overloads, though admittedly there's more conditional logic required after a function call, as the result can be many things. Could even do a named tuple. |
Seems like both the overload and structured return value have different drawbacks: what is Maybe it's worth revisiting the API, if we want to make this module more stable and maybe expose it publicly, as it is used already by some other projects. |
Yeah, fair point. Let's not go with the structured return. One other idea - could we revert to that single signature idea, and manufacture a |
You mean something like |
Or even like |
but the issue is we currently raise using
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others.Learn more.
Looking over this again, seems reasonable, given the constraints we've discussed re typing and overloads.
Going to go ahead and merge. We can cherry pick relevant stuff for the v2.10 official release (not including this). |
By adding a new `evaluated` attribute that can be set during modelfields collection. Also refactor a bit the utility functions to evalsuch annotations.
ed6e232
to076da3c
Comparebcfd413
intomainUh oh!
There was an error while loading.Please reload this page.
By adding a new
evaluated
attribute that can be set during model fields collection. Also refactor a bit the utility functions to eval such annotations.Change Summary
Related issue number
Checklist