@@ -1818,14 +1818,17 @@ def __init__(cls, *args, **kwargs):
18181818 def __subclasscheck__ (cls , other ):
18191819 if cls is Protocol :
18201820 return type .__subclasscheck__ (cls , other )
1821- if not isinstance (other , type ):
1822- # Same error message as for issubclass(1, int).
1823- raise TypeError ('issubclass() arg 1 must be a class' )
18241821 if (
18251822 getattr (cls , '_is_protocol' , False )
18261823 and not _allow_reckless_class_checks ()
18271824 ):
1828- if not cls .__callable_proto_members_only__ :
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+ if (
1829+ not cls .__callable_proto_members_only__
1830+ and cls .__dict__ .get ("__subclasshook__" ) is _proto_hook
1831+ ):
18291832 raise TypeError (
18301833 "Protocols with non-method members don't support issubclass()"
18311834 )
@@ -1869,6 +1872,30 @@ def __instancecheck__(cls, instance):
18691872 return False
18701873
18711874
1875+ @classmethod
1876+ def _proto_hook (cls , other ):
1877+ if not cls .__dict__ .get ('_is_protocol' , False ):
1878+ return NotImplemented
1879+
1880+ for attr in cls .__protocol_attrs__ :
1881+ for base in other .__mro__ :
1882+ # Check if the members appears in the class dictionary...
1883+ if attr in base .__dict__ :
1884+ if base .__dict__ [attr ] is None :
1885+ return NotImplemented
1886+ break
1887+
1888+ # ...or in annotations, if it is a sub-protocol.
1889+ annotations = getattr (base , '__annotations__' , {})
1890+ if (isinstance (annotations , collections .abc .Mapping ) and
1891+ attr in annotations and
1892+ issubclass (other , Generic ) and getattr (other , '_is_protocol' , False )):
1893+ break
1894+ else :
1895+ return NotImplemented
1896+ return True
1897+
1898+
18721899class Protocol (Generic , metaclass = _ProtocolMeta ):
18731900 """Base class for protocol classes.
18741901
@@ -1914,37 +1941,11 @@ def __init_subclass__(cls, *args, **kwargs):
19141941 cls ._is_protocol = any (b is Protocol for b in cls .__bases__ )
19151942
19161943 # Set (or override) the protocol subclass hook.
1917- def _proto_hook (other ):
1918- if not cls .__dict__ .get ('_is_protocol' , False ):
1919- return NotImplemented
1920-
1921- for attr in cls .__protocol_attrs__ :
1922- for base in other .__mro__ :
1923- # Check if the members appears in the class dictionary...
1924- if attr in base .__dict__ :
1925- if base .__dict__ [attr ] is None :
1926- return NotImplemented
1927- break
1928-
1929- # ...or in annotations, if it is a sub-protocol.
1930- annotations = getattr (base , '__annotations__' , {})
1931- if (isinstance (annotations , collections .abc .Mapping ) and
1932- attr in annotations and
1933- issubclass (other , Generic ) and getattr (other , '_is_protocol' , False )):
1934- break
1935- else :
1936- return NotImplemented
1937- return True
1938-
19391944 if '__subclasshook__' not in cls .__dict__ :
19401945 cls .__subclasshook__ = _proto_hook
19411946
1942- # We have nothing more to do for non-protocols...
1943- if not cls ._is_protocol :
1944- return
1945-
1946- # ... otherwise prohibit instantiation.
1947- if cls .__init__ is Protocol .__init__ :
1947+ # Prohibit instantiation for protocol classes
1948+ if cls ._is_protocol and cls .__init__ is Protocol .__init__ :
19481949 cls .__init__ = _no_init_or_replace_init
19491950
19501951
0 commit comments