pythonpython-3.xannotationstypecheckingunion-types

How to check a variable against Union type during runtime?


I'm trying to write a function decorator that uses Python 3.6's 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?


Solution

  • You could use the __args__ attribute of Union which holds a tuple of the "possible contents:

    >>> from typing import Union
    
    >>> x = Union[int, str]
    >>> x.__args__
    (int, str)
    >>> isinstance(3, x.__args__)
    True
    >>> isinstance('a', x.__args__)
    True
    

    The __args__ argument is not documented so it could be considered "messing with implementation details" but it seems like a better way than parsing the repr.