Skip to content

Commit

Permalink
bpo-44807: Allow Protocol classes to define __init__ (GH-31628)
Browse files Browse the repository at this point in the history
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
  • Loading branch information
adriangb and JelleZijlstra committed Apr 11, 2022
1 parent b0b836b commit 5f2abae
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 1 deletion.
26 changes: 26 additions & 0 deletions Lib/test/test_typing.py
Expand Up @@ -1598,6 +1598,32 @@ class CG(PG[T]): pass
with self.assertRaises(TypeError):
CG[int](42)

def test_protocol_defining_init_does_not_get_overridden(self):
# check that P.__init__ doesn't get clobbered
# see https://bugs.python.org/issue44807

class P(Protocol):
x: int
def __init__(self, x: int) -> None:
self.x = x
class C: pass

c = C()
P.__init__(c, 1)
self.assertEqual(c.x, 1)

def test_concrete_class_inheriting_init_from_protocol(self):
class P(Protocol):
x: int
def __init__(self, x: int) -> None:
self.x = x

class C(P): pass

c = C(1)
self.assertIsInstance(c, C)
self.assertEqual(c.x, 1)

def test_cannot_instantiate_abstract(self):
@runtime_checkable
class P(Protocol):
Expand Down
3 changes: 2 additions & 1 deletion Lib/typing.py
Expand Up @@ -1997,7 +1997,8 @@ def _proto_hook(other):
issubclass(base, Generic) and base._is_protocol):
raise TypeError('Protocols can only inherit from other'
' protocols, got %r' % base)
cls.__init__ = _no_init_or_replace_init
if cls.__init__ is Protocol.__init__:
cls.__init__ = _no_init_or_replace_init


class _AnnotatedAlias(_GenericAlias, _root=True):
Expand Down
@@ -0,0 +1 @@
:class:`typing.Protocol` no longer silently replaces :meth:`__init__` methods defined on subclasses. Patch by Adrian Garcia Badaracco.

0 comments on commit 5f2abae

Please sign in to comment.