Determining if object is of typing.Literal type

Question:

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?

Asked By: Moder New

||

Answers:

you should compare with <class 'typing._LiteralGenericAlias'> instead:

from typing import _LiteralGenericAlias
if type(GameState) == _LiteralGenericAlias:
     #do something
Answered By: XxJames07-

typing.get_origin() returns Literal for Literal descendandts, so what I needed is basicly

if get_origin(GameState) == Literal:
    # do sth
Answered By: Moder New

typing.getOrigin(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"
Answered By: Mandera