"Variant or associated item not found in `Enum`" when a variant is disabled through a feature
Bug Description
When using Cargo features to conditionally enable enum variants, #[pyclass] tries to wrap disabled variants, which causes the compilation to fail.
Steps to Reproduce
Try to compile this code without enabling optional_feature:
#[pyclass]
enum Enum {
AlwaysAvailable,
#[cfg (feature = "optional_feature")]
OptionalVariant,
}
This fails with error:
error[E0599]: no variant or associated item named `OptionalVariant` found for enum `Enum` in the current scope
--> src\lib.rs:5:5
|
2 | enum Enum {
| ____------------
| | |
| | variant or associated item `OptionalVariant` not found for this enum
3 | | AlwaysAvailable,
4 | | #[cfg (feature = "optional_feature")]
5 | | OptionalVariant,
| | -^^^^^^^^^^^^^^^ variant or associated item not found in `Enum`
| |______|
|
For more information about this error, try `rustc --explain E0599`.
(the code works fine when optional_feature is enabled)
Backtrace
No response
Your operating system and version
Windows 10 & ArchLinux
Your Python version (python --version)
Python 3.11.7
Your Rust version (rustc --version)
rustc 1.80.0 (051478957 2024-07-21)
Your PyO3 version
0.20.3
How did you install python? Did you use a virtualenv?
Installer + virtualenv
Additional Info
No response
Thanks for the report - looks like we're missing handling for #[cfg] inside our enum code. There are other places in the proc-macros where we handle cfgs, so it should be possible to do similar here. PR welcome!
Hi, I'm a long time fan of PyO3 and I'm interested about learning some more about how it works. I've come up with a fix for this bug in the case of simple enums: https://github.com/PyO3/pyo3/compare/main...jeff-k:pyo3:enum-feature-variants
I see in the pyimpl.rs and module.rs modules that the solution is to propagate the cfg attributes to the generated code, so that's what I've done.
Here's a test case that could go in tests/test_field_cfg.rs:
#[pyclass(eq, eq_int)]
#[derive(PartialEq)]
enum CfgSimpleEnum {
#[cfg(any())]
pub DisabledVariant,
#[cfg(not(any()))]
pub EnabledVariant,
}
#[test]
fn test_cfg_simple_enum() {
Python::with_gil(|py| {
let simple = py.get_type::<CfgSimpleEnum>();
pyo3::py_run!(py, simple, r#"
assert hasattr(simple, "EnabledVariant")
assert not hasattr(simple, "DisabledVariant")
"#);
})
}
This should fix this specific bug, but motivates a similar fix for complex enums. I'd be happy to be assigned this task.
Thanks for the amazing crate.
@jeff-k sounds perfect and thank you for both the appreciation and contribution. If you're willing to open a PR, I'll gladly review. 🙏
Fixed in #4509