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

gh-105974: Revert unintentional behaviour change for protocols with non-callable members and custom `__subclasshook__` methods (GH-105976)
(cherry picked from commit 9499b0f138)

Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
Miss Islington (bot) 2023-06-23 08:26:37 -07:00 committed by GitHub
parent 1ffcd49be2
commit 7d6ee298e9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 79 additions and 32 deletions

View file

@ -3465,6 +3465,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):