Repository navigation
python-stdlib/enum/enum.py: Add Enum class. - #980
IhorNehrutsa wants to merge 10 commits into
Conversation
|
Usage example:: Output is:: |
|
Thanks for the contribution, this looks pretty good! Did you implement this from scratch, or copy parts from CPython's implementation? I'm just wondering about licensing and copyright. Can you please add the test to the CI, in |
I just saw CPython Enum. It looks like incredible magic. :-) |
That doesn't really answer the question. Did you copy this implementation from CPython? Also, please make sure the CI all passes, there's currently a failure. |
|
| Did you implement this from scratch, or copy parts from CPython's implementation? No, I didn't use CPython implementation. It was inspired by @shariltumin Dot class from the Way to use dot notation to refer to states in a state machine #15694 |
e70dd06 to
6ab2ebe
Compare
|
Should I squash commits? |
| @@ -0,0 +1,91 @@ | |||
| # enum_test.py | |||
|
|
|||
| from enum import Enum, enum | |||
There was a problem hiding this comment.
I tried to run this test under CPython 3.12.2 but it doesn't work, for many reasons. And it should run under CPython so we can test that the implementation of MicroPython's enum matches the CPython enum.
For example, enum does not exist in the enum CPython module. Which version of CPython were you testing against?
There was a problem hiding this comment.
Version 1.4 matches CPython as I could manage.
| print("type(state('CW')):", type(state("CW"))) | ||
|
|
||
| print("state.key_from_value(20):", state.key_from_value(20)) | ||
| print("len(state):", len(state)) |
There was a problem hiding this comment.
CPython doesn't have __len__ on an enum.
There was a problem hiding this comment.
from enum import Enum
class Color(Enum):
RED = 1
GREEN = 2
print(dir(Color))
['GREEN', 'RED', '__class__', '__contains__', '__doc__', '__getitem__', '__init_subclass__', '__iter__',
'__len__',
'__members__', '__module__', '__name__', '__qualname__']
|
There is a quite comprehensive set of unit-tests for enum available in CPython: https://github.com/python/cpython/blob/main/Lib/test/test_enum.py |
|
I have successfully completed the task that requires the Enum class. |
We need to mip install `datetime`, tzif-parser requires it. https://github.com/micropython/micropython-lib/tree/master/python-stdlib/datetime ``` mpremote connect id:a5f14b8bfbff4289 mip install datetime ``` ## CPython features originally used in `tzif-parser` which were missing or different in MicroPython * `sysconfig` * `enum` - micropython/micropython-lib#269 - micropython/micropython-lib#980 * Regex _named_ Groups - https://docs.python.org/3/howto/regex.html#non-capturing-and-named-groups - https://docs.micropython.org/en/latest/library/re.html * `dataclasses` - https://docs.python.org/3/library/dataclasses.html - https://github.com/orgs/micropython/discussions/13741 - https://github.com/dhrosa/udataclasses - https://udataclasses.readthedocs.io/en/latest/ * `struct` (https://docs.python.org/3/library/struct.html#format-characters) features not available in MicroPython (https://docs.micropython.org/en/latest/library/struct.html#module-struct): - `c` for `char`, which in CPython would be decoded as an instance of [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes-objects) with length 1. Instead of `c`, we could use `s`, but we know this is a single byte, so `b` does just fine, giving us a Python integer. The integral repeat count prefix `1` is superfluous. * [MicroPython `bytearray`](https://www.fredscave.com/43-micropython-data-types-bytearray.html) type doesn't have the [`clear()`](https://docs.python.org/3/library/stdtypes.html#sequence.clear) method [mutable sequences](https://docs.python.org/3/library/stdtypes.html#typesseq-mutable) in CPython do * `Typing.IO` - python/typing#829
We need to mip install `datetime`, tzif-parser requires it. https://github.com/micropython/micropython-lib/tree/master/python-stdlib/datetime ``` mpremote connect id:a5f14b8bfbff4289 mip install datetime ``` ## CPython features originally used in `tzif-parser` which were missing or different in MicroPython * `sysconfig` * `enum` - micropython/micropython-lib#269 - micropython/micropython-lib#980 * Regex _named_ Groups - https://docs.python.org/3/howto/regex.html#non-capturing-and-named-groups - https://docs.micropython.org/en/latest/library/re.html * `dataclasses` - https://docs.python.org/3/library/dataclasses.html - https://github.com/orgs/micropython/discussions/13741 - https://github.com/dhrosa/udataclasses - https://udataclasses.readthedocs.io/en/latest/ * `struct` (https://docs.python.org/3/library/struct.html#format-characters) features not available in MicroPython (https://docs.micropython.org/en/latest/library/struct.html#module-struct): - `c` for `char`, which in CPython would be decoded as an instance of [`bytes`](https://docs.python.org/3/library/stdtypes.html#bytes-objects) with length 1. Instead of `c`, we could use `s`, but we know this is a single byte, so `b` does just fine, giving us a Python integer. The integral repeat count prefix `1` is superfluous. * [MicroPython `bytearray`](https://www.fredscave.com/43-micropython-data-types-bytearray.html) type doesn't have the [`clear()`](https://docs.python.org/3/library/stdtypes.html#sequence.clear) method [mutable sequences](https://docs.python.org/3/library/stdtypes.html#typesseq-mutable) in CPython do * `Typing.IO` - python/typing#829
|
@dpgeorge Need some help on this PR ? Were could I start ? Dominique |
That would be much appreciated. |
|
@IhorNehrutsa, may I ask why you closed the documentation PR? |
This has been going on for so long that I forgot. :( |
|
I'm a bit skeptical about the last @IhorNehrutsa action. On the meanwhile, @IhorNehrutsa pushed an AI rework of the code and "here is it for you to test". Nevertheless, I do not want to be retrograde but being the "human behind the IA for checking the IA work" is not really what I was expecting. |
|
@mchobby, @IhorNehrutsa , I’m also genuinely confused by the pattern of behavior around these PRs: starting work, abandoning it, then suddenly re‑engaging with AI‑generated updates, along with the closing, and re‑opening of related PRs. It makes it difficult to understand the actual intent, the direction of the contribution, or whether you are committed to following through. There is clear interest in having an At the same time, it’s important that MicroPython stays close to CPython where feasible, while still respecting MicroPython’s own design principles and constraints. Achieving that balance requires careful design and discussion, not a surface‑level or (mostly) AI‑generated port. I have not had the time to look at the most recent tests and code - but I do plan to do that in the next few days. |
|
Okay. No one minds if I copy the previous version of enum.py to enum_0.py, the latest to enum_1.py, then we'll choose the best implementation options for enum.py from them. |
Can someone write a MicroPython version of the CPython tests https://github.com/python/cpython/blob/main/Lib/test/test_enum.py ? |
|
I have a concrete StrEnum use case from an application sharing model definitions between CPython and MicroPython. Two behaviors matter for its validators:
I compared CPython 3.12.14, my application’s existing StrEnum implementation, and this PR at Explicit initialization resolves several differences in the PR, but its members still aren’t instances of their declared enum class. The application implementation achieves both behaviors, although it uses a process-wide Are immediate member availability and declared-enum instance identity intended goals for the supported subset? I have a small synthetic comparison runner and recorded results that could help investigate those requirements. |
|
@MrCodeGameandAnime Python 3.12.2 MicroPython v1.29 Are immediate member availability and declared-enum instance identity possible?
You may look at #1061 |
Signed-off-by: Ihor Nehrutsa <[email protected]>
Signed-off-by: Ihor Nehrutsa <[email protected]>
Signed-off-by: Ihor Nehrutsa <[email protected]>
Signed-off-by: Ihor Nehrutsa <[email protected]>
|
Thanks for the explanation and the pointer to #1061. I’ve now tested both approaches alongside the implementation used in my game, Dungeon Drifters. For the narrower from enum import StrEnum
class Mode(StrEnum):
FAST = "fast"
SLOW = "slow"
assert Mode.FAST.name == "FAST"
assert Mode.FAST.value == "fast"
assert isinstance(Mode.FAST, Mode)
assert isinstance(Mode.FAST, str)
assert Mode("fast") is Mode.FAST
assert Mode(Mode.FAST) is Mode.FASTThe mechanism creates actual instances of the declared string subclass and finalizes members through a process-wide The original implementation and application contract tests are public:
I extracted synthetic cases from those requirements into a reproducible comparison at commit I also built #1061’s proposed companion core with all four metaclass options enabled. Immediate member access and declared-enum identity work there. The remaining differences relevant to DD include [GitHub CI reproduced both comparisons](https://github.com/MrCodeGameandAnime/enum_980/actions/runs/38917607382), built both interpreters, and passed all 20 harness tests without skips. Would immediately usable, correctly typed |
|
@MrCodeGameandAnime Thank you very much. I wil develop the immediate member availability after class definition. |
|
@IhorNehrutsa if you don't mind, I’d like to contribute the implementation. Are you be open to me preparing a focused patch based on DD’s approach for your branch? I'd be grateful for the opportunity to build upon your existing work. Having even narrow developmental participation in the Python ecosystem means the world to me, especially MicroPython. |
|
Version 1.5.0 support the the immediate Enum member availability after class definition. @MrCodeGameandAnime I would especially appreciate it if you could review the code, test the implementation, and check the |
The builder hook allows using an Enum without lazy initialization. Signed-off-by: Ihor Nehrutsa <[email protected]>
|
I’ve prepared a focused contribution package based directly on The patch gives StrEnum members their genuine declared class identity while keeping direct functional creation, canonical lookup, declared methods, class iteration, and ordinary string indexing/slicing. It also addresses full/mini builder hook coexistence, fresh imports retaining older aliases, and mini’s missing length operation. Generic Enum and IntEnum implementations remain unchanged. Regression coverage stays in the existing two test files, and the README distinguishes the container and typed class profiles. I ran both package test files directly in separate processes on unmodified stock MicroPython 1.29.0 on Windows and Unix, normally and with The README documents the remaining stock-runtime limits, including class length/subscription, class mutation guards, representation differences, and string-subclass dictionary/JSON keys. Separately, the pinned manifest still declares version |
Signed-off-by: MrCodeGameandAnime <[email protected]>
Signed-off-by: Ihor Nehrutsa <[email protected]>
Signed-off-by: Ihor Nehrutsa <[email protected]>
|
@dpgeorge @agatti @Josverl Public timeline of my contribution to
|
python-stdlib/enum: Improve StrEnum behavior and tests
While I'm also just a contributor, I want to thank you for your willingness to help improve MicroPython. I'm sorry to read that this experience has led you to step away from contributing. If that is your decision, I think the community is losing a enthusiastic contributor. One thing I would like to clarify is that your PR was opened against someone's personal fork rather than the main micropython/micropython-lib repository. Because of that, I would encourage you not to judge the broader MicroPython community solely on this particular experience. Of course, that's entirely your choice, and I can understand why the situation has been frustrating. In my own experience, collaboration on pull requests can be difficult. It is not just about merging Git branches into someone else's fork; it is also about combining different ideas, approaches, and expectations. Questions of authorship and recognition can sometimes become part of that process as well. In some situations, it works better to open a separate PR of your own that incorporates contributions from multiple people and clearly credits everyone involved. Perhaps that might be worth considering in the future, whether for this project or another one. I also noticed that your "PR to the PR" has since been merged. That said, I was surprised to see that you do not appear as the author of the resulting commit, as I would have expected your contribution to be reflected there. In any case, thank you again for your efforts and for taking the time to contribute. Even when things do not go smoothly, contributions like yours help move projects forward. |
|
Hi all, I'm coming in late to this discussion and it's taken me a little while to read all the comments and try to get up to speed. I'm not confident I fully understand all the issues, so please tell me if I'm mistaking anything I want to start by acknowledging that both @IhorNehrutsa and @MrCodeGameandAnime have done a bunch of work here, and thank you both for putting in the time to work on upstream contributions. I particularly appreciate whenever someone builds something for their own project and looks to generalise it into MicroPython, it's often a good indicator of features that will be useful to others. I also acknowledge that feedback from maintainers is often hard or slow to get, and I'm sorry about that. My understanding of @MrCodeGameandAnime's most recent reply is that the major issue here is attribution. I see the Dungeon Drifter's code is under a proprietary license so we can't adapt it directly, but if I understand correctly this PR's contents is intended to be MIT licensed as a contribution to micropython-lib, via Ihor's fork? If so, then suggest this PR adds attribution by naming all contributors via copyright statements in the relevant source files (we don't do a great job being consistent about this in micropython-lib, but a good example to follow is the cbor2 library.) I also wanted to echo Jos, that I hope one bad experience doesn't put anyone off contributing to MicroPython - but understand if it has, @MrCodeGameandAnime. On the "big picture" view of enum support, this PR, and the alternative #1061: from what I can see both of these PRs need significant work before being ready to merge into micropython-lib. However, this approach seems very viable as it doesn't depend on metaclass support landing first (and it still seems to still do well on feature completeness, code size, usefulness, etc.) One major outstanding request I see in the comments is to look at porting CPython's enum tests to MicroPython. It looks like @IhorNehrutsa was looking for help with this earlier in the year but nobody has stepped up. Am I missing anything there? @IhorNehrutsa are you still interested in working on this PR? If so then I can provide more detailed review comments on some other parts of the code/docs. |
My PR in #1061 has tests based on the cpython test suite so should be (hopefully) directly usable here. It's true my PR is intended to be built on top of a minimal metaclass impl in micropython itself in the linked PR, I've put efforts into making both the C and py code as small as possible for the features added - but it still adds up to a fair bit of code! |
|
@projectgus Yes, I am still working on PR. Give me a time for v1.5.2 The PR from @MrCodeGameandAnime was my first PR, and it turned out to be unsuccessful—both in terms of technical aspects and communication. :( @andrewleech Could you create a PR to the https://github.com/IhorNehrutsa/micropython-lib/tree/enum that includes the common CPython/MicroPython test file from #1061? |
|
I appreciate you both taking the time to review what occurred and understand why I decided to step away. Initially, I was certain my involvement was over. However, after reading your responses and seeing how much work remains, I'm willing to reconsider. My goal was always to help get Enum into MicroPython, and that hasn't changed. I also want to expand on Dungeon Drifters as a downstream use case, particularly since @projectgus mentioned the value of bringing solutions developed for real projects into MicroPython. Dungeon Drifters has an extensive MicroPython runtime qualification probe that I've been developing and documenting alongside the game. This goes well beyond isolated unit tests, exercising actual gameplay systems, including combat, progression, recruitment, dungeon traversal, extraction, persistence-related state transitions, and memory-constrained execution. The October 29 qualification used a pinned MicroPython 1.29.0 Windows build, alongside CPython semantic-parity checks. It passed three consecutive full-loop runs at a 608 KB heap boundary, while the expected memory-limit classification was reproduced three times at 576 KB. The implementation, qualification history, memory-pressure findings, and limitations are documented here: https://github.com/MrCodeGameandAnime/Dungeon-Drifters/blob/master/docs/probe.md The successful hosted qualification is available here: https://github.com/MrCodeGameandAnime/Dungeon-Drifters/actions/runs/40914215425 I understand the licensing distinction between Dungeon Drifters' proprietary implementation and contributions to Before moving forward, I'd like three things established. First, proper attribution. I recognize that @IhorNehrutsa has put substantial effort into PR #980. That is precisely why I credited his work in my own contribution, which was built upon his existing implementation. I expect that same recognition for my engineering work, including appropriate authorship and attribution when it is incorporated. Second, a clear collaborative process. I have no intention of creating a competing fork or fragmenting development unnecessarily. I'm willing to continue contributing directly to Ihor's branch, provided we establish that submitted contributions will be reviewed collaboratively rather than superseded by overlapping implementations without discussion, and that authorship will be properly preserved. Third, a concrete path to completion. We already have substantial implementation work, targeted regression coverage, and the possibility of incorporating CPython-derived tests from #1061, as @andrewleech mentioned. Looking through the earlier discussion, several requirements have been raised repeatedly. These include improving CPython compatibility, running meaningful tests against both interpreters, documenting intentional deviations from CPython, and ensuring that the implementation satisfies MicroPython's memory and code-size constraints. There are also practical integration issues remaining. The current PR has passing package, lint, and spelling checks, but the commit-message formatting check is failing, merge conflicts remain, and the PR is still in draft. I believe the next step should be to establish which behaviors are required for upstream acceptance, identify the remaining compatibility gaps, and build a common test suite that clearly distinguishes supported behavior, intentional deviations, and runtime limitations. Dungeon Drifters can complement that effort by providing real downstream qualification alongside the broader CPython compatibility tests. With the existing work and the experience of everyone now involved, I believe we have the resources to get this finished. What we need is an agreed direction and a clear division of responsibilities. I don't want to revisit the previous dispute indefinitely. The public record is there, and my position remains unchanged. However, I also don't want to see a viable implementation remain unfinished when there's an opportunity for us to work together and complete it. I'm willing to contribute further engineering, testing, compatibility analysis, documentation, and review to help get Enum across the finish line. So, what specifically remains before PR #980 can be accepted upstream, and which areas would you like me to take responsibility for? Thank you, |
Docs in:
docs/library/enum.rst: Add Enum class. #16842
Usage example:
EDITED:
Inspired by @shariltumin Dot class from the Way to use dot notation to refer to states in a state machine #15694
and @njourdane enum() func from the Request for package: micropython-enum #269
EDITED October 2026:
See
README.md, `CPy/CPy.py'@MrCodeGameandAnime Thank you very much. I catch idea of immediate member availability after class definition from the DD’s enum implementation.
Standard Behavior (Compatible)
Color.RED,.name,.valuefor item in ColorIntEnumandStrEnumtypes with strict value checkingEnum('Name', {'KEY': value, ...})Non-Standard Behavior
Key differences from CPython:
Color("RED")works for both name and value lookup (CPython standard call only supports value lookup).Color.RED == 1isTrue(only true forIntEnumin CPython)..dump()does not exist in stdlibEnum.Color.RED()returns the value (not supported in CPython).__len__:len(Color)works; CPython enums are not containers.dump()for eval-based reconstruction is MicroPython-specific.Comparing the implementations
enum.pyenum_mini.pyEnum,IntEnum,StrEnumEnum,IntEnum,StrEnumEnumColor["RED"]Color("RED")orColor["RED"]Color("RED")Color(1)Color(1)Color(1)for item in Colorfor item in Colorfor item in Color__members____members__mappingstartfor generated integer valuesIntEnum/StrEnumIntEnum/StrEnumlen(Color)len(Color).dump()Enummember equals its raw valueColor.RED()Code size report: enum.py
esp32: +2688 +0.148% ESP32_GENERIC[incl +2688(data)]
mimxrt: +2632 +0.668% TEENSY40
rp2: +2612 +0.270% RPI_PICO_W
samd: +2632 +0.947% ADAFRUIT_ITSYBITSY_M4_EXPRESS
Code size report: enum_mini.py
esp32: +1568 +0.087% ESP32_GENERIC[incl +1568(data)]
mimxrt: +1544 +0.392% TEENSY40
rp2: +1532 +0.158% RPI_PICO_W
samd: +1548 +0.557% ADAFRUIT_ITSYBITSY_M4_EXPRESS