always normalize exceptions before raising
This commit is contained in:
parent
42f9cd4476
commit
1e8833e15e
|
@ -0,0 +1 @@
|
||||||
|
Fix `IterNextOutput::Return` not returning a value on PyPy.
|
|
@ -1,5 +1,6 @@
|
||||||
hypothesis>=3.55
|
hypothesis>=3.55
|
||||||
pytest>=6.0
|
pytest>=6.0
|
||||||
|
pytest-asyncio>=0.21
|
||||||
pytest-benchmark>=3.4
|
pytest-benchmark>=3.4
|
||||||
psutil>=5.6
|
psutil>=5.6
|
||||||
typing_extensions>=4.0.0
|
typing_extensions>=4.0.0
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
//! The following classes are examples of objects which implement Python's
|
||||||
|
//! awaitable protocol.
|
||||||
|
//!
|
||||||
|
//! Both IterAwaitable and FutureAwaitable will return a value immediately
|
||||||
|
//! when awaited, see guide examples related to pyo3-asyncio for ways
|
||||||
|
//! to suspend tasks and await results.
|
||||||
|
|
||||||
|
use pyo3::{prelude::*, pyclass::IterNextOutput};
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub(crate) struct IterAwaitable {
|
||||||
|
result: Option<PyResult<PyObject>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl IterAwaitable {
|
||||||
|
#[new]
|
||||||
|
fn new(result: PyObject) -> Self {
|
||||||
|
IterAwaitable {
|
||||||
|
result: Some(Ok(result)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __await__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> {
|
||||||
|
pyself
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __iter__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> {
|
||||||
|
pyself
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __next__(&mut self, py: Python<'_>) -> PyResult<IterNextOutput<PyObject, PyObject>> {
|
||||||
|
match self.result.take() {
|
||||||
|
Some(res) => match res {
|
||||||
|
Ok(v) => Ok(IterNextOutput::Return(v)),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
},
|
||||||
|
_ => Ok(IterNextOutput::Yield(py.None())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyclass]
|
||||||
|
pub(crate) struct FutureAwaitable {
|
||||||
|
#[pyo3(get, set, name = "_asyncio_future_blocking")]
|
||||||
|
py_block: bool,
|
||||||
|
result: Option<PyResult<PyObject>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymethods]
|
||||||
|
impl FutureAwaitable {
|
||||||
|
#[new]
|
||||||
|
fn new(result: PyObject) -> Self {
|
||||||
|
FutureAwaitable {
|
||||||
|
py_block: false,
|
||||||
|
result: Some(Ok(result)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __await__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> {
|
||||||
|
pyself
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __iter__(pyself: PyRef<'_, Self>) -> PyRef<'_, Self> {
|
||||||
|
pyself
|
||||||
|
}
|
||||||
|
|
||||||
|
fn __next__(
|
||||||
|
mut pyself: PyRefMut<'_, Self>,
|
||||||
|
) -> PyResult<IterNextOutput<PyRefMut<'_, Self>, PyObject>> {
|
||||||
|
match pyself.result {
|
||||||
|
Some(_) => match pyself.result.take().unwrap() {
|
||||||
|
Ok(v) => Ok(IterNextOutput::Return(v)),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
},
|
||||||
|
_ => Ok(IterNextOutput::Yield(pyself)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pymodule]
|
||||||
|
pub fn awaitable(_py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_class::<IterAwaitable>()?;
|
||||||
|
m.add_class::<FutureAwaitable>()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ use pyo3::prelude::*;
|
||||||
use pyo3::types::PyDict;
|
use pyo3::types::PyDict;
|
||||||
use pyo3::wrap_pymodule;
|
use pyo3::wrap_pymodule;
|
||||||
|
|
||||||
|
pub mod awaitable;
|
||||||
pub mod buf_and_str;
|
pub mod buf_and_str;
|
||||||
pub mod comparisons;
|
pub mod comparisons;
|
||||||
pub mod datetime;
|
pub mod datetime;
|
||||||
|
@ -17,6 +18,7 @@ pub mod subclassing;
|
||||||
|
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
m.add_wrapped(wrap_pymodule!(awaitable::awaitable))?;
|
||||||
#[cfg(not(Py_LIMITED_API))]
|
#[cfg(not(Py_LIMITED_API))]
|
||||||
m.add_wrapped(wrap_pymodule!(buf_and_str::buf_and_str))?;
|
m.add_wrapped(wrap_pymodule!(buf_and_str::buf_and_str))?;
|
||||||
m.add_wrapped(wrap_pymodule!(comparisons::comparisons))?;
|
m.add_wrapped(wrap_pymodule!(comparisons::comparisons))?;
|
||||||
|
@ -37,6 +39,7 @@ fn pyo3_pytests(py: Python<'_>, m: &PyModule) -> PyResult<()> {
|
||||||
|
|
||||||
let sys = PyModule::import(py, "sys")?;
|
let sys = PyModule::import(py, "sys")?;
|
||||||
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?;
|
let sys_modules: &PyDict = sys.getattr("modules")?.downcast()?;
|
||||||
|
sys_modules.set_item("pyo3_pytests.awaitable", m.getattr("awaitable")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?;
|
sys_modules.set_item("pyo3_pytests.buf_and_str", m.getattr("buf_and_str")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?;
|
sys_modules.set_item("pyo3_pytests.comparisons", m.getattr("comparisons")?)?;
|
||||||
sys_modules.set_item("pyo3_pytests.datetime", m.getattr("datetime")?)?;
|
sys_modules.set_item("pyo3_pytests.datetime", m.getattr("datetime")?)?;
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from pyo3_pytests.awaitable import IterAwaitable, FutureAwaitable
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_iter_awaitable():
|
||||||
|
assert await IterAwaitable(5) == 5
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_future_awaitable():
|
||||||
|
assert await FutureAwaitable(5) == 5
|
|
@ -156,18 +156,7 @@ impl PyErrState {
|
||||||
#[cfg(not(Py_3_12))]
|
#[cfg(not(Py_3_12))]
|
||||||
pub(crate) fn restore(self, py: Python<'_>) {
|
pub(crate) fn restore(self, py: Python<'_>) {
|
||||||
let (ptype, pvalue, ptraceback) = match self {
|
let (ptype, pvalue, ptraceback) = match self {
|
||||||
PyErrState::Lazy(lazy) => {
|
PyErrState::Lazy(lazy) => lazy_into_normalized_ffi_tuple(py, lazy),
|
||||||
let PyErrStateLazyFnOutput { ptype, pvalue } = lazy(py);
|
|
||||||
if unsafe { ffi::PyExceptionClass_Check(ptype.as_ptr()) } == 0 {
|
|
||||||
(
|
|
||||||
PyTypeError::type_object_raw(py).cast(),
|
|
||||||
PyString::new(py, "exceptions must derive from BaseException").into_ptr(),
|
|
||||||
std::ptr::null_mut(),
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
(ptype.into_ptr(), pvalue.into_ptr(), std::ptr::null_mut())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
PyErrState::FfiTuple {
|
PyErrState::FfiTuple {
|
||||||
ptype,
|
ptype,
|
||||||
pvalue,
|
pvalue,
|
||||||
|
|
Loading…
Reference in New Issue