Skip to content

Commit 927411a

Browse files
committed
fix __qualname__ for complex enum variants (#5796)
* fix `__qualname__` for complex enum variants * newsfragment * clippy
1 parent 2334344 commit 927411a

3 files changed

Lines changed: 58 additions & 0 deletions

File tree

newsfragments/5796.fixed.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix `__qualname__` for complex `#[pyclass]` enum variants to include the enum name.

pyo3-macros-backend/src/pyclass.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,11 @@ fn impl_complex_enum_struct_variant_cls(
14521452
field_getter_impls.push(field_getter_impl);
14531453
}
14541454

1455+
let (qualname, qualname_impl) =
1456+
impl_complex_enum_variant_qualname(enum_name, variant_ident, &variant_cls_type, ctx)?;
1457+
1458+
field_getters.push(qualname);
1459+
14551460
let (variant_match_args, match_args_const_impl) =
14561461
impl_complex_enum_variant_match_args(ctx, &variant_cls_type, &field_names)?;
14571462

@@ -1469,6 +1474,8 @@ fn impl_complex_enum_struct_variant_cls(
14691474

14701475
#match_args_const_impl
14711476

1477+
#qualname_impl
1478+
14721479
#(#field_getter_impls)*
14731480
}
14741481
};
@@ -1641,6 +1648,11 @@ fn impl_complex_enum_tuple_variant_cls(
16411648
&mut field_types,
16421649
)?;
16431650

1651+
let (qualname, qualname_impl) =
1652+
impl_complex_enum_variant_qualname(enum_name, variant_ident, &variant_cls_type, ctx)?;
1653+
1654+
field_getters.push(qualname);
1655+
16441656
let num_fields = variant.fields.len();
16451657

16461658
let (variant_len, len_method_impl) =
@@ -1674,6 +1686,8 @@ fn impl_complex_enum_tuple_variant_cls(
16741686

16751687
#match_args_method_impl
16761688

1689+
#qualname_impl
1690+
16771691
#(#field_getter_impls)*
16781692
}
16791693
};
@@ -1685,6 +1699,34 @@ fn gen_complex_enum_variant_class_ident(enum_: &Ident, variant: &Ident) -> Ident
16851699
format_ident!("{}_{}", enum_, variant)
16861700
}
16871701

1702+
fn impl_complex_enum_variant_qualname(
1703+
enum_name: &syn::Ident,
1704+
variant_ident: &syn::Ident,
1705+
variant_cls_type: &syn::Type,
1706+
ctx: &Ctx,
1707+
) -> syn::Result<(MethodAndMethodDef, syn::ImplItemFn)> {
1708+
let Ctx { pyo3_path, .. } = ctx;
1709+
let qualname = format!("{}.{}", enum_name, variant_ident);
1710+
let mut qualname_impl: syn::ImplItemFn = {
1711+
parse_quote! {
1712+
#[classattr]
1713+
fn __qualname__(py: #pyo3_path::Python<'_>) -> &'static str {
1714+
#qualname
1715+
}
1716+
}
1717+
};
1718+
1719+
let spec = FnSpec::parse(
1720+
&mut qualname_impl.sig,
1721+
&mut qualname_impl.attrs,
1722+
Default::default(),
1723+
)?;
1724+
1725+
// NB: Deliberately add no introspection here, this is __qualname__
1726+
let qualname = impl_py_class_attribute(variant_cls_type, &spec, ctx)?;
1727+
Ok((qualname, qualname_impl))
1728+
}
1729+
16881730
#[cfg(feature = "experimental-inspect")]
16891731
struct FunctionIntrospectionData<'a> {
16901732
names: &'a [&'a str],

tests/test_enum.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,3 +404,18 @@ fn complex_enum_with_raw_pattern_match() {
404404
"#);
405405
});
406406
}
407+
408+
#[test]
409+
fn complex_enum_variant_qualname() {
410+
#[pyclass(skip_from_py_object)]
411+
pub enum ComplexEnum {
412+
A(i32),
413+
B { msg: String },
414+
}
415+
416+
Python::attach(|py| {
417+
let cls = py.get_type::<ComplexEnum>();
418+
py_assert!(py, cls, "cls.A.__qualname__ == 'ComplexEnum.A'");
419+
py_assert!(py, cls, "cls.B.__qualname__ == 'ComplexEnum.B'");
420+
});
421+
}

0 commit comments

Comments
 (0)