Skip to content

gh-149828: make Protocol compatible with Enum instantiation#149830

Open
randolf-scholz wants to merge 2 commits into
python:mainfrom
randolf-scholz:protocol_enum
Open

gh-149828: make Protocol compatible with Enum instantiation#149830
randolf-scholz wants to merge 2 commits into
python:mainfrom
randolf-scholz:protocol_enum

Conversation

@randolf-scholz
Copy link
Copy Markdown
Contributor

@randolf-scholz randolf-scholz commented May 14, 2026

Fixes #149828

This was surprisingly easy, the issue is that with enums, __init_subclass__ is only called after EnumType.__new__ is finished.

However, when subclassing from typing.Protocol, _is_protocol is only set during __init_subclass__. The fix is to replace the lookup of _is_protocol inside _no_init_or_replace_init with the actual check.

A more robust solution would probably be for _is_protocol to be a lazy class property, but that would be a larger change and class-properties are not natively supported...

cc @sobolevn

Copy link
Copy Markdown
Member

@sobolevn sobolevn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me! Let's wait for @ethanfurman :)

@AlexWaygood AlexWaygood added the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label May 14, 2026
@bedevere-bot
Copy link
Copy Markdown

🤖 New build scheduled with the buildbot fleet by @AlexWaygood for commit 5ab82ba 🤖

Results will be shown at:

https://buildbot.python.org/all/#/grid?branch=refs%2Fpull%2F149830%2Fmerge

If you want to schedule another build, you need to add the 🔨 test-with-refleak-buildbots label again.

@bedevere-bot bedevere-bot removed the 🔨 test-with-refleak-buildbots Test PR w/ refleak buildbots; report in status section label May 14, 2026
Comment thread Lib/test/test_enum.py

class ProtoEnum(Example, Enum, metaclass=CompatEnumType):
__qualname__ = 'ProtoEnum' # needed for pickle protocol 4
impl = Impl()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the ()'s are needed -- can someone test it both ways and verify which version results in the expected enum member and value?

impl = Impl vs impl = Impl()

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without the () the enum member would be the class Impl, not an instance of the class.

>>> from enum import Enum, EnumType
... from typing import Protocol
... 
... class Example(Protocol):
...     def method(self) -> None: ...
... 
... class Impl(Example):
...     def method(self) -> None: ...
... 
... class CompatEnumType(type(Protocol), EnumType): ...
... 
... class ProtoEnumA(Example, Enum, metaclass=CompatEnumType):
...     impl = Impl
... 
... class ProtoEnumB(Example, Enum, metaclass=CompatEnumType):
...     impl = Impl()
... 
... print(repr(ProtoEnumA.impl))
... print(repr(ProtoEnumB.impl))
... 
<ProtoEnumA.impl: <class '__main__.Impl'>>
<ProtoEnumB.impl: <__main__.Impl object at 0x74e096376660>>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good, thank you!

@randolf-scholz randolf-scholz changed the title gh-119946: make Protocol compatible with Enum instantiation gh-149828: make Protocol compatible with Enum instantiation May 15, 2026
@randolf-scholz
Copy link
Copy Markdown
Contributor Author

Had to update the PR title since I copy-pasted the wrong issue number. The Misc/NEWS.d already used the correct number though, so no code changes are needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot subclass from Protocol and Enum at the same time.

5 participants