typing_inspect icon indicating copy to clipboard operation
typing_inspect copied to clipboard

get_origin gives inconsistent results for differently defined Unions

Open bernt-matthias opened this issue 2 years ago • 3 comments

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...

bernt-matthias avatar Jun 08 '23 10:06 bernt-matthias

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.

ilevkivskyi avatar Jun 08 '23 23:06 ilevkivskyi

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 :)

bernt-matthias avatar Jun 09 '23 07:06 bernt-matthias

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.

JelleZijlstra avatar Jun 09 '23 14:06 JelleZijlstra