@@ -29,18 +29,7 @@ macro_rules! impl_exception_boilerplate {
29
29
}
30
30
}
31
31
32
- impl $name {
33
- /// Creates a new [`PyErr`] of this type.
34
- ///
35
- /// [`PyErr`]: https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html "PyErr in pyo3"
36
- #[ inline]
37
- pub fn new_err<A >( args: A ) -> $crate:: PyErr
38
- where
39
- A : $crate:: PyErrArguments + :: std:: marker:: Send + :: std:: marker:: Sync + ' static ,
40
- {
41
- $crate:: PyErr :: new:: <$name, A >( args)
42
- }
43
- }
32
+ $crate:: impl_exception_boilerplate_bound!( $name) ;
44
33
45
34
impl :: std:: error:: Error for $name {
46
35
fn source( & self ) -> :: std:: option:: Option <& ( dyn :: std:: error:: Error + ' static ) > {
@@ -59,6 +48,25 @@ macro_rules! impl_exception_boilerplate {
59
48
} ;
60
49
}
61
50
51
+ #[ doc( hidden) ]
52
+ #[ macro_export]
53
+ macro_rules! impl_exception_boilerplate_bound {
54
+ ( $name: ident) => {
55
+ impl $name {
56
+ /// Creates a new [`PyErr`] of this type.
57
+ ///
58
+ /// [`PyErr`]: https://docs.rs/pyo3/latest/pyo3/struct.PyErr.html "PyErr in pyo3"
59
+ #[ inline]
60
+ pub fn new_err<A >( args: A ) -> $crate:: PyErr
61
+ where
62
+ A : $crate:: PyErrArguments + :: std:: marker:: Send + :: std:: marker:: Sync + ' static ,
63
+ {
64
+ $crate:: PyErr :: new:: <$name, A >( args)
65
+ }
66
+ }
67
+ } ;
68
+ }
69
+
62
70
/// Defines a Rust type for an exception defined in Python code.
63
71
///
64
72
/// # Syntax
@@ -105,34 +113,57 @@ macro_rules! import_exception {
105
113
106
114
impl $name {
107
115
fn type_object_raw( py: $crate:: Python <' _>) -> * mut $crate:: ffi:: PyTypeObject {
108
- use $crate:: sync:: GILOnceCell ;
109
- use $crate:: prelude:: PyTracebackMethods ;
110
- use $crate:: prelude:: PyAnyMethods ;
111
- static TYPE_OBJECT : GILOnceCell <$crate:: Py <$crate:: types:: PyType >> =
112
- GILOnceCell :: new( ) ;
116
+ use $crate:: types:: PyTypeMethods ;
117
+ static TYPE_OBJECT : $crate:: impl_:: exceptions:: ImportedExceptionTypeObject =
118
+ $crate:: impl_:: exceptions:: ImportedExceptionTypeObject :: new( stringify!( $module) , stringify!( $name) ) ;
119
+ TYPE_OBJECT . get( py) . as_type_ptr( )
120
+ }
121
+ }
122
+ } ;
123
+ }
113
124
114
- TYPE_OBJECT
115
- . get_or_init( py, || {
116
- let imp = py
117
- . import_bound( stringify!( $module) )
118
- . unwrap_or_else( |err| {
119
- let traceback = err
120
- . traceback_bound( py)
121
- . map( |tb| tb. format( ) . expect( "raised exception will have a traceback" ) )
122
- . unwrap_or_default( ) ;
123
- :: std:: panic!( "Can not import module {}: {}\n {}" , stringify!( $module) , err, traceback) ;
124
- } ) ;
125
- let cls = imp. getattr( stringify!( $name) ) . expect( concat!(
126
- "Can not load exception class: " ,
127
- stringify!( $module) ,
128
- "." ,
129
- stringify!( $name)
130
- ) ) ;
131
-
132
- cls. extract( )
133
- . expect( "Imported exception should be a type object" )
134
- } )
135
- . as_ptr( ) as * mut _
125
+ /// Variant of [`import_exception`](crate::import_exception) that does not emit code needed to
126
+ /// use the imported exception type as a GIL Ref.
127
+ ///
128
+ /// This is useful only during migration as a way to avoid generating needless code.
129
+ #[ macro_export]
130
+ macro_rules! import_exception_bound {
131
+ ( $module: expr, $name: ident) => {
132
+ /// A Rust type representing an exception defined in Python code.
133
+ ///
134
+ /// This type was created by the [`pyo3::import_exception_bound!`] macro - see its documentation
135
+ /// for more information.
136
+ ///
137
+ /// [`pyo3::import_exception_bound!`]: https://docs.rs/pyo3/latest/pyo3/macro.import_exception.html "import_exception in pyo3"
138
+ #[ repr( transparent) ]
139
+ #[ allow( non_camel_case_types) ] // E.g. `socket.herror`
140
+ pub struct $name( $crate:: PyAny ) ;
141
+
142
+ $crate:: impl_exception_boilerplate_bound!( $name) ;
143
+
144
+ // FIXME remove this: was necessary while `PyTypeInfo` requires `HasPyGilRef`,
145
+ // should change in 0.22.
146
+ unsafe impl $crate:: type_object:: HasPyGilRef for $name {
147
+ type AsRefTarget = $crate:: PyAny ;
148
+ }
149
+
150
+ $crate:: pyobject_native_type_info!(
151
+ $name,
152
+ $name:: type_object_raw,
153
+ :: std:: option:: Option :: Some ( stringify!( $module) )
154
+ ) ;
155
+
156
+ impl $crate:: types:: DerefToPyAny for $name { }
157
+
158
+ impl $name {
159
+ fn type_object_raw( py: $crate:: Python <' _>) -> * mut $crate:: ffi:: PyTypeObject {
160
+ use $crate:: types:: PyTypeMethods ;
161
+ static TYPE_OBJECT : $crate:: impl_:: exceptions:: ImportedExceptionTypeObject =
162
+ $crate:: impl_:: exceptions:: ImportedExceptionTypeObject :: new(
163
+ stringify!( $module) ,
164
+ stringify!( $name) ,
165
+ ) ;
166
+ TYPE_OBJECT . get( py) . as_type_ptr( )
136
167
}
137
168
}
138
169
} ;
@@ -849,8 +880,8 @@ mod tests {
849
880
use crate :: types:: { IntoPyDict , PyDict } ;
850
881
use crate :: { PyErr , PyNativeType } ;
851
882
852
- import_exception ! ( socket, gaierror) ;
853
- import_exception ! ( email. errors, MessageError ) ;
883
+ import_exception_bound ! ( socket, gaierror) ;
884
+ import_exception_bound ! ( email. errors, MessageError ) ;
854
885
855
886
#[ test]
856
887
fn test_check_exception ( ) {
0 commit comments