Yeah, it’s this. We don’t support isinstance or issubclass on string-literal forward references either:
ForwardRefType = "int | str"
isinstance(0, ForwardRefType) # TypeError: isinstance() arg 2 must be a type, a tuple of types, or a union
issubclass(int, ForwardRefType) # TypeError: issubclass() arg 2 must be a class, a tuple of classes, or a union
We could probably use TypeAliasType.__value__. I’d imagine this would have the following effects:
A small runtime cost on non-alias, exception-raising isinstance and issubclass calls (since we’d have to check for TypeAliasType if the initial check fails).
The potential to make isinstance and issubclass expensive if the second argument is indeed a TypeAliasType.
Neither’s immediately fatal, I’d imagine, but they’re worth considering.
from typing import TypeAlias
Foo: TypeAlias = int | str
isinstance(1, Foo) # Works
Bar: TypeAlias = int | list[str]
isinstance(["a"], Bar) # TypeError: isinstance() argument 2 cannot be a parameterized generic
I don’t think TypeAliasType should support this as long as it can go from “working” to “not working” because someone added another member to the union.
This is a case where I wish the original beahvior hadn’t happened. isinstance shouldn’t have supported typing unions to begin with, exactly because isinstance isn’t for typing, but for runtime, and there’s edges where it won’t work. It became an additional way to do something you already could, while implying that it’s desirable to use it that way in general (it isn’t)