@@ -562,7 +562,7 @@ def matches_type(
562
562
def is_instance (
563
563
cls ,
564
564
obj : object ,
565
- candidates : ty .Union [ty .Type [ty .Any ], ty .Iterable [ty .Type [ty .Any ]]],
565
+ candidates : ty .Union [ty .Type [ty .Any ], ty .Sequence [ty .Type [ty .Any ]]],
566
566
) -> bool :
567
567
"""Checks whether the object is an instance of cls or that cls is typing.Any,
568
568
extending the built-in isinstance to check nested type args
@@ -574,7 +574,7 @@ def is_instance(
574
574
candidates : type or ty.Iterable[type]
575
575
the candidate types to check the object against
576
576
"""
577
- if not isinstance (candidates , ( tuple , list ) ):
577
+ if not isinstance (candidates , ty . Sequence ):
578
578
candidates = [candidates ]
579
579
for candidate in candidates :
580
580
if candidate is ty .Any :
@@ -600,7 +600,7 @@ def is_instance(
600
600
def is_subclass (
601
601
cls ,
602
602
klass : ty .Type [ty .Any ],
603
- candidates : ty .Union [ty .Type [ty .Any ], ty .Iterable [ty .Type [ty .Any ]]],
603
+ candidates : ty .Union [ty .Type [ty .Any ], ty .Sequence [ty .Type [ty .Any ]]],
604
604
any_ok : bool = False ,
605
605
) -> bool :
606
606
"""Checks whether the class a is either the same as b, a subclass of b or b is
@@ -617,16 +617,23 @@ def is_subclass(
617
617
"""
618
618
if not isinstance (candidates , ty .Sequence ):
619
619
candidates = [candidates ]
620
+ if ty .Any in candidates :
621
+ return True
622
+ if klass is ty .Any :
623
+ return any_ok
624
+
625
+ origin = get_origin (klass )
626
+ args = get_args (klass )
620
627
621
628
for candidate in candidates :
629
+ candidate_origin = get_origin (candidate )
630
+ candidate_args = get_args (candidate )
622
631
# Handle ty.Type[*] types in klass and candidates
623
- if ty .get_origin (klass ) is type and (
624
- candidate is type or ty .get_origin (candidate ) is type
625
- ):
632
+ if origin is type and (candidate is type or candidate_origin is type ):
626
633
if candidate is type :
627
634
return True
628
- return cls .is_subclass (ty . get_args ( klass ) [0 ], ty . get_args ( candidate ) [0 ])
629
- elif ty . get_origin ( klass ) is type or ty . get_origin ( candidate ) is type :
635
+ return cls .is_subclass (args [0 ], candidate_args [0 ])
636
+ elif origin is type or candidate_origin is type :
630
637
return False
631
638
if NO_GENERIC_ISSUBCLASS :
632
639
if klass is type and candidate is not type :
@@ -636,27 +643,29 @@ def is_subclass(
636
643
):
637
644
return True
638
645
else :
639
- if klass is ty .Any :
640
- if ty .Any in candidates : # type: ignore
641
- return True
642
- else :
643
- return any_ok
644
- origin = get_origin (klass )
645
646
if origin is ty .Union :
646
- args = get_args (klass )
647
- if get_origin (candidate ) is ty .Union :
648
- candidate_args = get_args (candidate )
649
- else :
650
- candidate_args = [candidate ]
651
- return all (
652
- any (cls .is_subclass (a , c ) for c in candidate_args ) for a in args
647
+ union_args = (
648
+ candidate_args if candidate_origin is ty .Union else (candidate ,)
653
649
)
654
- if origin is not None :
655
- klass = origin
656
- if klass is candidate or candidate is ty .Any :
657
- return True
658
- if issubclass (klass , candidate ):
659
- return True
650
+ matches = all (
651
+ any (cls .is_subclass (a , c ) for c in union_args ) for a in args
652
+ )
653
+ if matches :
654
+ return True
655
+ else :
656
+ if candidate_args and candidate_origin is not ty .Union :
657
+ if (
658
+ origin
659
+ and issubclass (origin , candidate_origin ) # type: ignore[arg-type]
660
+ and len (args ) == len (candidate_args )
661
+ and all (
662
+ issubclass (a , c ) for a , c in zip (args , candidate_args )
663
+ )
664
+ ):
665
+ return True
666
+ else :
667
+ if issubclass (origin if origin else klass , candidate ):
668
+ return True
660
669
return False
661
670
662
671
@classmethod
0 commit comments