1
1
import contextlib
2
2
import collections
3
+ import collections .abc
3
4
from collections import defaultdict
4
5
from functools import lru_cache , wraps
5
6
import inspect
@@ -2722,19 +2723,41 @@ def x(self): ...
2722
2723
self .assertIsSubclass (C , PG )
2723
2724
self .assertIsSubclass (BadP , PG )
2724
2725
2725
- with self .assertRaises (TypeError ):
2726
+ no_subscripted_generics = (
2727
+ "Subscripted generics cannot be used with class and instance checks"
2728
+ )
2729
+
2730
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2726
2731
issubclass (C , PG [T ])
2727
- with self .assertRaises (TypeError ):
2732
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2728
2733
issubclass (C , PG [C ])
2729
- with self .assertRaises (TypeError ):
2734
+
2735
+ only_runtime_checkable_protocols = (
2736
+ "Instance and class checks can only be used with "
2737
+ "@runtime_checkable protocols"
2738
+ )
2739
+
2740
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_protocols ):
2730
2741
issubclass (C , BadP )
2731
- with self .assertRaises (TypeError ):
2742
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_protocols ):
2732
2743
issubclass (C , BadPG )
2733
- with self .assertRaises (TypeError ):
2744
+
2745
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2734
2746
issubclass (P , PG [T ])
2735
- with self .assertRaises (TypeError ):
2747
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2736
2748
issubclass (PG , PG [int ])
2737
2749
2750
+ only_classes_allowed = r"issubclass\(\) arg 1 must be a class"
2751
+
2752
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
2753
+ issubclass (1 , P )
2754
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
2755
+ issubclass (1 , PG )
2756
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
2757
+ issubclass (1 , BadP )
2758
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
2759
+ issubclass (1 , BadPG )
2760
+
2738
2761
def test_protocols_issubclass_non_callable (self ):
2739
2762
class C :
2740
2763
x = 1
@@ -2743,12 +2766,19 @@ class C:
2743
2766
class PNonCall (Protocol ):
2744
2767
x = 1
2745
2768
2746
- with self .assertRaises (TypeError ):
2769
+ non_callable_members_illegal = (
2770
+ "Protocols with non-method members don't support issubclass()"
2771
+ )
2772
+
2773
+ with self .assertRaisesRegex (TypeError , non_callable_members_illegal ):
2747
2774
issubclass (C , PNonCall )
2775
+
2748
2776
self .assertIsInstance (C (), PNonCall )
2749
2777
PNonCall .register (C )
2750
- with self .assertRaises (TypeError ):
2778
+
2779
+ with self .assertRaisesRegex (TypeError , non_callable_members_illegal ):
2751
2780
issubclass (C , PNonCall )
2781
+
2752
2782
self .assertIsInstance (C (), PNonCall )
2753
2783
2754
2784
# check that non-protocol subclasses are not affected
@@ -2759,7 +2789,8 @@ class D(PNonCall): ...
2759
2789
D .register (C )
2760
2790
self .assertIsSubclass (C , D )
2761
2791
self .assertIsInstance (C (), D )
2762
- with self .assertRaises (TypeError ):
2792
+
2793
+ with self .assertRaisesRegex (TypeError , non_callable_members_illegal ):
2763
2794
issubclass (D , PNonCall )
2764
2795
2765
2796
def test_no_weird_caching_with_issubclass_after_isinstance (self ):
@@ -2778,7 +2809,10 @@ def __init__(self) -> None:
2778
2809
# as the cached result of the isinstance() check immediately above
2779
2810
# would mean the issubclass() call would short-circuit
2780
2811
# before we got to the "raise TypeError" line
2781
- with self .assertRaises (TypeError ):
2812
+ with self .assertRaisesRegex (
2813
+ TypeError ,
2814
+ "Protocols with non-method members don't support issubclass()"
2815
+ ):
2782
2816
issubclass (Eggs , Spam )
2783
2817
2784
2818
def test_no_weird_caching_with_issubclass_after_isinstance_2 (self ):
@@ -2795,7 +2829,10 @@ class Eggs: ...
2795
2829
# as the cached result of the isinstance() check immediately above
2796
2830
# would mean the issubclass() call would short-circuit
2797
2831
# before we got to the "raise TypeError" line
2798
- with self .assertRaises (TypeError ):
2832
+ with self .assertRaisesRegex (
2833
+ TypeError ,
2834
+ "Protocols with non-method members don't support issubclass()"
2835
+ ):
2799
2836
issubclass (Eggs , Spam )
2800
2837
2801
2838
def test_no_weird_caching_with_issubclass_after_isinstance_3 (self ):
@@ -2816,7 +2853,10 @@ def __getattr__(self, attr):
2816
2853
# as the cached result of the isinstance() check immediately above
2817
2854
# would mean the issubclass() call would short-circuit
2818
2855
# before we got to the "raise TypeError" line
2819
- with self .assertRaises (TypeError ):
2856
+ with self .assertRaisesRegex (
2857
+ TypeError ,
2858
+ "Protocols with non-method members don't support issubclass()"
2859
+ ):
2820
2860
issubclass (Eggs , Spam )
2821
2861
2822
2862
def test_no_weird_caching_with_issubclass_after_isinstance_pep695 (self ):
@@ -2835,7 +2875,10 @@ def __init__(self, x: T) -> None:
2835
2875
# as the cached result of the isinstance() check immediately above
2836
2876
# would mean the issubclass() call would short-circuit
2837
2877
# before we got to the "raise TypeError" line
2838
- with self .assertRaises (TypeError ):
2878
+ with self .assertRaisesRegex (
2879
+ TypeError ,
2880
+ "Protocols with non-method members don't support issubclass()"
2881
+ ):
2839
2882
issubclass (Eggs , Spam )
2840
2883
2841
2884
def test_protocols_isinstance (self ):
@@ -2883,13 +2926,21 @@ def __init__(self):
2883
2926
with self .subTest (klass = klass .__name__ , proto = proto .__name__ ):
2884
2927
self .assertIsInstance (klass (), proto )
2885
2928
2886
- with self .assertRaises (TypeError ):
2929
+ no_subscripted_generics = "Subscripted generics cannot be used with class and instance checks"
2930
+
2931
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2887
2932
isinstance (C (), PG [T ])
2888
- with self .assertRaises (TypeError ):
2933
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2889
2934
isinstance (C (), PG [C ])
2890
- with self .assertRaises (TypeError ):
2935
+
2936
+ only_runtime_checkable_msg = (
2937
+ "Instance and class checks can only be used "
2938
+ "with @runtime_checkable protocols"
2939
+ )
2940
+
2941
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_msg ):
2891
2942
isinstance (C (), BadP )
2892
- with self .assertRaises (TypeError ):
2943
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_msg ):
2893
2944
isinstance (C (), BadPG )
2894
2945
2895
2946
def test_protocols_isinstance_properties_and_descriptors (self ):
@@ -3274,7 +3325,7 @@ class P(Protocol):
3274
3325
3275
3326
class C : pass
3276
3327
3277
- with self .assertRaises (TypeError ):
3328
+ with self .assertRaisesRegex (TypeError , r"issubclass\(\) arg 1 must be a class" ):
3278
3329
issubclass (C (), P )
3279
3330
3280
3331
def test_defining_generic_protocols (self ):
@@ -3654,6 +3705,28 @@ def __init__(self):
3654
3705
3655
3706
Foo () # Previously triggered RecursionError
3656
3707
3708
+ def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta (self ):
3709
+ # Ensure the cache is empty, or this test won't work correctly
3710
+ collections .abc .Sized ._abc_registry_clear ()
3711
+
3712
+ class Foo (collections .abc .Sized , Protocol ): pass
3713
+
3714
+ # gh-105144: this previously raised TypeError
3715
+ # if a Protocol subclass of Sized had been created
3716
+ # before any isinstance() checks against Sized
3717
+ self .assertNotIsInstance (1 , collections .abc .Sized )
3718
+
3719
+ def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta_2 (self ):
3720
+ # Ensure the cache is empty, or this test won't work correctly
3721
+ collections .abc .Sized ._abc_registry_clear ()
3722
+
3723
+ class Foo (typing .Sized , Protocol ): pass
3724
+
3725
+ # gh-105144: this previously raised TypeError
3726
+ # if a Protocol subclass of Sized had been created
3727
+ # before any isinstance() checks against Sized
3728
+ self .assertNotIsInstance (1 , typing .Sized )
3729
+
3657
3730
3658
3731
class GenericTests (BaseTestCase ):
3659
3732
0 commit comments