Skip to content

Commit 5528895

Browse files
committed
Relax the error type in the Result<Option<T>, E>> specializations for __(a)next__.
1 parent a605308 commit 5528895

File tree

2 files changed

+15
-11
lines changed

2 files changed

+15
-11
lines changed

guide/src/migration.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Python::with_gil(|py| {
7676

7777
### `Iter(A)NextOutput` are deprecated
7878

79-
The `__next__` and `__anext__` magic methods can now return any type convertible into Python objects directly just like all other `#[pymethods]`. The `IterNextOutput` used by `__next__` and `IterANextOutput` used by `__anext__` are subsequently deprecated. Most importantly, this change allows returning an awaitable from `__anext__` without non-sensically wrapping it into `Yield` or `Some`. Only the return types `Option<T>` and `PyResult<Option<T>>` are still handled in a special manner where `Some(val)` yields `val` and `None` stops iteration.
79+
The `__next__` and `__anext__` magic methods can now return any type convertible into Python objects directly just like all other `#[pymethods]`. The `IterNextOutput` used by `__next__` and `IterANextOutput` used by `__anext__` are subsequently deprecated. Most importantly, this change allows returning an awaitable from `__anext__` without non-sensically wrapping it into `Yield` or `Some`. Only the return types `Option<T>` and `Result<Option<T>, E>` are still handled in a special manner where `Some(val)` yields `val` and `None` stops iteration.
8080

8181
Starting with an implementation of a Python iterator using `IterNextOutput`, e.g.
8282

@@ -126,7 +126,7 @@ impl PyClassIter {
126126
}
127127
```
128128

129-
This form also has additional benefits: It has already worked in previous PyO3 versions, it matches the signature of Rust's [`Iterator` trait](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html) and it allows using a fast path in CPython which completely avoids the cost of raising a `StopIteration` exception. Note that using [`Option::transpose`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose) and the `PyResult<Option<T>>` variant, this form can also be used to wrap fallible iterators.
129+
This form also has additional benefits: It has already worked in previous PyO3 versions, it matches the signature of Rust's [`Iterator` trait](https://doc.rust-lang.org/stable/std/iter/trait.Iterator.html) and it allows using a fast path in CPython which completely avoids the cost of raising a `StopIteration` exception. Note that using [`Option::transpose`](https://doc.rust-lang.org/stable/std/option/enum.Option.html#method.transpose) and the `Result<Option<T>, E>` variant, this form can also be used to wrap fallible iterators.
130130

131131
Alternatively, the implementation can also be done as it would in Python itself, i.e. by "raising" a `StopIteration` exception
132132

src/impl_/pymethods.rs

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ use crate::exceptions::PyStopAsyncIteration;
33
use crate::gil::LockGIL;
44
use crate::impl_::panic::PanicTrap;
55
use crate::internal_tricks::extract_c_string;
6-
use crate::{ffi, PyAny, PyCell, PyClass, PyObject, PyResult, PyTraverseError, PyVisit, Python};
6+
use crate::{
7+
ffi, PyAny, PyCell, PyClass, PyErr, PyObject, PyResult, PyTraverseError, PyVisit, Python,
8+
};
79
use std::borrow::Cow;
810
use std::ffi::CStr;
911
use std::fmt;
@@ -358,18 +360,19 @@ pub struct IterResultOptionTag;
358360

359361
impl IterResultOptionTag {
360362
#[inline]
361-
pub fn convert<Value>(
363+
pub fn convert<Value, Error>(
362364
self,
363365
py: Python<'_>,
364-
value: PyResult<Option<Value>>,
366+
value: Result<Option<Value>, Error>,
365367
) -> PyResult<*mut ffi::PyObject>
366368
where
367369
Value: IntoPyCallbackOutput<*mut ffi::PyObject>,
370+
Error: Into<PyErr>,
368371
{
369372
match value {
370373
Ok(Some(value)) => value.convert(py),
371374
Ok(None) => Ok(null_mut()),
372-
Err(err) => Err(err),
375+
Err(err) => Err(err.into()),
373376
}
374377
}
375378
}
@@ -381,7 +384,7 @@ pub trait IterResultOptionKind {
381384
}
382385
}
383386

384-
impl<Value> IterResultOptionKind for PyResult<Option<Value>> {}
387+
impl<Value, Error> IterResultOptionKind for Result<Option<Value>, Error> {}
385388

386389
// Autoref-based specialization for handling `__anext__` returning `Option`
387390

@@ -438,18 +441,19 @@ pub struct AsyncIterResultOptionTag;
438441

439442
impl AsyncIterResultOptionTag {
440443
#[inline]
441-
pub fn convert<Value>(
444+
pub fn convert<Value, Error>(
442445
self,
443446
py: Python<'_>,
444-
value: PyResult<Option<Value>>,
447+
value: Result<Option<Value>, Error>,
445448
) -> PyResult<*mut ffi::PyObject>
446449
where
447450
Value: IntoPyCallbackOutput<*mut ffi::PyObject>,
451+
Error: Into<PyErr>,
448452
{
449453
match value {
450454
Ok(Some(value)) => value.convert(py),
451455
Ok(None) => Err(PyStopAsyncIteration::new_err(())),
452-
Err(err) => Err(err),
456+
Err(err) => Err(err.into()),
453457
}
454458
}
455459
}
@@ -461,4 +465,4 @@ pub trait AsyncIterResultOptionKind {
461465
}
462466
}
463467

464-
impl<Value> AsyncIterResultOptionKind for PyResult<Option<Value>> {}
468+
impl<Value, Error> AsyncIterResultOptionKind for Result<Option<Value>, Error> {}

0 commit comments

Comments
 (0)