typing.get_type_hints
function for this use case, see https://docs.python.org/3.9/library/typing.html#typing.get_type_hintsI'm trying to write a function decorator that uses Python 3.6 type hints to check that a dictionary of arguments respects the type hints and if not raise an error with a clear description of the problem, to be used for HTTP APIs.
The problem is that when the function has a parameter using the Union
type I can't check a variable against it at runtime.
For example, I have this function
from typing import Union
def bark(myname: str, descr: Union[int, str], mynum: int = 3) -> str:
return descr + myname * mynum
I can do:
isinstance('Arnold', bark.__annotations__['myname'])
But not:
isinstance(3, bark.__annotations__['descr'])
Because Union
cannot be used with isinstance
or issubclass
.
I couldn't find a way to check it using the type object.
I tried to implement the check by myself but while bark.__annotations__['descr']
is shown as typing.Union[int, str]
in the REPL I can't access the list of the types at runtime, if not using the ugly hack of examining bark.__annotations__['descr'].__repr__()
.
Is there a proper way to access this information? Or is it deliberately intended to not be easily accessible at runtime?
The existing accepted answer by MSeifert (https://stackoverflow.com/a/45959000/7433423) does not distinguish Union
s from other generic types, and it is difficult to determine at runtime whether a type annotation is a Union
or some other generic type like Mapping
due to the behavior of isinstance()
and issubclass()
on parameterized Union
types.
It appears that generic types will have an undocumented __origin__
attribute which will contain a reference to the original generic type used to create it. Once you have confirmed that the type annotation is a parameterized Union
, you can then use the also undocumented __args__
attribute to get the type parameters.
>>> from typing import Union
>>> type_anno = Union[int, str]
>>> type_anno.__origin__ is Union
True
>>> isinstance(3, type_anno.__args__)
True
>>> isinstance('a', type_anno.__args__)
True