diff --git a/newsfragments/2979.changed.md b/newsfragments/2979.changed.md new file mode 100644 index 00000000000..35a8e49a056 --- /dev/null +++ b/newsfragments/2979.changed.md @@ -0,0 +1 @@ +Allow `create_exception!` to take a `dotted.module` to place the exception in a submodule. diff --git a/src/exceptions.rs b/src/exceptions.rs index 1e2572d1d38..622ee180abb 100644 --- a/src/exceptions.rs +++ b/src/exceptions.rs @@ -201,7 +201,7 @@ macro_rules! import_exception { /// #[macro_export] macro_rules! create_exception { - ($module: ident, $name: ident, $base: ty) => { + ($module: expr, $name: ident, $base: ty) => { #[repr(transparent)] #[allow(non_camel_case_types)] // E.g. `socket.herror` pub struct $name($crate::PyAny); @@ -210,7 +210,7 @@ macro_rules! create_exception { $crate::create_exception_type_object!($module, $name, $base, ::std::option::Option::None); }; - ($module: ident, $name: ident, $base: ty, $doc: expr) => { + ($module: expr, $name: ident, $base: ty, $doc: expr) => { #[repr(transparent)] #[allow(non_camel_case_types)] // E.g. `socket.herror` #[doc = $doc] @@ -232,7 +232,7 @@ macro_rules! create_exception { #[doc(hidden)] #[macro_export] macro_rules! create_exception_type_object { - ($module: ident, $name: ident, $base: ty, $doc: expr) => { + ($module: expr, $name: ident, $base: ty, $doc: expr) => { $crate::pyobject_native_type_core!( $name, *$name::type_object_raw($crate::Python::assume_gil_acquired()), @@ -876,6 +876,21 @@ mod tests { }); } + #[test] + fn custom_exception_dotted_module() { + create_exception!(mymodule.exceptions, CustomError, PyException); + Python::with_gil(|py| { + let error_type = py.get_type::(); + let ctx = [("CustomError", error_type)].into_py_dict(py); + let type_description: String = py + .eval("str(CustomError)", None, Some(ctx)) + .unwrap() + .extract() + .unwrap(); + assert_eq!(type_description, ""); + }); + } + #[test] fn custom_exception_doc() { create_exception!(mymodule, CustomError, PyException, "Some docs");