[Python-checkins] bpo-44806: Fix __init__ in subclasses of protocols (GH-27545) (GH-27559)
ambv
webhook-mailer at python.org
Mon Aug 2 12:52:33 EDT 2021
https://github.com/python/cpython/commit/0f6a7739df0055b5c6abe2180f1be97ea4da87b7
commit: 0f6a7739df0055b5c6abe2180f1be97ea4da87b7
branch: 3.9
author: Miss Islington (bot) <31488909+miss-islington at users.noreply.github.com>
committer: ambv <lukasz at langa.pl>
date: 2021-08-02T18:52:16+02:00
summary:
bpo-44806: Fix __init__ in subclasses of protocols (GH-27545) (GH-27559)
Non-protocol subclasses of protocol ignore now the __init__ method
inherited from protocol base classes.
(cherry picked from commit 043cd60abed09edddc7185bcf7d039771acc734d)
Co-authored-by: Serhiy Storchaka <storchaka at gmail.com>
files:
A Misc/NEWS.d/next/Library/2021-08-02-14-37-32.bpo-44806.wOW_Qn.rst
M Lib/test/test_typing.py
M Lib/typing.py
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index 6abd07ec3f540..e05ac4539fb50 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -745,6 +745,9 @@ class P(Protocol): pass
class C(P): pass
self.assertIsInstance(C(), C)
+ with self.assertRaises(TypeError):
+ C(42)
+
T = TypeVar('T')
class PG(Protocol[T]): pass
@@ -759,6 +762,8 @@ class PG(Protocol[T]): pass
class CG(PG[T]): pass
self.assertIsInstance(CG[int](), CG)
+ with self.assertRaises(TypeError):
+ CG[int](42)
def test_cannot_instantiate_abstract(self):
@runtime_checkable
@@ -1194,6 +1199,37 @@ def __init__(self):
self.assertEqual(C[int]().test, 'OK')
+ class B:
+ def __init__(self):
+ self.test = 'OK'
+
+ class D1(B, P[T]):
+ pass
+
+ self.assertEqual(D1[int]().test, 'OK')
+
+ class D2(P[T], B):
+ pass
+
+ self.assertEqual(D2[int]().test, 'OK')
+
+ def test_new_called(self):
+ T = TypeVar('T')
+
+ class P(Protocol[T]): pass
+
+ class C(P[T]):
+ def __new__(cls, *args):
+ self = super().__new__(cls, *args)
+ self.test = 'OK'
+ return self
+
+ self.assertEqual(C[int]().test, 'OK')
+ with self.assertRaises(TypeError):
+ C[int](42)
+ with self.assertRaises(TypeError):
+ C[int](a=42)
+
def test_protocols_bad_subscripts(self):
T = TypeVar('T')
S = TypeVar('S')
diff --git a/Lib/typing.py b/Lib/typing.py
index 5f75a2728055a..894b2d905114c 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -1080,8 +1080,7 @@ def _is_callable_members_only(cls):
def _no_init(self, *args, **kwargs):
- if type(self)._is_protocol:
- raise TypeError('Protocols cannot be instantiated')
+ raise TypeError('Protocols cannot be instantiated')
def _allow_reckless_class_cheks():
@@ -1210,6 +1209,15 @@ def _proto_hook(other):
# We have nothing more to do for non-protocols...
if not cls._is_protocol:
+ if cls.__init__ == _no_init:
+ for base in cls.__mro__:
+ init = base.__dict__.get('__init__', _no_init)
+ if init != _no_init:
+ cls.__init__ = init
+ break
+ else:
+ # should not happen
+ cls.__init__ = object.__init__
return
# ... otherwise check consistency of bases, and prohibit instantiation.
diff --git a/Misc/NEWS.d/next/Library/2021-08-02-14-37-32.bpo-44806.wOW_Qn.rst b/Misc/NEWS.d/next/Library/2021-08-02-14-37-32.bpo-44806.wOW_Qn.rst
new file mode 100644
index 0000000000000..6d818c3fc5798
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-08-02-14-37-32.bpo-44806.wOW_Qn.rst
@@ -0,0 +1,2 @@
+Non-protocol subclasses of :class:`typing.Protocol` ignore now the
+``__init__`` method inherited from protocol base classes.
More information about the Python-checkins
mailing list