From 37915336ea4567cecfb9262832bd65ef2355b56a Mon Sep 17 00:00:00 2001 From: Jeong YunWon Date: Sun, 26 Oct 2025 23:17:40 +0900 Subject: [PATCH] Expand #[pyexception] macro working with module attr --- derive-impl/src/pyclass.rs | 8 +++++++- derive-impl/src/pymodule.rs | 10 +++++++--- derive-impl/src/util.rs | 3 ++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/derive-impl/src/pyclass.rs b/derive-impl/src/pyclass.rs index 6c589896e..272ed7e5f 100644 --- a/derive-impl/src/pyclass.rs +++ b/derive-impl/src/pyclass.rs @@ -551,7 +551,13 @@ pub(crate) fn impl_pyexception(attr: PunctuatedNestedMeta, item: Item) -> Result } } } else { - quote! {} + quote! { + impl ::rustpython_vm::PyPayload for #ident { + fn class(_ctx: &::rustpython_vm::vm::Context) -> &'static ::rustpython_vm::Py<::rustpython_vm::builtins::PyType> { + ::static_type() + } + } + } }; let impl_pyclass = if class_meta.has_impl()? { quote! { diff --git a/derive-impl/src/pymodule.rs b/derive-impl/src/pymodule.rs index 9e052cd1f..a8588a762 100644 --- a/derive-impl/src/pymodule.rs +++ b/derive-impl/src/pymodule.rs @@ -16,6 +16,7 @@ enum AttrName { Function, Attr, Class, + Exception, } impl std::fmt::Display for AttrName { @@ -24,6 +25,7 @@ impl std::fmt::Display for AttrName { Self::Function => "pyfunction", Self::Attr => "pyattr", Self::Class => "pyclass", + Self::Exception => "pyexception", }; s.fmt(f) } @@ -37,6 +39,7 @@ impl FromStr for AttrName { "pyfunction" => Self::Function, "pyattr" => Self::Attr, "pyclass" => Self::Class, + "pyexception" => Self::Exception, s => { return Err(s.to_owned()); } @@ -232,7 +235,8 @@ fn module_item_new( inner: ContentItemInner { index, attr_name }, py_attrs, }), - AttrName::Class => Box::new(ClassItem { + // pyexception is treated like pyclass - both define types + AttrName::Class | AttrName::Exception => Box::new(ClassItem { inner: ContentItemInner { index, attr_name }, py_attrs, }), @@ -302,13 +306,13 @@ where result.push(item_new(i, attr_name, Vec::new())); } else { match attr_name { - AttrName::Class | AttrName::Function => { + AttrName::Class | AttrName::Function | AttrName::Exception => { result.push(item_new(i, attr_name, py_attrs.clone())); } _ => { bail_span!( attr, - "#[pyclass] or #[pyfunction] only can follow #[pyattr]", + "#[pyclass], #[pyfunction], or #[pyexception] can follow #[pyattr]", ) } } diff --git a/derive-impl/src/util.rs b/derive-impl/src/util.rs index 47a0606f0..f7f0d28fb 100644 --- a/derive-impl/src/util.rs +++ b/derive-impl/src/util.rs @@ -446,7 +446,8 @@ impl ClassItemMeta { pub(crate) struct ExceptionItemMeta(ClassItemMeta); impl ItemMeta for ExceptionItemMeta { - const ALLOWED_NAMES: &'static [&'static str] = &["name", "base", "unhashable", "ctx", "impl"]; + const ALLOWED_NAMES: &'static [&'static str] = + &["module", "name", "base", "unhashable", "ctx", "impl"]; fn from_inner(inner: ItemMetaInner) -> Self { Self(ClassItemMeta(inner))