捕获和转换py.allow_threads闭包内引发的错误?

Catch and transform error raised inside py.allow_threads closure?

提问人:mike rodent 提问时间:10/15/2023 最后编辑:mike rodent 更新时间:10/15/2023 访问量:44

问:

我有一个 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_threadsUngil

显然,一个简单的解决方案是在这个函数中有一个命令,并在另一个被调用的函数中执行所有多个命令,该函数返回,然后这个 / 块处理这里的事情,如图所示。但我只是想知道是否有可能在这里,在这个函数中捕捉到这个闭包之外的东西。Result<((usize, usize)), Box<dyn std::error::Error>>OkErr

编辑: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”函数。

Rust 错误处理 闭包 PYO3

评论

0赞 cafce25 10/15/2023
你不只需要把电话放在比赛中吗?match py.allow_threads(...) { ... }
0赞 mike rodent 10/15/2023
谢谢。刚刚试过,在关闭“}”之后使用 / 块 1) 和在关闭“)”之后使用 2) 块。两者都不编译。OkErr
0赞 cafce25 10/15/2023
为什么在 ?胳膊进去了.}{}match py.allow_threads(...) { Ok(tup) => tup, Err(e) => {...}}
0赞 mike rodent 10/15/2023
是的,正如我所说,我也尝试过。我得到“ 无法将错误转换为 ” 和 “^ 没有实现特征?pyo3::PyErrFrom<Box<dyn StdError>>pyo3::PyErr"
0赞 cafce25 10/15/2023
此外,如果某些内容无法编译,请将编译器错误添加到问题中

答: 暂无答案