Skip to content

Commit 869a25b

Browse files
Icxoludavidhewitt
authored andcommitted
fix error with complex enums with many fields (#4832)
1 parent f2915f5 commit 869a25b

File tree

4 files changed

+63
-25
lines changed

4 files changed

+63
-25
lines changed

newsfragments/4832.fixed.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
`#[pyclass]` complex enums support more than 12 variant fields.

pyo3-macros-backend/src/pyclass.rs

+23-24
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ use crate::method::{FnArg, FnSpec, PyArg, RegularArg};
1919
use crate::pyfunction::ConstructorAttribute;
2020
use crate::pyimpl::{gen_py_const, get_cfg_attributes, PyClassMethodsType};
2121
use crate::pymethod::{
22-
impl_py_getter_def, impl_py_setter_def, MethodAndMethodDef, MethodAndSlotDef, PropertyType,
23-
SlotDef, __GETITEM__, __HASH__, __INT__, __LEN__, __REPR__, __RICHCMP__, __STR__,
22+
impl_py_class_attribute, impl_py_getter_def, impl_py_setter_def, MethodAndMethodDef,
23+
MethodAndSlotDef, PropertyType, SlotDef, __GETITEM__, __HASH__, __INT__, __LEN__, __REPR__,
24+
__RICHCMP__, __STR__,
2425
};
2526
use crate::pyversions::is_abi3_before;
2627
use crate::utils::{self, apply_renaming_rule, Ctx, LitCStr, PythonDoc};
@@ -1185,34 +1186,30 @@ fn impl_complex_enum_variant_cls(
11851186
}
11861187

11871188
fn impl_complex_enum_variant_match_args(
1188-
ctx: &Ctx,
1189+
ctx @ Ctx { pyo3_path, .. }: &Ctx,
11891190
variant_cls_type: &syn::Type,
11901191
field_names: &mut Vec<Ident>,
1191-
) -> (MethodAndMethodDef, syn::ImplItemConst) {
1192+
) -> syn::Result<(MethodAndMethodDef, syn::ImplItemFn)> {
11921193
let ident = format_ident!("__match_args__");
1193-
let match_args_const_impl: syn::ImplItemConst = {
1194-
let args_tp = field_names.iter().map(|_| {
1195-
quote! { &'static str }
1196-
});
1194+
let mut match_args_impl: syn::ImplItemFn = {
11971195
parse_quote! {
1198-
#[allow(non_upper_case_globals)]
1199-
const #ident: ( #(#args_tp,)* ) = (
1200-
#(stringify!(#field_names),)*
1201-
);
1196+
#[classattr]
1197+
fn #ident(py: #pyo3_path::Python<'_>) -> #pyo3_path::PyResult<#pyo3_path::Bound<'_, #pyo3_path::types::PyTuple>> {
1198+
#pyo3_path::types::PyTuple::new::<&str, _>(py, [
1199+
#(stringify!(#field_names),)*
1200+
])
1201+
}
12021202
}
12031203
};
12041204

1205-
let spec = ConstSpec {
1206-
rust_ident: ident,
1207-
attributes: ConstAttributes {
1208-
is_class_attr: true,
1209-
name: None,
1210-
},
1211-
};
1212-
1213-
let variant_match_args = gen_py_const(variant_cls_type, &spec, ctx);
1205+
let spec = FnSpec::parse(
1206+
&mut match_args_impl.sig,
1207+
&mut match_args_impl.attrs,
1208+
Default::default(),
1209+
)?;
1210+
let variant_match_args = impl_py_class_attribute(variant_cls_type, &spec, ctx)?;
12141211

1215-
(variant_match_args, match_args_const_impl)
1212+
Ok((variant_match_args, match_args_impl))
12161213
}
12171214

