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.
fromisinstance2importisinstance2, issubclass2fromtypingimportIterableassertisinstance2((1, 2.0, 'three'), tuple[int, float, str])
assertissubclass2(dict[str, int], dict[str, int|float])
assertissubclass2(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 isinstance2fromtypingimportIterable, Literalfromisinstance2importisinstance2# Basic instance checksassertisinstance2([1, 2, 3], list[int])
assertisinstance2((1, 2.0, 'three'), tuple[int, float, str])
assertisinstance2({1, 2, 3}, set[int])
assertisinstance2({"foo": 1, "bar": 2}, dict[str, int])
assertisinstance2(frozenset([1, 2, 'Hi! 😊', 'literally amazing']), frozenset[int|Literal['Hi! 😊', 'literally amazing']])
# Ellipses in tuples workassertisinstance2((1, 'two', 3.0, 'four'), tuple[int|float|str, ...])
# You can also check against abstract generic classesassertisinstance2(range(10), Iterable[int])
assertnotisinstance2(range(10), Iterable[float])fromtypingimportCollection, Iterablefromisinstance2importissubclass2# Basic subclass checksassertissubclass2(list[int], list[int|float])
assertissubclass2(tuple[int, float], tuple[int|float, ...])
# Classes without generic parameters are presumed to matchassertissubclass2(list, list[int])
assertissubclass2(list[int], list)
# Abstract generic classesassertissubclass2(list[int], Iterable[int])
assertissubclass2(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
fromtypingimportGeneric, TypeVar, Anyfromisinstance2importisinstance2, register_instance_checkerT=TypeVar('T')
classMyClass(Generic[T]):
...
@register_instance_checkerdefis_instance_of_my_class(obj: Any) ->bool:
returnisinstance(obj, MyClass)
assertisinstance2(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).
fromtypingimportGeneric, TypeVarfromisinstance2importregister, instance_checker_registryfromfunctoolsimportpartial# Copy the default registrymy_registry=instance_checker_registry.copy()
# Make a custom registration functionmy_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.