@@ -1698,7 +1698,7 @@ class NT(NamedTuple):
1698
1698
1699
1699
skip_if_py312b1 = skipIf (
1700
1700
sys .version_info == (3 , 12 , 0 , 'beta' , 1 ),
1701
- "CPython had a bug in 3.12.0b1"
1701
+ "CPython had bugs in 3.12.0b1"
1702
1702
)
1703
1703
1704
1704
@@ -1902,40 +1902,75 @@ def x(self): ...
1902
1902
self .assertIsSubclass (C , P )
1903
1903
self .assertIsSubclass (C , PG )
1904
1904
self .assertIsSubclass (BadP , PG )
1905
- with self .assertRaises (TypeError ):
1905
+
1906
+ no_subscripted_generics = (
1907
+ "Subscripted generics cannot be used with class and instance checks"
1908
+ )
1909
+
1910
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
1906
1911
issubclass (C , PG [T ])
1907
- with self .assertRaises (TypeError ):
1912
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
1908
1913
issubclass (C , PG [C ])
1909
- with self .assertRaises (TypeError ):
1914
+
1915
+ only_runtime_checkable_protocols = (
1916
+ "Instance and class checks can only be used with "
1917
+ "@runtime_checkable protocols"
1918
+ )
1919
+
1920
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_protocols ):
1910
1921
issubclass (C , BadP )
1911
- with self .assertRaises (TypeError ):
1922
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_protocols ):
1912
1923
issubclass (C , BadPG )
1913
- with self .assertRaises (TypeError ):
1924
+
1925
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
1914
1926
issubclass (P , PG [T ])
1915
- with self .assertRaises (TypeError ):
1927
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
1916
1928
issubclass (PG , PG [int ])
1917
1929
1930
+ only_classes_allowed = r"issubclass\(\) arg 1 must be a class"
1931
+
1932
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
1933
+ issubclass (1 , P )
1934
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
1935
+ issubclass (1 , PG )
1936
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
1937
+ issubclass (1 , BadP )
1938
+ with self .assertRaisesRegex (TypeError , only_classes_allowed ):
1939
+ issubclass (1 , BadPG )
1940
+
1918
1941
def test_protocols_issubclass_non_callable (self ):
1919
1942
class C :
1920
1943
x = 1
1944
+
1921
1945
@runtime_checkable
1922
1946
class PNonCall (Protocol ):
1923
1947
x = 1
1924
- with self .assertRaises (TypeError ):
1948
+
1949
+ non_callable_members_illegal = (
1950
+ "Protocols with non-method members don't support issubclass()"
1951
+ )
1952
+
1953
+ with self .assertRaisesRegex (TypeError , non_callable_members_illegal ):
1925
1954
issubclass (C , PNonCall )
1955
+
1926
1956
self .assertIsInstance (C (), PNonCall )
1927
1957
PNonCall .register (C )
1928
- with self .assertRaises (TypeError ):
1958
+
1959
+ with self .assertRaisesRegex (TypeError , non_callable_members_illegal ):
1929
1960
issubclass (C , PNonCall )
1961
+
1930
1962
self .assertIsInstance (C (), PNonCall )
1963
+
1931
1964
# check that non-protocol subclasses are not affected
1932
1965
class D (PNonCall ): ...
1966
+
1933
1967
self .assertNotIsSubclass (C , D )
1934
1968
self .assertNotIsInstance (C (), D )
1935
1969
D .register (C )
1936
1970
self .assertIsSubclass (C , D )
1937
1971
self .assertIsInstance (C (), D )
1938
- with self .assertRaises (TypeError ):
1972
+
1973
+ with self .assertRaisesRegex (TypeError , non_callable_members_illegal ):
1939
1974
issubclass (D , PNonCall )
1940
1975
1941
1976
def test_no_weird_caching_with_issubclass_after_isinstance (self ):
@@ -1954,7 +1989,10 @@ def __init__(self) -> None:
1954
1989
# as the cached result of the isinstance() check immediately above
1955
1990
# would mean the issubclass() call would short-circuit
1956
1991
# before we got to the "raise TypeError" line
1957
- with self .assertRaises (TypeError ):
1992
+ with self .assertRaisesRegex (
1993
+ TypeError ,
1994
+ "Protocols with non-method members don't support issubclass()"
1995
+ ):
1958
1996
issubclass (Eggs , Spam )
1959
1997
1960
1998
def test_no_weird_caching_with_issubclass_after_isinstance_2 (self ):
@@ -1971,7 +2009,10 @@ class Eggs: ...
1971
2009
# as the cached result of the isinstance() check immediately above
1972
2010
# would mean the issubclass() call would short-circuit
1973
2011
# before we got to the "raise TypeError" line
1974
- with self .assertRaises (TypeError ):
2012
+ with self .assertRaisesRegex (
2013
+ TypeError ,
2014
+ "Protocols with non-method members don't support issubclass()"
2015
+ ):
1975
2016
issubclass (Eggs , Spam )
1976
2017
1977
2018
def test_no_weird_caching_with_issubclass_after_isinstance_3 (self ):
@@ -1992,7 +2033,10 @@ def __getattr__(self, attr):
1992
2033
# as the cached result of the isinstance() check immediately above
1993
2034
# would mean the issubclass() call would short-circuit
1994
2035
# before we got to the "raise TypeError" line
1995
- with self .assertRaises (TypeError ):
2036
+ with self .assertRaisesRegex (
2037
+ TypeError ,
2038
+ "Protocols with non-method members don't support issubclass()"
2039
+ ):
1996
2040
issubclass (Eggs , Spam )
1997
2041
1998
2042
def test_protocols_isinstance (self ):
@@ -2028,13 +2072,24 @@ def __init__(self):
2028
2072
for proto in P , PG , WeirdProto , WeirdProto2 , WeirderProto :
2029
2073
with self .subTest (klass = klass .__name__ , proto = proto .__name__ ):
2030
2074
self .assertIsInstance (klass (), proto )
2031
- with self .assertRaises (TypeError ):
2075
+
2076
+ no_subscripted_generics = (
2077
+ "Subscripted generics cannot be used with class and instance checks"
2078
+ )
2079
+
2080
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2032
2081
isinstance (C (), PG [T ])
2033
- with self .assertRaises (TypeError ):
2082
+ with self .assertRaisesRegex (TypeError , no_subscripted_generics ):
2034
2083
isinstance (C (), PG [C ])
2035
- with self .assertRaises (TypeError ):
2084
+
2085
+ only_runtime_checkable_msg = (
2086
+ "Instance and class checks can only be used "
2087
+ "with @runtime_checkable protocols"
2088
+ )
2089
+
2090
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_msg ):
2036
2091
isinstance (C (), BadP )
2037
- with self .assertRaises (TypeError ):
2092
+ with self .assertRaisesRegex (TypeError , only_runtime_checkable_msg ):
2038
2093
isinstance (C (), BadPG )
2039
2094
2040
2095
def test_protocols_isinstance_properties_and_descriptors (self ):
@@ -2435,12 +2490,13 @@ def __subclasshook__(cls, other):
2435
2490
self .assertIsSubclass (OKClass , C )
2436
2491
self .assertNotIsSubclass (BadClass , C )
2437
2492
2493
+ @skip_if_py312b1
2438
2494
def test_issubclass_fails_correctly (self ):
2439
2495
@runtime_checkable
2440
2496
class P (Protocol ):
2441
2497
x = 1
2442
2498
class C : pass
2443
- with self .assertRaises (TypeError ):
2499
+ with self .assertRaisesRegex (TypeError , r"issubclass\(\) arg 1 must be a class" ):
2444
2500
issubclass (C (), P )
2445
2501
2446
2502
def test_defining_generic_protocols (self ):
@@ -2768,6 +2824,30 @@ def __call__(self, *args: Unpack[Ts]) -> T: ...
2768
2824
self .assertEqual (Y .__parameters__ , ())
2769
2825
self .assertEqual (Y .__args__ , (int , bytes , memoryview ))
2770
2826
2827
+ @skip_if_py312b1
2828
+ def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta (self ):
2829
+ # Ensure the cache is empty, or this test won't work correctly
2830
+ collections .abc .Sized ._abc_registry_clear ()
2831
+
2832
+ class Foo (collections .abc .Sized , Protocol ): pass
2833
+
2834
+ # CPython gh-105144: this previously raised TypeError
2835
+ # if a Protocol subclass of Sized had been created
2836
+ # before any isinstance() checks against Sized
2837
+ self .assertNotIsInstance (1 , collections .abc .Sized )
2838
+
2839
+ @skip_if_py312b1
2840
+ def test_interaction_with_isinstance_checks_on_superclasses_with_ABCMeta_2 (self ):
2841
+ # Ensure the cache is empty, or this test won't work correctly
2842
+ collections .abc .Sized ._abc_registry_clear ()
2843
+
2844
+ class Foo (typing .Sized , Protocol ): pass
2845
+
2846
+ # CPython gh-105144: this previously raised TypeError
2847
+ # if a Protocol subclass of Sized had been created
2848
+ # before any isinstance() checks against Sized
2849
+ self .assertNotIsInstance (1 , typing .Sized )
2850
+
2771
2851
2772
2852
class Point2DGeneric (Generic [T ], TypedDict ):
2773
2853
a : T
0 commit comments