micropython-lib icon indicating copy to clipboard operation
micropython-lib copied to clipboard

python-stdlib/enum: Add enum module

Open andrewleech opened this issue 1 month ago • 0 comments

Summary

Adds enum package implementing PEP 435 (Enum) and PEP 663 (Flag) with modular lazy-loading structure.

This package provides CPython-compatible enum support for MicroPython, enabling libraries like python-statemachine and providing standard enum functionality for embedded projects.

Features

Complete enum implementation:

  • Enum - Base enumeration with member management and value lookup
  • IntEnum - Integer-valued enums with arithmetic operations
  • Flag - Bitwise flags with |, &, ^, ~ operators
  • IntFlag - Integer-compatible bitwise flags
  • StrEnum - String-valued enums (Python 3.11+)
  • auto() - Automatic value assignment based on insertion order
  • @unique - Decorator to prevent duplicate values

Structure

Modular design with lazy loading to minimize memory footprint:

python-stdlib/enum/
├── enum/
│   ├── __init__.py    # Entry point with lazy loader (~200 bytes)
│   ├── core.py        # Enum, IntEnum, EnumMeta (~1.5KB frozen)
│   ├── flags.py       # Flag, IntFlag (~500 bytes, loaded on demand)
│   └── extras.py      # StrEnum, auto, unique (~450 bytes, loaded on demand)
├── manifest.py        # Package definition
├── README.md          # Documentation
└── test_enum.py       # CPython's official enum test suite

Total size when frozen: ~5.4KB (core always loaded: ~1.7KB, features loaded on demand: ~950 bytes)

CPython Compatibility

Tested against CPython 3.13's official test_enum.py:

  • 448 tests run
  • 445 passed (99.3%)
  • 3 tests skipped (functional API not implemented)

Works

  • All class-based enum definitions
  • auto() value generation (requires MICROPY_PY_METACLASS_PREPARE)
  • Explicit and mixed values
  • Iteration, lookup, comparison, repr
  • Flag bitwise operations and combination membership
  • @unique decorator
  • Type mixins (int, str, float, date)
  • Pickling/unpickling
  • __members__, dir(), introspection
  • Thread-safe enum creation

Not Implemented

  • Functional API: Enum('Name', 'A B C') - use class syntax instead
  • _missing_(), _ignore_(), _generate_next_value_() hooks
  • Boundary modes (STRICT, CONFORM, EJECT, KEEP)

Known Limitation

IntEnum members fail isinstance(member, int) check in MicroPython due to implementation constraints, but all integer operations work correctly. This is a MicroPython limitation, not an enum package issue.

MicroPython Requirements

Requires metaclass support from main MicroPython repo:

  • MICROPY_PY_METACLASS_INIT (CORE level) - For basic enum functionality
  • MICROPY_PY_METACLASS_OPS (EXTRA level) - For len(EnumClass) and member in EnumClass
  • MICROPY_PY_METACLASS_PREPARE (FULL level) - For auto() support

These features are included in the companion PR to micropython/micropython: #18416

Usage

from enum import Enum, IntEnum, Flag, IntFlag, auto

# Basic enum
class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3

print(Color.RED)           # Color.RED
print(Color.RED.value)     # 1
print(Color(1))            # Color.RED

# With auto()
class Status(Enum):
    PENDING = auto()   # 1
    ACTIVE = auto()    # 2
    DONE = auto()      # 3

# Flags
class Permission(Flag):
    READ = 1
    WRITE = 2
    EXECUTE = 4

perm = Permission.READ | Permission.WRITE
print(perm)                        # Permission.READ|WRITE
print(Permission.READ in perm)     # True

Testing

Includes CPython's official test_enum.py (6000+ lines) for validation. Run on MicroPython Unix port:

micropython test_enum.py

Size Impact

When frozen into firmware:

  • Core module (Enum, IntEnum): ~1.7KB
  • Optional features (Flag, StrEnum, auto): ~950 bytes (loaded on demand)
  • Total: ~2.6KB bytecode

Example for STM32 PYBV10:

  • Baseline: 368,648 bytes
  • With enum frozen: 374,076 bytes (+5,428 bytes = +1.47%)

Related

Companion PR for MicroPython core: micropython/micropython#18416

andrewleech avatar Nov 14 '25 05:11 andrewleech