Interrupt running code from another thread by raising an exception, similar to how Python signal handlers work #3635
-
I'm trying to reproduce the behavior of Python signal handlers when an exception is raised inside of them, from Rust. It will raise the exception as soon as possible in whatever code is currently running. I have a little demo setup here, but it's not working. The Python loop is not interrupted with the exception injected by use pyo3::{Python, exceptions::PyTypeError, PyErr};
#[tokio::main]
async fn main() -> eyre::Result<()> {
tokio::task::spawn_blocking(move || {
Python::with_gil(|py| {
py.run(r#"
import time;
for i in range(15):
time.sleep(1)
print('post sleep python')"#, None, None).expect("");
println!("post sleep rust");
})
});
tokio::signal::ctrl_c().await?;
Python::with_gil(|py| {
println!("attempting to throw");
PyTypeError::new_err("Error").restore(py);
assert!(PyErr::occurred(py));
drop(PyErr::fetch(py));
println!("thrown");
});
Ok(())
} The output looks like this:
No exception is raised, and the Python code completes after the loop is finished. Is it possible to get this running properly? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
Why are you doing a PyErr:: fetch which clears the exception from the interpreter state? Does it have differently if you leave that line out? |
Beta Was this translation helpful? Give feedback.
Like the text says, that example shows how to "write and fetch" exceptions, it's probably not the best example for the chapter heading.
But I have to apologize, I just now looked closer at your example and I didn't consider before that Tokio's
spawn_blocking
must obviously run its closure in a thread pool, so the raising thread is not the thread you want an exception to be run in.This can be done but is not encouraged. You'd need to use
PyThreadState_SetAsyncExc
like shown here but it is not wrapped in PyO3, so you need to work with the rawffi
binding.A much better solution would be to use a flag, event, queue or other synchronization method to signal the other thread to stop.