@@ -1822,14 +1822,17 @@ def __init__(cls, *args, **kwargs):
1822
1822
def __subclasscheck__ (cls , other ):
1823
1823
if cls is Protocol :
1824
1824
return type .__subclasscheck__ (cls , other )
1825
- if not isinstance (other , type ):
1826
- # Same error message as for issubclass(1, int).
1827
- raise TypeError ('issubclass() arg 1 must be a class' )
1828
1825
if (
1829
1826
getattr (cls , '_is_protocol' , False )
1830
1827
and not _allow_reckless_class_checks ()
1831
1828
):
1832
- if not cls .__callable_proto_members_only__ :
1829
+ if not isinstance (other , type ):
1830
+ # Same error message as for issubclass(1, int).
1831
+ raise TypeError ('issubclass() arg 1 must be a class' )
1832
+ if (
1833
+ not cls .__callable_proto_members_only__
1834
+ and cls .__dict__ .get ("__subclasshook__" ) is _proto_hook
1835
+ ):
1833
1836
raise TypeError (
1834
1837
"Protocols with non-method members don't support issubclass()"
1835
1838
)
@@ -1873,6 +1876,30 @@ def __instancecheck__(cls, instance):
1873
1876
return False
1874
1877
1875
1878
1879
+ @classmethod
1880
+ def _proto_hook (cls , other ):
1881
+ if not cls .__dict__ .get ('_is_protocol' , False ):
1882
+ return NotImplemented
1883
+
1884
+ for attr in cls .__protocol_attrs__ :
1885
+ for base in other .__mro__ :
1886
+ # Check if the members appears in the class dictionary...
1887
+ if attr in base .__dict__ :
1888
+ if base .__dict__ [attr ] is None :
1889
+ return NotImplemented
1890
+ break
1891
+
1892
+ # ...or in annotations, if it is a sub-protocol.
1893
+ annotations = getattr (base , '__annotations__' , {})
1894
+ if (isinstance (annotations , collections .abc .Mapping ) and
1895
+ attr in annotations and
1896
+ issubclass (other , Generic ) and getattr (other , '_is_protocol' , False )):
1897
+ break
1898
+ else :
1899
+ return NotImplemented
1900
+ return True
1901
+
1902
+
1876
1903
class Protocol (Generic , metaclass = _ProtocolMeta ):
1877
1904
"""Base class for protocol classes.
1878
1905
@@ -1918,37 +1945,11 @@ def __init_subclass__(cls, *args, **kwargs):
1918
1945
cls ._is_protocol = any (b is Protocol for b in cls .__bases__ )
1919
1946
1920
1947
# Set (or override) the protocol subclass hook.
1921
- def _proto_hook (other ):
1922
- if not cls .__dict__ .get ('_is_protocol' , False ):
1923
- return NotImplemented
1924
-
1925
- for attr in cls .__protocol_attrs__ :
1926
- for base in other .__mro__ :
1927
- # Check if the members appears in the class dictionary...
1928
- if attr in base .__dict__ :
1929
- if base .__dict__ [attr ] is None :
1930
- return NotImplemented
1931
- break
1932
-
1933
- # ...or in annotations, if it is a sub-protocol.
1934
- annotations = getattr (base , '__annotations__' , {})
1935
- if (isinstance (annotations , collections .abc .Mapping ) and
1936
- attr in annotations and
1937
- issubclass (other , Generic ) and getattr (other , '_is_protocol' , False )):
1938
- break
1939
- else :
1940
- return NotImplemented
1941
- return True
1942
-
1943
1948
if '__subclasshook__' not in cls .__dict__ :
1944
1949
cls .__subclasshook__ = _proto_hook
1945
1950
1946
- # We have nothing more to do for non-protocols...
1947
- if not cls ._is_protocol :
1948
- return
1949
-
1950
- # ... otherwise prohibit instantiation.
1951
- if cls .__init__ is Protocol .__init__ :
1951
+ # Prohibit instantiation for protocol classes
1952
+ if cls ._is_protocol and cls .__init__ is Protocol .__init__ :
1952
1953
cls .__init__ = _no_init_or_replace_init
1953
1954
1954
1955
0 commit comments