mirror of https://github.com/python/cpython
gh-104935: typing: Fix interactions between `@runtime_checkable` and `Generic` (#104939)
--------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
77d7ec5aa9
commit
2b7027d0b2
|
@ -2472,6 +2472,48 @@ class ProtocolTests(BaseTestCase):
|
|||
self.assertNotIsSubclass(types.FunctionType, P)
|
||||
self.assertNotIsInstance(f, P)
|
||||
|
||||
def test_runtime_checkable_generic_non_protocol(self):
|
||||
# Make sure this doesn't raise AttributeError
|
||||
with self.assertRaisesRegex(
|
||||
TypeError,
|
||||
"@runtime_checkable can be only applied to protocol classes",
|
||||
):
|
||||
@runtime_checkable
|
||||
class Foo[T]: ...
|
||||
|
||||
def test_runtime_checkable_generic(self):
|
||||
@runtime_checkable
|
||||
class Foo[T](Protocol):
|
||||
def meth(self) -> T: ...
|
||||
|
||||
class Impl:
|
||||
def meth(self) -> int: ...
|
||||
|
||||
self.assertIsSubclass(Impl, Foo)
|
||||
|
||||
class NotImpl:
|
||||
def method(self) -> int: ...
|
||||
|
||||
self.assertNotIsSubclass(NotImpl, Foo)
|
||||
|
||||
def test_pep695_generics_can_be_runtime_checkable(self):
|
||||
@runtime_checkable
|
||||
class HasX(Protocol):
|
||||
x: int
|
||||
|
||||
class Bar[T]:
|
||||
x: T
|
||||
def __init__(self, x):
|
||||
self.x = x
|
||||
|
||||
class Capybara[T]:
|
||||
y: str
|
||||
def __init__(self, y):
|
||||
self.y = y
|
||||
|
||||
self.assertIsInstance(Bar(1), HasX)
|
||||
self.assertNotIsInstance(Capybara('a'), HasX)
|
||||
|
||||
def test_everything_implements_empty_protocol(self):
|
||||
@runtime_checkable
|
||||
class Empty(Protocol):
|
||||
|
|
|
@ -1894,7 +1894,7 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
|
|||
annotations = getattr(base, '__annotations__', {})
|
||||
if (isinstance(annotations, collections.abc.Mapping) and
|
||||
attr in annotations and
|
||||
issubclass(other, Generic) and other._is_protocol):
|
||||
issubclass(other, Generic) and getattr(other, '_is_protocol', False)):
|
||||
break
|
||||
else:
|
||||
return NotImplemented
|
||||
|
@ -1912,7 +1912,7 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
|
|||
if not (base in (object, Generic) or
|
||||
base.__module__ in _PROTO_ALLOWLIST and
|
||||
base.__name__ in _PROTO_ALLOWLIST[base.__module__] or
|
||||
issubclass(base, Generic) and base._is_protocol):
|
||||
issubclass(base, Generic) and getattr(base, '_is_protocol', False)):
|
||||
raise TypeError('Protocols can only inherit from other'
|
||||
' protocols, got %r' % base)
|
||||
if cls.__init__ is Protocol.__init__:
|
||||
|
@ -2059,7 +2059,7 @@ def runtime_checkable(cls):
|
|||
Warning: this will check only the presence of the required methods,
|
||||
not their type signatures!
|
||||
"""
|
||||
if not issubclass(cls, Generic) or not cls._is_protocol:
|
||||
if not issubclass(cls, Generic) or not getattr(cls, '_is_protocol', False):
|
||||
raise TypeError('@runtime_checkable can be only applied to protocol classes,'
|
||||
' got %r' % cls)
|
||||
cls._is_runtime_protocol = True
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Fix bugs with the interaction between :func:`typing.runtime_checkable` and
|
||||
:class:`typing.Generic` that were introduced by the :pep:`695`
|
||||
implementation. Patch by Jelle Zijlstra.
|
Loading…
Reference in New Issue