isinstance2 is an experimental module that provides a powerful runtime type checker for Python's built-in generic classes and
generic type hints. It allows you to perform runtime instance type checks on objects that are instances of a generic
class, as well as subclass checks on generic classes, even if you don't know the exact type of the generic parameters.
from isinstance2 import isinstance2, issubclass2
from typing import Iterable
assert isinstance2((1, 2.0, 'three'), tuple[int, float, str])
assert issubclass2(dict[str, int], dict[str, int | float])
assert issubclass2(list[int] | set[int] | tuple[int, ...], Iterable[int])- Perform runtime instance and subclass checks on generic classes
- Supports built-in generic classes such as
list,tuple,dict,set, andfrozenset, as well asOptionalandLiteral. - Check if an object is an instance of a
tuplewith variadic arguments. - Register custom class or function with
isinstance2's instance checker registry.
pip install isinstance2from typing import Iterable, Literal
from isinstance2 import isinstance2
# Basic instance checks
assert isinstance2([1, 2, 3], list[int])
assert isinstance2((1, 2.0, 'three'), tuple[int, float, str])
assert isinstance2({1, 2, 3}, set[int])
assert isinstance2({"foo": 1, "bar": 2}, dict[str, int])
assert isinstance2(frozenset([1, 2, 'Hi! 😊', 'literally amazing']), frozenset[int | Literal['Hi! 😊', 'literally amazing']])
# Ellipses in tuples work
assert isinstance2((1, 'two', 3.0, 'four'), tuple[int | float | str, ...])
# You can also check against abstract generic classes
assert isinstance2(range(10), Iterable[int])
assert not isinstance2(range(10), Iterable[float])from typing import Collection, Iterable
from isinstance2 import issubclass2
# Basic subclass checks
assert issubclass2(list[int], list[int | float])
assert issubclass2(tuple[int, float], tuple[int | float, ...])
# Classes without generic parameters are presumed to match
assert issubclass2(list, list[int])
assert issubclass2(list[int], list)
# Abstract generic classes
assert issubclass2(list[int], Iterable[int])
assert issubclass2(Collection[bool], Iterable[int]) # Yes, bool is a subclass of intTo check if an object is an instance of a custom generic class, register it with isinstance2's instance checker
from typing import Generic, TypeVar, Any
from isinstance2 import isinstance2, register_instance_checker
T = TypeVar('T')
class MyClass(Generic[T]):
...
@register_instance_checker
def is_instance_of_my_class(obj: Any) -> bool:
return isinstance(obj, MyClass)
assert isinstance2(MyClass(), MyClass)If you'd prefer not to add your checkers globally, you can use isinstance2's register instead and pass a custom registry (which is just a dict).
from typing import Generic, TypeVar
from isinstance2 import register, instance_checker_registry
from functools import partial
# Copy the default registry
my_registry = instance_checker_registry.copy()
# Make a custom registration function
my_register = partial(register, registry=my_registry)Now you can use my_register in place of register_instance_checker.
- Does not yet support
TypeVarContainer- And likely quite a few other generic classes that I've missed. Please open an issue if you find one.
- Subclass checks for custom classes (instance checks are supported)
- Subclass checks are, in general, unreliable.
- I haven't yet figured out how to deal with things like structural subtyping. For instance,
issubclass2(str, Iterator[int])currently returnsTruewhen it clearly shouldn't - Instance checks are somewhat simpler and shouldn't suffer as much from this problem.
- I haven't yet figured out how to deal with things like structural subtyping. For instance,
- Requires Python 3.11 or later
isinstance2 is released under the MIT License.