RFC: Opt-in native_enum mode — expose #[pyclass] enums as real enum.Enum subclasses
#5991
Replies: 2 comments
-
|
Thank you! My 2cents:
My (personal!) feeling is that it depends on performances. If the functional-API is nearly as fast (or faster?) then it looks to me like a nice way to go. A benchmark would be very useful here.
Something I overlooked in my previous answer, sorry: In any case I do not have the final call on this, so take my answer accordingly. |
Beta Was this translation helpful? Give feedback.
-
Benchmark Complete: Cache Strategy ComparisonI measured multiple caching strategies to understand the performance implications of different approaches to exposing Rust enums as Python Benchmark Results
Hardware: Apple Silicon M-series, PyO3 0.28.3, Python 3.11 Critical Finding: Why Caching Python
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Opt-in
native_enummode for#[pyclass]enums?Context
#[pyclass] enumfailsisinstance(x, enum.Enum)and is missing most of the enum protocol (__iter__,__members__,name,value,MyEnum(0),MyEnum["X"], …), so pydantic / FastAPI / SQLAlchemy /match-case need hand-written shims.#2887 raised that true
enum.Enumsubclassing is blocked by #991 (Enum isn't in the C-API). The C-API isn't needed —enum.Enum("Name", [(name, value), …])is a pure-Python functional constructor that returns a fully metaclass-blessed class. Calling it via PyO3 sidesteps #991.Prior art
py::native_enum+.finalize()(native_enum_data.h). No metaclass reimplementation — getters/setters only buffer name/value pairs before the functional call.#[derive(PyEnum)]produces a realenum.Enumsubclass (class cached inPyOnceLock<Py<PyType>>, auto-derivesIntoPyObject/FromPyObject, supportsEnum/IntEnum/StrEnum/Flag/IntFlag, pickle +match-case tested).pyenum can stay external — I'm not assuming it needs upstreaming. Opening this Discussion to ask whether PyO3 wants a native mode.
Sketch
First access →
enum.<Base>("Status", [...], module=..., qualname=...)via functional API, cached inPyOnceLock<Py<PyType>>. Unit variants only; tuple/struct/generic rejected at compile time.Open questions
#[pyclass] enumbehavior kept under the bare attribute; new behavior strictly behindnative_enum = "…". Deprecate over time or not?module/qualname. Auto-populate from enclosing#[pymodule], explicit override available.eq/eq_int/hash/frozen. Mostly redundant underEnumMeta. Warn, ignore, or error?_missing_/ custom__new__. Out of scope for v1?Perf
pyenum targets: first construction < 2 ms (≤32 variants) / < 20 ms (≤1024), steady-state conversion < 1 µs (cache hit =
PyOnceLockload + attr lookup). I'll post measured numbers as a follow-up to address @Tpt's "no significant perf hit" bar.Asks
enums generated by Pyo3 don't actually subclass Python'sEnum#2887 — or is a separate crate the right home for this case?native_enum = "…"the right surface?If there's interest I can split into (1) small RFC PR for the attribute + scope, (2) implementation PR with cache + derive changes + trybuild/pytest + benchmarks. If the answer is "keep it external," that's fine too — pyenum continues on its own.
Beta Was this translation helpful? Give feedback.
All reactions