@@ -383,22 +383,42 @@ fn lazy_into_normalized_ffi_tuple(
383383}
384384
385385/// Raises a "lazy" exception state into the Python interpreter.
386- ///
387- /// In principle this could be split in two; first a function to create an exception
388- /// in a normalized state, and then a call to `PyErr_SetRaisedException` to raise it.
389- ///
390- /// This would require either moving some logic from C to Rust, or requesting a new
391- /// API in CPython.
392386fn raise_lazy ( py : Python < ' _ > , lazy : Box < PyErrStateLazyFn > ) {
393387 let PyErrStateLazyFnOutput { ptype, pvalue } = lazy ( py) ;
388+
394389 unsafe {
395390 if ffi:: PyExceptionClass_Check ( ptype. as_ptr ( ) ) == 0 {
396391 ffi:: PyErr_SetString (
397392 PyTypeError :: type_object_raw ( py) . cast ( ) ,
398393 c"exceptions must derive from BaseException" . as_ptr ( ) ,
399- )
394+ ) ;
400395 } else {
401- ffi:: PyErr_SetObject ( ptype. as_ptr ( ) , pvalue. as_ptr ( ) )
396+ #[ cfg( not( Py_3_12 ) ) ]
397+ ffi:: PyErr_SetObject ( ptype. as_ptr ( ) , pvalue. as_ptr ( ) ) ;
398+
399+ #[ cfg( Py_3_12 ) ]
400+ {
401+ let exc = if ffi:: PyExceptionInstance_Check ( pvalue. as_ptr ( ) ) != 0 {
402+ // If it's already an exception instance, keep it as-is.
403+ ffi:: Py_NewRef ( pvalue. as_ptr ( ) )
404+ } else if pvalue. as_ptr ( ) == ffi:: Py_None ( ) {
405+ // If the value is None, call the type with no arguments.
406+ ffi:: PyObject_CallNoArgs ( ptype. as_ptr ( ) )
407+ } else if ffi:: PyTuple_Check ( pvalue. as_ptr ( ) ) != 0 {
408+ // If the value is a tuple, unpack it as arguments to the type.
409+ ffi:: PyObject_Call ( ptype. as_ptr ( ) , pvalue. as_ptr ( ) , std:: ptr:: null_mut ( ) )
410+ } else {
411+ // Fallback: type(value)
412+ ffi:: compat:: PyObject_CallOneArg ( ptype. as_ptr ( ) , pvalue. as_ptr ( ) )
413+ } ;
414+
415+ if exc. is_null ( ) {
416+ // Exception constructor raised an exception, so propagate that instead of the original one.
417+ return ;
418+ }
419+
420+ ffi:: PyErr_SetRaisedException ( exc) ;
421+ }
402422 }
403423 }
404424}
0 commit comments