pythonmypypython-typingpytype

Compare two type annotations (possibly generics) to see if they fit


I'm looking for a function that can say if a type annotation is a subset of another.

It could be in the standard library or 3rd-party. Since type-checkers such as mypy and pytype have solved this problem, I assume there is some function that can do this, but couldn't find it.

e.g. a function f such that:

from typing import *

f(Sequence, List) # True
f(Sequence[str], List) # False
f(Iterable[str], List[str]) # True
f(List[str], Iterable[str]) # False
f(str, str) # True
f(int, str) # False

issubclass works for actual types and simple type annotations,

issubclass(str, str) # True
issubclass(int, str) # False
issubclass(list, Sequence) # True
issubclass(Iterable, Sequence) # False
issubclass(Sequence, Iterable) # True

but not for generics:

issubclass(List[str], Iterable[str])

TypeError: Subscripted generics cannot be used with class and instance checks

The high-level goal is be able to, given two functions, determine if they can be composed.


Solution

  • Ended up implementing this myself for the common use cases (Optional, Union, Callable, Tuple and simple types all work).

    pip install gamla

    then usage is:

    import gamla
    
    
    def test_is_subtype():
        for x, y in [
            [FrozenSet[str], FrozenSet[str]],
            [str, Any],
            [Tuple[str, ...], Tuple[str, ...]],
            [Set[str], Collection[str]],
            [List, Sequence],
            [Union[int, str], Union[int, str]],
            [str, Union[int, str]],
            [Union[List, Set], Collection],
        ]:
            assert gamla.is_subtype(x, y)
    
    
    def test_not_is_subtype():
        for x, y in [
            [FrozenSet[int], FrozenSet[str]],
            [str, FrozenSet[str]],
            [Collection, FrozenSet],
            [Tuple[str, ...], Tuple[int, ...]],
            [Union[int, str], int],
            [Any, str],
            [List, Union[int, str]],
            [Union[int, str, List], Union[int, str]],
        ]:
            assert not gamla.is_subtype(x, y)