-
-
Notifications
You must be signed in to change notification settings - Fork 397
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
fix(typing): always unwrap TypeAliasType
s
#3982
base: main
Are you sure you want to change the base?
Conversation
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 also don't quite know on how to proceed. I think that probably documenting different corner cases is a must here. For example: how different serializer frameworks handle recursive aliases and when to use them. Maybe some recipies.
Thanks for raising this! I am really interested in this topic.
I think this might be related: python/mypy#18252 Mypy also doesn't seem to handle these cyclic definitions |
while stack: | ||
ann = stack.pop() | ||
|
||
if isinstance(ann, TypeAliasType): |
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.
Just a heads up: typing-extensions
4.13.0 (yet to be released) has a backported TypeAliasType
version, meaning:
from typing import TypeAliasType
from typing_extensions import TypeAliasType as ExtensionsTypeAliasType
Test = ExtensionsTypeAliasType('Test', int)
isinstance(Test, TypeAliasType)
#> False
Also on Python 3.10 a bug leads to the following:
T = TypeVar('T')
Test = TypeAliasType('Test', list[T], type_params=(T,))
isinstance(Test[int], TypeAliasType)
#> True, but should be false as Test[int] is a `types.GenericAlias` instance`. In your case, your are going to loose the parametrization and `__value__` will be list[T]
This is how we do it in Pydantic.
Overall it seems that you may face similar issues in the future if typing-extensions starts exposing new versions of the typing.*
constructs. One example is also in this function: you extract type qualifiers such as Required
, and latter in the code base a Required in type_wrappers
is performed. Currently, typing_extensions
reexports typing.(Not)Required
on 3.11, but that might change in the future.
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.
Thanks for the heads up @Viicos! Seems like another indicator that what was discussed in beartype/beartype#479 (comment) would be quite useful
While fixing #3912 I noticed we only unwrap these partially. However, I am not sure if unwrapping them at all is proper, because of a particular edge case: They can be self-referential. This is used e.g. in
pydantic.JsonType
.SelfReferential = TypeAliasType("Outer", Union[Annotated[int, "meta"], list["Outer"]])
This type can be understood by e.g. mypy, but is hard to parse for our typing system since we want to extract the metadata from the
Annotated
, but need to keep the outerTypeAliasType
, so the self-referencing works in later stages (e.g. Pydantic).I'm not entirely sure how we should best handle this, as our typing system has fundamentally different requirements than that of the 3rd party tools we rely on.
Divergences in how self-referential types are treated by these tools further complicates things.
For example, this is fine in Pydantic:
But msgspec raises a
RecursionError
:Not really sure yet how to proceed, I'll have to think about this a bit. I'd be happy about some input though @litestar-org/members