Skip to content

python-stdlib/enum/enum.py: Add Enum class. - #980

Open
IhorNehrutsa wants to merge 4 commits into
micropython:masterfrom
IhorNehrutsa:enum
Open

IhorNehrutsa wants to merge 4 commits into
micropython:masterfrom
IhorNehrutsa:enum

Conversation

@IhorNehrutsa

@IhorNehrutsa IhorNehrutsa commented Mar 5, 2025 •

Copy link
Copy Markdown

Docs in:
docs/library/enum.rst: Add Enum class. #16842
Usage example:

from enum import Enum

class Color(Enum):
    RED = 'red'
    GREEN = 'green'

# Initialize
Color()

print(Color.RED)        # Color.RED
print(Color.RED.name)   # RED
print(Color.RED.value)  # red
print(len(Color()))     # 2
print(Color.__members__)    # {<Color.GREEN: 'green'>: 'green', <Color.RED: 'red'>: 'red'}

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'

Standard Behavior (Compatible)

  • ✅ Member access: Color.RED, .name, .value
  • ✅ Member iteration: for item in Color()
  • ✅ IntEnum and StrEnum types with strict value checking
  • ✅ Immutability: members cannot be modified after creation
  • ✅ Functional API: Enum('Name', {'KEY': value, ...})

Non-Standard Behavior

Key differences from CPython:

  • Explicit Lazy Initialization: MicroPython implementations rely on class/instance evaluation (e.g., Color()) to trigger lazy member initialization when standard class bodies aren't fully traversed upfront.
  • Name-based lookup via call: Color("RED") works for both name and value lookup (CPython standard call only supports value lookup).
  • Value equality: Color.RED == 1 is True (only true for IntEnum in CPython).
  • Custom methods: .dump() does not exist in stdlib Enum.
  • Callable members: Color.RED() returns the value (not supported in CPython).
  • Instance __len__: len(Color()) works; CPython enums are not containers.
  • Serialization: dump() for eval-based reconstruction is MicroPython-specific.

Comparing the implementations

Feature CPython enum.py enum_mini.py
Enum types Enum, IntEnum, StrEnum Enum, IntEnum, StrEnum Enum
Lookup by name Color["RED"] Color("RED") or Color()["RED"] Color("RED")
Lookup by value Color(1) Color(1) Color(1)
Iteration for item in Color for item in Color() for item in Color()
Iteration in __members__ Yes Yes Yes
__members__ keys and values Names and members Members and values Members and values
Functional API Dict, names string, list/tuple, or iterable Dict, names string, list/tuple, or iterable Dictionary only
start for generated integer values Yes Yes No
.dump() No Yes No
Plain Enum member equals its raw value No Yes Yes
Member is an instance of its enum class Yes No No
Calling the enum without arguments returns a container No Yes Yes

Code size report: enum.py
esp32: +2288 +0.126% ESP32_GENERIC[incl +2288(data)]
mimxrt: +2232 +0.567% TEENSY40
rp2: +2228 +0.231% RPI_PICO_W
samd: +2236 +0.804% ADAFRUIT_ITSYBITSY_M4_EXPRESS

Code size report: enum_mini.py
esp32: +1264 +0.070% ESP32_GENERIC[incl +1264(data)]
mimxrt: +1232 +0.313% TEENSY40
rp2: +1236 +0.128% RPI_PICO_W
samd: +1232 +0.443% ADAFRUIT_ITSYBITSY_M4_EXPRESS

@IhorNehrutsa IhorNehrutsa changed the title Add Enum class. python-stdlib/enum/enum.py: Add Enum class. Mar 5, 2025
@IhorNehrutsa

IhorNehrutsa commented Mar 5, 2025 •

Copy link
Copy Markdown
Author

Usage example::

from enum import Enum

class State(Enum):
  Stop = 10
  Run = 20
  Ready = 30

state = State()
print("state:", State())

current_state = state.Stop
print("current_state:", current_state, current_state.name)
if current_state == state.Stop:
  print(" Stop state")
if current_state != state.Ready:
  print(" Not a Ready state")
  print(" Run!")
  current_state = state.Run
print("current_state:", current_state, current_state.name)
# some process
i = -1
while current_state != state.Ready:
  i += 1
  if state.is_value(i):
      if state(i) == state.Ready:
          current_state = state.Ready
  print(".", end="")
print()
print("current_state:", current_state, state(current_state))
print("Done!")

Output is::

state: State(names={'Run': 20, 'Stop': 10, 'Ready': 30})
current_state: Stop: 10 Stop
 Stop state
 Not a Ready state
 Run!
current_state: Run: 20 Run
...............................
current_state: Ready: 30 Ready: 30
Done!

@dpgeorge

Copy link
Copy Markdown
Member

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 tools/ci.sh inside the function ci_package_tests_run.

@IhorNehrutsa

Copy link
Copy Markdown
Author

Did you implement this from scratch, or copy parts from CPython's implementation?

I just saw CPython Enum. It looks like incredible magic. :-)

@dpgeorge

Copy link
Copy Markdown
Member

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.

@IhorNehrutsa

Copy link
Copy Markdown
Author

| 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
and @njourdane enum() func from the Request for package: micropython-enum #269

Comment thread python-stdlib/enum/manifest.py Outdated
@IhorNehrutsa
IhorNehrutsa force-pushed the enum branch 2 times, most recently from e70dd06 to 6ab2ebe Compare March 12, 2025 07:34
@IhorNehrutsa

Copy link
Copy Markdown
Author

Should I squash commits?

Comment thread python-stdlib/enum/test_enum.py Outdated
@@ -0,0 +1,91 @@
# enum_test.py

from enum import Enum, enum

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 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?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Version 1.4 matches CPython as I could manage.

