提问人:mike rodent 提问时间:10/15/2023 最后编辑:mike rodent 更新时间:10/15/2023 访问量:44
捕获和转换py.allow_threads闭包内引发的错误?
Catch and transform error raised inside py.allow_threads closure?
问:
我有一个 PyO3 函数,如下所示:
#[pyfunction]
fn update_index(py: Python, dir_root_path_str: String, index_name: String, n_docx_docs: usize)
-> PyResult<(usize, usize)> {
py.allow_threads(move || {
...
let (docx_hit_objs_for_processing, docx_hit_objs_for_deletion) = match op_handler.analyse_index_correspondence() {
Ok((docx_hit_objs_for_processing, docx_hit_objs_for_deletion)) => (docx_hit_objs_for_processing, docx_hit_objs_for_deletion),
Err(e) => {return Err(PyErr::new::<PyTypeError, _>(e.to_string()))}
};
...
上述方法的签名:
fn analyse_index_correspondence(&self) ->
Result<(Vec<DocxHitObject>, Vec<DocxHitObject>), Box<dyn std::error::Error>>
任何对 PyO3 相当熟悉的人都会理解这个问题:错误必须被“包装”或“转换”才能作为可接受的错误传递(这将导致 Python 代码中的异常)。PyResult
问题在于,此闭包中有几个命令,每个命令都必须对错误进行包装。所以我想知道是否有办法在闭包之外进行这种包装,这意味着我可以只使用 .我尝试过这样的事情:?
py.allow_threads(move || {
...
let (docx_hit_objs_for_processing, docx_hit_objs_for_deletion)
= op_handler.analyse_index_correspondence()?;
...
Ok((a, b))
}) match {
Ok(tuple) => Ok(tuple),
Err(e) => {Err(PyErr::new::<PyTypeError, _>(e.to_string()))}
}
}
这给出编译器错误:
error[E0277]: `?` couldn't convert the error to `pyo3::PyErr`
--> src\lib.rs:45:109
|
45 | let (docx_hit_objs_for_processing, docx_hit_objs_for_deletion) = op_handler.analyse_index_correspondence()?;
| ^ the trait `From<Box<dyn StdError>>` is not implemented for `pyo3::PyErr`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `From<T>`:
<pyo3::PyErr as From<&CancelledError>>
<pyo3::PyErr as From<&IncompleteReadError>>
<pyo3::PyErr as From<&InvalidStateError>>
<pyo3::PyErr as From<&LimitOverrunError>>
<pyo3::PyErr as From<&PanicException>>
<pyo3::PyErr as From<&PyArithmeticError>>
<pyo3::PyErr as From<&PyAssertionError>>
<pyo3::PyErr as From<&PyAttributeError>>
and 87 others
= note: required for `Result<_, pyo3::PyErr>` to implement `FromResidual<Result<Infallible, Box<dyn StdError>>>`
文档在这里。据说它的返回类型是 ,这让我很担心。有什么方法可以做到这一点吗?allow_threads
Ungil
显然,一个简单的解决方案是在这个函数中有一个命令,并在另一个被调用的函数中执行所有多个命令,该函数返回,然后这个 / 块处理这里的事情,如图所示。但我只是想知道是否有可能在这里,在这个函数中捕捉到这个闭包之外的东西。Result<((usize, usize)), Box<dyn std::error::Error>>
Ok
Err
编辑:cafce的建议
我尝试这样做:
py.allow_threads(move || -> Result<(usize, usize), Box<dyn std::error::Error>> {
...
这会产生以下编译器错误:
error[E0277]: `dyn StdError` cannot be sent between threads safely
--> src\lib.rs:27:5
|
27 | py.allow_threads(move || -> Result<(usize, usize), Box<dyn std::error::Error>> {
| ^^^^^^^^^^^^^ `dyn StdError` cannot be sent between threads safely
|
= help: the trait `Send` is not implemented for `dyn StdError`
= note: required for `Unique<dyn StdError>` to implement `Send`
= note: required because it appears within the type `Box<dyn Error>`
= note: required because it appears within the type `Result<(usize, usize), Box<dyn Error>>`
= note: required for `Result<(usize, usize), Box<dyn StdError>>` to implement `Ungil`
note: required by a bound in `pyo3::Python::<'py>::allow_threads`
--> D:\apps\rust\rust_1.70.0\.cargo\git\checkouts\pyo3-a22e69bc62b9f0fd\8dc3d2b\src\marker.rs:531:12
|
531 | T: Ungil,
| ^^^^^ required by this bound in `Python::<'py>::allow_threads`
error[E0308]: mismatched types
--> src\lib.rs:27:2
|
24 | -> PyResult<(usize, usize)> {
| ------------------------ expected `Result<(usize, usize), PyErr>` because of return type
我理解第二个错误。但关于第一个,我认为我在这里处于深水区。我想我只需要按照上面的建议调用第二个“纯 Rust”函数。
答: 暂无答案
评论
match py.allow_threads(...) { ... }
Ok
Err
}
{}
match py.allow_threads(...) { Ok(tup) => tup, Err(e) => {...}}
?
pyo3::PyErr
From<Box<dyn StdError>>
pyo3::PyErr
"