_TYPING_INTERNALS = frozenset({
'__parameters__', '__orig_bases__', '__orig_class__',
- '_is_protocol', '_is_runtime_protocol'
+ '_is_protocol', '_is_runtime_protocol', '__protocol_attrs__',
+ '__callable_proto_members_only__',
})
_SPECIAL_NAMES = frozenset({
return attrs
-def _is_callable_members_only(cls, protocol_attrs):
- # PEP 544 prohibits using issubclass() with protocols that have non-method members.
- return all(callable(getattr(cls, attr, None)) for attr in protocol_attrs)
-
-
def _no_init_or_replace_init(self, *args, **kwargs):
cls = type(self)
class _ProtocolMeta(ABCMeta):
# This metaclass is really unfortunate and exists only because of
# the lack of __instancehook__.
+ def __init__(cls, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ cls.__protocol_attrs__ = _get_protocol_attrs(cls)
+ # PEP 544 prohibits using issubclass()
+ # with protocols that have non-method members.
+ cls.__callable_proto_members_only__ = all(
+ callable(getattr(cls, attr, None)) for attr in cls.__protocol_attrs__
+ )
+
def __instancecheck__(cls, instance):
# We need this method for situations where attributes are
# assigned in __init__.
if is_protocol_cls:
getattr_static = _lazy_load_getattr_static()
- for attr in _get_protocol_attrs(cls):
+ for attr in cls.__protocol_attrs__:
try:
val = getattr_static(instance, attr)
except AttributeError:
raise TypeError("Instance and class checks can only be used with"
" @runtime_checkable protocols")
- protocol_attrs = _get_protocol_attrs(cls)
-
- if not _is_callable_members_only(cls, protocol_attrs):
+ if not cls.__callable_proto_members_only__ :
if _allow_reckless_class_checks():
return NotImplemented
raise TypeError("Protocols with non-method members"
raise TypeError('issubclass() arg 1 must be a class')
# Second, perform the actual structural compatibility check.
- for attr in protocol_attrs:
+ for attr in cls.__protocol_attrs__:
for base in other.__mro__:
# Check if the members appears in the class dictionary...
if attr in base.__dict__: