gh-105974: Revert unintentional behaviour change for protocols with non-callable members and custom __subclasshook__ methods (#105976)

This commit is contained in:
Alex Waygood 2023-06-23 15:59:25 +01:00 committed by GitHub
parent 968435ddb1
commit 9499b0f138
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 32 deletions

View file

@ -3477,6 +3477,46 @@ class ProtocolTests(BaseTestCase):
self.assertIsSubclass(OKClass, C)
self.assertNotIsSubclass(BadClass, C)
def test_custom_subclasshook_2(self):
@runtime_checkable
class HasX(Protocol):
# The presence of a non-callable member
# would mean issubclass() checks would fail with TypeError
# if it weren't for the custom `__subclasshook__` method
x = 1
@classmethod
def __subclasshook__(cls, other):
return hasattr(other, 'x')
class Empty: pass
class ImplementsHasX:
x = 1
self.assertIsInstance(ImplementsHasX(), HasX)
self.assertNotIsInstance(Empty(), HasX)
self.assertIsSubclass(ImplementsHasX, HasX)
self.assertNotIsSubclass(Empty, HasX)
# isinstance() and issubclass() checks against this still raise TypeError,
# despite the presence of the custom __subclasshook__ method,
# as it's not decorated with @runtime_checkable
class NotRuntimeCheckable(Protocol):
@classmethod
def __subclasshook__(cls, other):
return hasattr(other, 'x')
must_be_runtime_checkable = (
"Instance and class checks can only be used "
"with @runtime_checkable protocols"
)
with self.assertRaisesRegex(TypeError, must_be_runtime_checkable):
issubclass(object, NotRuntimeCheckable)
with self.assertRaisesRegex(TypeError, must_be_runtime_checkable):
isinstance(object(), NotRuntimeCheckable)
def test_issubclass_fails_correctly(self):
@runtime_checkable
class P(Protocol):