declarative modules: #[pymodule_export] macro cannot be gated in `cfg_attr`
The following code fails to work properly because #[pymodule_export] gets ignored even if the pyo3 feature is enabled:
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
#[cfg_attr(feature = "pyo3", pymodule)]
pub mod py_const {
#[cfg_attr(feature = "pyo3", pymodule_export)]
pub const MY_CONST: () = ();
}
We should update the pymodule macro code to support cfg_attr and not blindly match on #[pymodule_export].
Issue initially reported by @SichangHe (I reused the example): https://github.com/PyO3/pyo3/issues/3900#issuecomment-2944213501
My feelings on this depends on how this is implemented. I would not want an implementation that checks for particular feature names like feature = "pyo3", feature = "python" etc. I'd be okay with an implementation where you have #[cfg_attr(pred, pymodule_export)] where it puts #[cfg(pred)] on the generated code.
#[pyclass] inside inline modules is broken too, but in a different way: it does not error out, but does not produce a Python class.
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
#[cfg_attr(feature = "pyo3", pymodule)]
pub mod py_const {
#[cfg_attr(feature = "pyo3", pyclass)]
pub struct MyClass {}
}
This one can also be worked around by importing a passthrough attribute macro and using the plain #[pyclass].
#[cfg(feature = "pyo3")]
use pyo3::prelude::*;
#[cfg_attr(feature = "pyo3", pymodule)]
pub mod py_const {
#[cfg(not(feature = "py"))]
use macros::pass_through as pyclass;
#[pyclass]
pub struct MyClass {}
}
I am guessing this kind of problem happens to every non-macro attribute inline #[pymodule] is using.
I think this is a variation of the same issue:
use pyo3::prelude::*;
#[cfg_attr(feature = "py", pyclass(eq))]
#[derive(PartialEq, Eq)]
enum Foo {
#[cfg_attr(feature = "py", pyo3(name = "BAR"))]
Bar
}
Produces:
error: cannot find attribute `pyo3` in this scope
--> src/main.rs:7:32
|
7 | #[cfg_attr(feature = "py", pyo3(name = "BAR"))]
| ^^^^
|