You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
dataclasses that inherit from Protocol subclasses have wrong __init__ #89244
test.py: Example of another issue with Protocol subclassing
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee=Noneclosed_at=<Date2021-09-02.18:46:32.940>created_at=<Date2021-09-01.21:06:11.095>labels= ['type-bug', 'library', '3.9', '3.10', '3.11']
title='dataclasses that inherit from Protocol subclasses have wrong __init__'updated_at=<Date2021-09-12.21:38:03.668>user='https://github.com/julianfortune'
New changeset 98eb408 by Miss Islington (bot) in branch '3.9': bpo-45081: Fix __init__ method generation when inheriting from Protocol (GH-28121) (GH-28132) 98eb408
New changeset 79e9f5a by Miss Islington (bot) in branch '3.10': bpo-45081: Fix __init__ method generation when inheriting from Protocol (GH-28121) 79e9f5a
I believe this was a deeper issue that affected all classes inheriting Protocol, causing a TypeError on even the most basic case (see attached):
Traceback (most recent call last):
File "/.../test.py", line 14, in <module>
MyClass()
File "/.../test.py", line 11, in __init__super().__init__()
File "/usr/local/Cellar/python@3.9/3.9.7/Frameworks/Python.framework/Versions/3.9/lib/python3.9/typing.py", line 1083, in _no_initraiseTypeError('Protocols cannot be instantiated')
TypeError: Protocols cannot be instantiated
MyProtocol does not provide an __init__(), and thus
super().__init__()
is calling the __init__() from Protocol. This results in the TypeError.
Simply remove super().__init__() to resolve your issue.
This behavior was changed in #27545 (see [Lib/typing.py:1384](https://github.com/python/cpython/blob/main/Lib/typing.py#L1384)); I don't see what you are reporting as a regression, I see it as correct behavior that I would expect. Apologies if you feel differently.
Cheers,
Julian
icgood commented on Sep 12, 2021
icgoodmannequin
Mannequin
More actions
Julian,
That is certainly a workaround, however the behavior you are describing is inconsistent with PEP-544 in both word and intention. From the PEP:
To explicitly declare that a certain class implements a given protocol, it can be used as a regular base class.
It further describes the semantics of inheriting as "unchanged" from a "regular base class". If the semantics are "unchanged" then it should follow that super().__init__() would pass through the protocol to the object.__init__, just like a "regular base class" would if it does not override __init__.
Furthermore, the intention of inheriting a Protocol as described in the PEP:
Static analysis tools are expected to automatically detect that a class implements a given protocol. So while it's possible to subclass a protocol explicitly, it's not necessary to do so for the sake of type-checking.
The purpose of adding a Protocol sub-class as an explicit base class is thus only to improve static analysis, it should *not* to modify the runtime semantics.
Consider the case where a package maintainer wants to enhance the flexibility of their types by transitioning from using an ABC to using structural sub-typing. That simple typing change would be a breaking change to the package consumers, who must now remove a super().__init__() call.
Activity
julianfortune commentedon Sep 1, 2021
I believe
bpo-44806: Fix __init__ in subclasses of protocolshas caused a regression when using a Dataclass.In Python
3.9.7, adataclassthat inherits from a subclass oftyping.Protocol(i.e., a user-defined protocol), does not have the correct__init__.### Demonstration
In
3.9.7:In
3.9.6:B(value='test')### Affected Projects
ambv commentedon Sep 2, 2021
New changeset 0635e20 by Yurii Karabas in branch 'main':
bpo-45081: Fix __init__ method generation when inheriting from Protocol (GH-28121)
0635e20
ambv commentedon Sep 2, 2021
New changeset 98eb408 by Miss Islington (bot) in branch '3.9':
bpo-45081: Fix __init__ method generation when inheriting from Protocol (GH-28121) (GH-28132)
98eb408
miss-islington commentedon Sep 3, 2021
New changeset 79e9f5a by Miss Islington (bot) in branch '3.10':
bpo-45081: Fix __init__ method generation when inheriting from Protocol (GH-28121)
79e9f5a
icgood commentedon Sep 11, 2021
I believe this was a deeper issue that affected all classes inheriting Protocol, causing a TypeError on even the most basic case (see attached):
This was a new regression in 3.9.7 and seems to be resolved by this fix. The desired behavior should be supported according to PEP-544: https://www.python.org/dev/peps/pep-0544/#explicitly-declaring-implementation
julianfortune commentedon Sep 12, 2021
Ian,
MyProtocoldoes not provide an__init__(), and thusis calling the
__init__()fromProtocol. This results in theTypeError.Simply remove
super().__init__()to resolve your issue.This behavior was changed in #27545 (see
[Lib/typing.py:1384](https://github.com/python/cpython/blob/main/Lib/typing.py#L1384)); I don't see what you are reporting as a regression, I see it as correct behavior that I would expect. Apologies if you feel differently.Cheers,
Julian
icgood commentedon Sep 12, 2021
Julian,
That is certainly a workaround, however the behavior you are describing is inconsistent with PEP-544 in both word and intention. From the PEP:
It further describes the semantics of inheriting as "unchanged" from a "regular base class". If the semantics are "unchanged" then it should follow that super().__init__() would pass through the protocol to the object.__init__, just like a "regular base class" would if it does not override __init__.
Furthermore, the intention of inheriting a Protocol as described in the PEP:
The purpose of adding a Protocol sub-class as an explicit base class is thus only to improve static analysis, it should *not* to modify the runtime semantics.
Consider the case where a package maintainer wants to enhance the flexibility of their types by transitioning from using an ABC to using structural sub-typing. That simple typing change would be a breaking change to the package consumers, who must now remove a super().__init__() call.
Ian
[ONNX] Remove protocol dataclass (#85916)
[ONNX] Remove protocol dataclass (#85916)