1

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.

Alex Waygood
  • 6,304
  • 3
  • 24
  • 46
Uri
  • 25,622
  • 10
  • 45
  • 72
  • what do you mean by composing functions? – yedpodtrzitko Sep 30 '21 at 22:16
  • https://en.wikipedia.org/wiki/Function_composition – Uri Sep 30 '21 at 22:16
  • What's the term for `List`, if `List[str]` is a "subscripted generic"? My wording "simple type annotation" could be improved. – mkrieger1 Sep 30 '21 at 22:26
  • 2
    Can you explain at what stage you need to know if two functions are composable? Like, the only use case I see for this is while you are still coding, but then your editor will tell you, or you notice when you try to run the code and the traceback will tell you, no? – mapf Sep 30 '21 at 22:27
  • this is a feature i'm implementing for `gamla.compose` function (https://github.com/hyroai/gamla) – Uri Sep 30 '21 at 22:29
  • Type checkers are doing some things that are not entirely equivalent to runtime types. Can you clarify what exactly you need supported? What about forward references, NewType, Callable, Protocol, Tuple arity, Type, Literal, TypeVar (with/without variance), TypedDict, overload signatures, and generally signature matching? – MisterMiyagi Oct 01 '21 at 11:09
  • The more the better, importance per their usage in the wild. – Uri Oct 01 '21 at 11:20

1 Answers1

-3

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)
Uri
  • 25,622
  • 10
  • 45
  • 72