pyenum/register.rs
1//! Register derived enums into a `#[pymodule]`.
2//!
3//! The only supported registration path is an explicit library-provided
4//! helper — either the free [`add_enum`] function or the
5//! [`PyModuleExt::add_enum`] extension method. No hidden global registry,
6//! no replacement module macro.
7
8use pyo3::prelude::*;
9use pyo3::types::PyModule;
10
11use crate::trait_def::PyEnum;
12
13/// Register the Python class for `T` onto `module` under `T::SPEC.name`.
14///
15/// Triggers a one-time class construction on the first call per interpreter
16/// per enum type (subsequent calls reuse the cached class). Prefer the
17/// extension-method form [`PyModuleExt::add_enum`] inside `#[pymodule]`
18/// bodies; this free function exists for call sites that want an explicit
19/// type parameter.
20///
21/// If `module` already has an attribute with the same name, it is silently
22/// replaced — consistent with `PyModule::add` and `m.add_class::<T>()?`.
23/// Avoid registering two enums whose `#[pyenum(name = "...")]` resolves to
24/// the same string within a single module.
25///
26/// ```rust,ignore
27/// use pyenum::{PyEnum, add_enum};
28/// use pyo3::prelude::*;
29///
30/// #[derive(Clone, Copy, PyEnum)]
31/// pub enum Color { Red, Green, Blue }
32///
33/// #[pymodule]
34/// fn demo(m: &Bound<'_, PyModule>) -> PyResult<()> {
35/// add_enum::<Color>(m)
36/// }
37/// ```
38pub fn add_enum<T: PyEnum>(module: &Bound<'_, PyModule>) -> PyResult<()> {
39 let py = module.py();
40 let class = T::py_enum_class(py)?;
41 module.add(T::SPEC.name, class)
42}
43
44/// Extension method for `Bound<'_, PyModule>` — the idiomatic way to
45/// register a derived enum inside a `#[pymodule]` body.
46///
47/// ```rust,ignore
48/// use pyenum::{PyEnum, PyModuleExt};
49/// use pyo3::prelude::*;
50///
51/// #[derive(Clone, Copy, PyEnum)]
52/// pub enum Color { Red, Green, Blue }
53///
54/// #[pymodule]
55/// fn demo(m: &Bound<'_, PyModule>) -> PyResult<()> {
56/// m.add_enum::<Color>()
57/// }
58/// ```
59pub trait PyModuleExt {
60 /// Register the Python class for `T` on `self` under `T::SPEC.name`.
61 fn add_enum<T: PyEnum>(&self) -> PyResult<()>;
62}
63
64impl PyModuleExt for Bound<'_, PyModule> {
65 fn add_enum<T: PyEnum>(&self) -> PyResult<()> {
66 add_enum::<T>(self)
67 }
68}