mirror of
https://github.com/python/cpython.git
synced 2025-08-08 02:48:55 +00:00
[3.12] gh-105144: Runtime-checkable protocols: move all 'sanity checks' to _ProtocolMeta.__subclasscheck__
(GH-105152) (#105160)
(cherry picked from commit c05c31db8c
)
Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
4f477c796c
commit
076f3cda14
3 changed files with 111 additions and 37 deletions
|
@ -1733,7 +1733,7 @@ def _caller(depth=1, default='__main__'):
|
|||
pass
|
||||
return None
|
||||
|
||||
def _allow_reckless_class_checks(depth=3):
|
||||
def _allow_reckless_class_checks(depth=2):
|
||||
"""Allow instance and class checks for special stdlib modules.
|
||||
|
||||
The abc and functools modules indiscriminately call isinstance() and
|
||||
|
@ -1788,14 +1788,22 @@ class _ProtocolMeta(ABCMeta):
|
|||
)
|
||||
|
||||
def __subclasscheck__(cls, other):
|
||||
if not isinstance(other, type):
|
||||
# Same error message as for issubclass(1, int).
|
||||
raise TypeError('issubclass() arg 1 must be a class')
|
||||
if (
|
||||
getattr(cls, '_is_protocol', False)
|
||||
and not cls.__callable_proto_members_only__
|
||||
and not _allow_reckless_class_checks(depth=2)
|
||||
and not _allow_reckless_class_checks()
|
||||
):
|
||||
raise TypeError(
|
||||
"Protocols with non-method members don't support issubclass()"
|
||||
)
|
||||
if not cls.__callable_proto_members_only__:
|
||||
raise TypeError(
|
||||
"Protocols with non-method members don't support issubclass()"
|
||||
)
|
||||
if not getattr(cls, '_is_runtime_protocol', False):
|
||||
raise TypeError(
|
||||
"Instance and class checks can only be used with "
|
||||
"@runtime_checkable protocols"
|
||||
)
|
||||
return super().__subclasscheck__(other)
|
||||
|
||||
def __instancecheck__(cls, instance):
|
||||
|
@ -1807,7 +1815,7 @@ class _ProtocolMeta(ABCMeta):
|
|||
|
||||
if (
|
||||
not getattr(cls, '_is_runtime_protocol', False) and
|
||||
not _allow_reckless_class_checks(depth=2)
|
||||
not _allow_reckless_class_checks()
|
||||
):
|
||||
raise TypeError("Instance and class checks can only be used with"
|
||||
" @runtime_checkable protocols")
|
||||
|
@ -1875,18 +1883,6 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
|
|||
if not cls.__dict__.get('_is_protocol', False):
|
||||
return NotImplemented
|
||||
|
||||
# First, perform various sanity checks.
|
||||
if not getattr(cls, '_is_runtime_protocol', False):
|
||||
if _allow_reckless_class_checks():
|
||||
return NotImplemented
|
||||
raise TypeError("Instance and class checks can only be used with"
|
||||
" @runtime_checkable protocols")
|
||||
|
||||
if not isinstance(other, type):
|
||||
# Same error message as for issubclass(1, int).
|
||||
raise TypeError('issubclass() arg 1 must be a class')
|
||||
|
||||
# Second, perform the actual structural compatibility check.
|
||||
for attr in cls.__protocol_attrs__:
|
||||
for base in other.__mro__:
|
||||
# Check if the members appears in the class dictionary...
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue