Skip to content

Commit db762a9

Browse files
miss-islingtonuriyyo
authored andcommitted
bpo-45121: Fix RecursionError when calling Protocol.__init__ from a subclass' __init__ (GH-28206) (GH-28232)
(cherry picked from commit c11956a) Co-authored-by: Yurii Karabas <[email protected]>
1 parent 39c4fe5 commit db762a9

File tree

3 files changed

+17
-0
lines changed

3 files changed

+17
-0
lines changed

Lib/test/test_typing.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,6 +1604,16 @@ class P(Protocol):
16041604
with self.assertRaisesRegex(TypeError, "@runtime_checkable"):
16051605
isinstance(1, P)
16061606

1607+
def test_super_call_init(self):
1608+
class P(Protocol):
1609+
x: int
1610+
1611+
class Foo(P):
1612+
def __init__(self):
1613+
super().__init__()
1614+
1615+
Foo() # Previously triggered RecursionError
1616+
16071617

16081618
class GenericTests(BaseTestCase):
16091619

Lib/typing.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,6 +1404,11 @@ def _no_init_or_replace_init(self, *args, **kwargs):
14041404
if cls._is_protocol:
14051405
raise TypeError('Protocols cannot be instantiated')
14061406

1407+
# Already using a custom `__init__`. No need to calculate correct
1408+
# `__init__` to call. This can lead to RecursionError. See bpo-45121.
1409+
if cls.__init__ is not _no_init_or_replace_init:
1410+
return
1411+
14071412
# Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`.
14081413
# The first instantiation of the subclass will call `_no_init_or_replace_init` which
14091414
# searches for a proper new `__init__` in the MRO. The new `__init__`
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Fix issue where ``Protocol.__init__`` raises ``RecursionError`` when it's
2+
called directly or via ``super()``. Patch provided by Yurii Karabas.

0 commit comments

Comments
 (0)