typing_inspect
typing_inspect copied to clipboard
get_origin gives inconsistent results for differently defined Unions
If I got it right, Union[X, Y] should be equivalent to X | Y . But I get inconsistent results for get_origin:
import typing
from types import UnionType
import typing_inspect
optional = typing.Optional[int]
union = typing.Union[int, None]
pipe = int | None
print(typing_inspect.get_origin(optional)) # typing.Union
print(typing_inspect.get_origin(union)) # typing.Union
print(typing_inspect.get_origin(pipe)) # None
Note that also the python std lib behaves inconsistent wrt this:
import typing
from types import UnionType
# also behaves odd for python stdlib functions
print(typing.get_origin(union), typing.get_args(union))
print(typing.get_origin(optional), typing.get_args(optional))
print(typing.get_origin(pipe), typing.get_args(pipe))
assert typing.get_origin(union) is typing.Union
assert typing.get_origin(optional) is typing.Union
assert typing.get_origin(pipe) is not typing.Union
assert typing.get_origin(union) is not UnionType
assert typing.get_origin(optional) is not UnionType
assert typing.get_origin(pipe) is UnionType
I would expect that the behavior is equivalent, but I'm pretty new to the typing world. In the end I' looking for a way to check if something is a union and var is Union or var is UnionType does not seem right...
Yes, I think it is a bug. We support X | Y syntax in is_union_type(). I am not sure what the value get_origin() should return (probably we should match typing behavior), but definitely not None.
We support X | Y syntax in is_union_type()
Thanks for the tip. I guess this will work for me.
I am not sure what the value get_origin() should return
From the docs: Union type; Union[X, Y] is equivalent to X | Y .. so they should behave the same, or?
probably we should match typing behavior
Also a good idea. But maybe (just maybe) upstream is wrong :)
In Python 3.13 we may well merge types.UnionType and typing.Union: https://github.com/python/cpython/issues/105499. But in earlier Python versions we're not going to change the upstream behavior.
I would recommend typing-inspect to match the behavior of typing.get_origin, so get_origin(int | str) is types.UnionType and get_origin(Union[int, str]) is typing.Union.