pyo3 icon indicating copy to clipboard operation
pyo3 copied to clipboard

declarative modules: #[pymodule_export] macro cannot be gated in `cfg_attr`

Open Tpt opened this issue 6 months ago • 2 comments

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

Tpt avatar Jun 05 '25 19:06 Tpt

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.

mejrs avatar Jun 05 '25 23:06 mejrs

#[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.

SichangHe avatar Jun 06 '25 01:06 SichangHe

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"))]
  |                                ^^^^
  |

adamh-oai avatar Sep 10 '25 20:09 adamh-oai