12181215
fn impl_complex_enum_struct_variant_cls(
@@ -1260,14 +1257,15 @@ fn impl_complex_enum_struct_variant_cls(
12601257
}
12611258

12621259
let (variant_match_args, match_args_const_impl) =
1263-
impl_complex_enum_variant_match_args(ctx, &variant_cls_type, &mut field_names);
1260+
impl_complex_enum_variant_match_args(ctx, &variant_cls_type, &mut field_names)?;
12641261

12651262
field_getters.push(variant_match_args);
12661263

12671264
let cls_impl = quote! {
12681265
#[doc(hidden)]
12691266
#[allow(non_snake_case)]
12701267
impl #variant_cls {
1268+
#[allow(clippy::too_many_arguments)]
12711269
fn __pymethod_constructor__(py: #pyo3_path::Python<'_>, #(#fields_with_types,)*) -> #pyo3_path::PyClassInitializer<#variant_cls> {
12721270
let base_value = #enum_name::#variant_ident { #(#field_names,)* };
12731271
<#pyo3_path::PyClassInitializer<#enum_name> as ::std::convert::From<#enum_name>>::from(base_value).add_subclass(#variant_cls)
@@ -1434,14 +1432,15 @@ fn impl_complex_enum_tuple_variant_cls(
14341432
slots.push(variant_getitem);
14351433

14361434
let (variant_match_args, match_args_method_impl) =
1437-
impl_complex_enum_variant_match_args(ctx, &variant_cls_type, &mut field_names);
1435+
impl_complex_enum_variant_match_args(ctx, &variant_cls_type, &mut field_names)?;
14381436

14391437
field_getters.push(variant_match_args);
14401438

14411439
let cls_impl = quote! {
14421440
#[doc(hidden)]
14431441
#[allow(non_snake_case)]
14441442
impl #variant_cls {
1443+
#[allow(clippy::too_many_arguments)]
14451444
fn __pymethod_constructor__(py: #pyo3_path::Python<'_>, #(#field_names : #field_types,)*) -> #pyo3_path::PyClassInitializer<#variant_cls> {
14461445
let base_value = #enum_name::#variant_ident ( #(#field_names,)* );
14471446
<#pyo3_path::PyClassInitializer<#enum_name> as ::std::convert::From<#enum_name>>::from(base_value).add_subclass(#variant_cls)

pyo3-macros-backend/src/pymethod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -527,7 +527,7 @@ fn impl_clear_slot(cls: &syn::Type, spec: &FnSpec<'_>, ctx: &Ctx) -> syn::Result
527527
})
528528
}
529529

530-
fn impl_py_class_attribute(
530+
pub(crate) fn impl_py_class_attribute(
531531
cls: &syn::Type,
532532
spec: &FnSpec<'_>,
533533
ctx: &Ctx,

src/tests/hygiene/pyclass.rs

+38
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,44 @@ pub enum TupleEnumEqOrd {
9292
Variant2(u32),
9393
}
9494

95+
#[crate::pyclass(crate = "crate")]
96+
pub enum ComplexEnumManyVariantFields {
97+
ManyStructFields {
98+
field_1: u16,
99+
field_2: u32,
100+
field_3: u32,
101+
field_4: i32,
102+
field_5: u32,
103+
field_6: u32,
104+
field_7: u8,
105+
field_8: u32,
106+
field_9: i32,
107+
field_10: u32,
108+
field_11: u32,
109+
field_12: u32,
110+
field_13: u32,
111+
field_14: i16,
112+
field_15: u32,
113+
},
114+
ManyTupleFields(
115+
u16,
116+
u32,
117+
u32,
118+
i32,
119+
u32,
120+
u32,
121+
u8,
122+
u32,
123+
i32,
124+
u32,
125+
u32,
126+
u32,
127+
u32,
128+
i16,
129+
u32,
130+
),
131+
}
132+
95133
#[crate::pyclass(str = "{x}, {y}, {z}")]
96134
#[pyo3(crate = "crate")]
97135
pub struct PointFmt {

0 commit comments

Comments
 (0)