Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
bpo-45081: Fix __init__ method generation when inheriting from Protocol#28121
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
1eb7835084840a6d1be7491b011e8dc6a2eFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1400,8 +1400,29 @@ def _is_callable_members_only(cls): | ||
| return all(callable(getattr(cls, attr, None)) for attr in _get_protocol_attrs(cls)) | ||
| def _no_init(self, *args, **kwargs): | ||
| raise TypeError('Protocols cannot be instantiated') | ||
| def _no_init_or_replace_init(self, *args, **kwargs): | ||
| cls = type(self) | ||
| if cls._is_protocol: | ||
| raise TypeError('Protocols cannot be instantiated') | ||
Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note to self: this is the previous behavior. | ||
| # Initially, `__init__` of a protocol subclass is set to `_no_init_or_replace_init`. | ||
| # The first instantiation of the subclass will call `_no_init_or_replace_init` which | ||
| # searches for a proper new `__init__` in the MRO. The new `__init__` | ||
| # replaces the subclass' old `__init__` (ie `_no_init_or_replace_init`). Subsequent | ||
| # instantiation of the protocol subclass will thus use the new | ||
| # `__init__` and no longer call `_no_init_or_replace_init`. | ||
| for base in cls.__mro__: | ||
| init = base.__dict__.get('__init__', _no_init_or_replace_init) | ||
| if init is not _no_init_or_replace_init: | ||
| cls.__init__ = init | ||
| break | ||
| else: | ||
| # should not happen | ||
| cls.__init__ = object.__init__ | ||
| cls.__init__(self, *args, **kwargs) | ||
| def _caller(depth=1, default='__main__'): | ||
| try: | ||
| @@ -1541,15 +1562,6 @@ 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. | ||
| @@ -1560,7 +1572,7 @@ 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 | ||
| cls.__init__ = _no_init_or_replace_init | ||
| class _AnnotatedAlias(_GenericAlias, _root=True): | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| Fix issue when dataclasses that inherit from ``typing.Protocol`` subclasses | ||
| have wrong ``__init__``. Patch provided by Yurii Karabas. |
Uh oh!
There was an error while loading. Please reload this page.