Package: isinstance2
isinstance2isinstance2is 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.tl;drfromisinstance2importisinstance2,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])FeaturesPerform runtime instance and subclass checks on generic classesSupports built-in generic classes such aslist,tuple,dict,set, andfrozenset, as well asOptionalandLiteral.Check if an object is an instance of atuplewith variadic arguments.Register custom class or function withisinstance2's instance checker registry.Installationpipinstallisinstance2Basic UsageInstance ChecksfromtypingimportIterable,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])Subclass ChecksfromtypingimportCollection,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 intAdvanced UsageTo check if an object is an instance of a custom generic class, register it withisinstance2's instance checkerfromtypingimportGeneric,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 useisinstance2'sregisterinstead and pass a custom registry (which is just adict).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 usemy_registerin place ofregister_instance_checker.LimitationsDoes not yet supportTypeVarContainerAnd 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'tInstance checks are somewhat simpler and shouldn't suffer as much from this problem.Requires Python 3.11 or laterLicenseisinstance2is released under theMIT License.