summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdrian Garcia Badaracco <1755071+adriangb@users.noreply.github.com>2022-04-11 14:51:25 (GMT)
committerGitHub <noreply@github.com>2022-04-11 14:51:25 (GMT)
commit5f2abae61ec69264b835dcabe2cdabe57b9a990e (patch)
tree4c58c52c703a1f52e97ec402d8274620ee2a2352
parentb0b836b20cb56c225874a4a39ef895f89ab2970f (diff)
downloadcpython-5f2abae61ec69264b835dcabe2cdabe57b9a990e.zip
cpython-5f2abae61ec69264b835dcabe2cdabe57b9a990e.tar.gz
cpython-5f2abae61ec69264b835dcabe2cdabe57b9a990e.tar.bz2
bpo-44807: Allow Protocol classes to define __init__ (GH-31628)
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
-rw-r--r--Lib/test/test_typing.py26
-rw-r--r--Lib/typing.py3
-rw-r--r--Misc/NEWS.d/next/Library/2022-03-02-04-25-58.bpo-44807.gHNC9J.rst1
3 files changed, 29 insertions, 1 deletions
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index e09f8aa..b884f7b 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -1598,6 +1598,32 @@ class ProtocolTests(BaseTestCase):
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):
diff --git a/Lib/typing.py b/Lib/typing.py
index 26c6b8c..ec8cbbd 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1997,7 +1997,8 @@ class Protocol(Generic, metaclass=_ProtocolMeta):
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):
diff --git a/Misc/NEWS.d/next/Library/2022-03-02-04-25-58.bpo-44807.gHNC9J.rst b/Misc/NEWS.d/next/Library/2022-03-02-04-25-58.bpo-44807.gHNC9J.rst
new file mode 100644
index 0000000..4757d34
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-03-02-04-25-58.bpo-44807.gHNC9J.rst
@@ -0,0 +1 @@
+:class:`typing.Protocol` no longer silently replaces :meth:`__init__` methods defined on subclasses. Patch by Adrian Garcia Badaracco.