Search code examples
pythontype-hintingliteralspython-typingtyping

Determining if object is of typing.Literal type


I need to check if object is descendant of typing.Literal, I have annotation like this:

GameState: Literal['start', 'stop']

And I need to check GameState annotation type:

def parse_values(ann)
   if isinstance(ann, str):
       # do sth
   if isinstance(ann, int):
       # do sth
   if isinstance(ann, Literal):
       # do sth

But it causes error, so I swapped the last one to:

if type(ann) == Literal:
   # do sth

But it never returns True, so anyone knows a workaround for this?


Solution

  • typing.get_origin(tp) is the proper way

    It was implemented in Python 3.8 (Same as typing.Literal)

    The docstring is thoroughly instructive:

    def get_origin(tp):
        """Get the unsubscripted version of a type.
    
        This supports generic types, Callable, Tuple, Union, Literal, Final, ClassVar
        and Annotated. Return None for unsupported types. Examples::
    
            get_origin(Literal[42]) is Literal
            get_origin(int) is None
            get_origin(ClassVar[int]) is ClassVar
            get_origin(Generic) is Generic
            get_origin(Generic[T]) is Generic
            get_origin(Union[T, int]) is Union
            get_origin(List[Tuple[T, T]][int]) == list
        """
    

    In your use case it would be:

    from typing import Literal, get_origin
    
    def parse_values(ann):
        if isinstance(ann, str):
            return "str"
        elif isinstance(ann, int):
            return "int"
        elif get_origin(ann) is Literal:
            return "Literal"
    
    assert parse_values("foo") == "str"
    assert parse_values(5) == "int"
    assert parse_values(Literal["bar", 6]) == "Literal"