Comment thread python-stdlib/enum/test_enum.py Outdated
Comment thread python-stdlib/enum/test_enum.py Outdated
Comment thread python-stdlib/enum/test_enum.py Outdated
Comment thread python-stdlib/enum/test_enum.py Outdated
Comment thread python-stdlib/enum/test_enum.py Outdated
Comment thread python-stdlib/enum/test_enum.py Outdated
Comment thread python-stdlib/enum/test_enum.py Outdated
print("type(state('CW')):", type(state("CW")))

print("state.key_from_value(20):", state.key_from_value(20))
print("len(state):", len(state))

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.

CPython doesn't have __len__ on an enum.

@IhorNehrutsa IhorNehrutsa Oct 10, 2026 •

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

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__']

Comment thread python-stdlib/enum/test_enum.py Outdated
@jonnor

jonnor commented Apr 25, 2025

Copy link
Copy Markdown

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
With some exceptions like the tests using inspect, threading, pickle it seems possible to port most of them to MicroPython. That would give a very high degree of confidence that the implementation is conformant. And in the cases that one chooses to not be conformant, that can be documented with skipped tests.

@IhorNehrutsa

Copy link
Copy Markdown
Author

I have successfully completed the task that requires the Enum class.
I don't plan to support this PR in the future.
You are welcome to continue working with this PR as you wish.
Thanks everyone.

rtyley added a commit to rtyley/analogue-led-clock that referenced this pull request Mar 22, 2026
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
rtyley added a commit to rtyley/analogue-led-clock that referenced this pull request Mar 22, 2026
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
@mchobby

mchobby commented Apr 11, 2026

Copy link
Copy Markdown

@dpgeorge
This PR looks stuck in time. I didn't find enum.py in micropython-lib/python-stdlib/enum.py .
Getting Enum for MicroPython would be really useful .

Need some help on this PR ? Were could I start ?

Dominique

@Josverl

Josverl commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

Need some help on this PR ? Were could I start ?

That would be much appreciated.
I would suggest that making it match Cpython more and changing/adding tests to prove that would be the next step

@IhorNehrutsa

Copy link
Copy Markdown
Author

@mchobby @Josverl You may pull down this PR and try to use enum.py. Please write reviews about usage here

@Josverl

Josverl commented Apr 14, 2026

Copy link
Copy Markdown
Contributor

@IhorNehrutsa, may I ask why you closed the documentation PR?

@IhorNehrutsa

Copy link
Copy Markdown
Author

@IhorNehrutsa, may I ask why you closed the documentation PR?

This has been going on for so long that I forgot. :(

@mchobby

mchobby commented Apr 15, 2026

Copy link
Copy Markdown

I'm a bit skeptical about the last @IhorNehrutsa action.
As I understand, the initial PR enum.py behavior was too far from CPython implementation.
I was interested to help in reducing the gap between CPython & MicroPython implementation.
That was looking as a "Good-First-Issue" to me (and for me).

On the meanwhile, @IhorNehrutsa pushed an AI rework of the code and "here is it for you to test".
As last arrival in this PR (and micropython-lib), I'm not in great position to evaluate the appropriateness of that rework.
@Josverl could you have a quick review on this for guidance?

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.
Cheers

@Josverl

Josverl commented Apr 15, 2026 •

Copy link
Copy Markdown
Contributor

@mchobby,
I agree with the earlier comments that it isn’t the reviewer’s job to try to interpret or “fix up” clearly AI‑generated submissions. If the submitter isn’t putting in at least the same level of effort as the reviewers, the process becomes unbalanced and unsustainable.
That does not mean that AI is not to be used as a tool to create code, but it does mean that there needs to be more that just that.

@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.
to be clear - I do appreciate your efforts, and I realize that sometimes the wait for a PR to get merged (or even rejected) can exceed ones attention span. but in order for us to work as a community I prefer to have some level confidence.

There is clear interest in having an Enum class available in MicroPython. But implementing one properly is non‑trivial — it touches (the lack of) metaclasses, memory constraints, and the broader philosophy of keeping the core minimal.

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.

@IhorNehrutsa

Copy link
Copy Markdown
Author

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.

@IhorNehrutsa

Copy link
Copy Markdown
Author

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 With some exceptions like the tests using inspect, threading, pickle it seems possible to port most of them to MicroPython. That would give a very high degree of confidence that the implementation is conformant. And in the cases that one chooses to not be conformant, that can be documented with skipped tests.

Can someone write a MicroPython version of the CPython tests https://github.com/python/cpython/blob/main/Lib/test/test_enum.py ?

@Josverl

Josverl commented May 27, 2026

Copy link
Copy Markdown
Contributor

One of the twenty-something post its on my MicroPython to-do list is to do a full review and comparison.

But I can't give you a date

@agatti agatti left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I've had a quick look at the code, and whilst I'm still going through the internals of this module, I can at least provide a couple of hints on how to make the final output smaller :)

Comment thread python-stdlib/enum/README.md
Comment thread python-stdlib/enum/enum.py Outdated
Comment thread python-stdlib/enum/enum.py Outdated
Comment thread python-stdlib/enum/enum.py Outdated
Comment thread python-stdlib/enum/enum.py Outdated
@IhorNehrutsa

Copy link
Copy Markdown
Author

Hi all, I know you're busy, but just gently bringing this back to your attention. Please let me know if any changes, additional tests, or documentation updates are required on my end. Appreciate your work.

Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
@IhorNehrutsa
IhorNehrutsa marked this pull request as draft October 10, 2026 13:03
@IhorNehrutsa
IhorNehrutsa marked this pull request as ready for review October 10, 2026 13:03
Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Signed-off-by: Ihor Nehrutsa <Ihor.Nehrutsa@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants