You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: guide/src/migration.md
+118-1Lines changed: 118 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -74,7 +74,124 @@ Python::with_gil(|py| {
74
74
});
75
75
```
76
76
77
-
### `PyType::name` is now `PyType::qualname`
77
+
### `Iter(A)NextOutput` are deprecated
78
+
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.
80
+
81
+
Starting with an implementation of a Python iterator using `IterNextOutput`, e.g.
If returning `"done"` via `StopIteration` is not really required, this should be written as
107
+
108
+
```rust
109
+
usepyo3::prelude::*;
110
+
111
+
#[pyclass]
112
+
structPyClassIter {
113
+
count:usize,
114
+
}
115
+
116
+
#[pymethods]
117
+
implPyClassIter {
118
+
fn__next__(&mutself) ->Option<usize> {
119
+
ifself.count <5 {
120
+
self.count +=1;
121
+
Some(self.count)
122
+
} else {
123
+
None
124
+
}
125
+
}
126
+
}
127
+
```
128
+
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.
130
+
131
+
Alternatively, the implementation can also be done as it would in Python itself, i.e. by "raising" a `StopIteration` exception
132
+
133
+
```rust
134
+
usepyo3::prelude::*;
135
+
usepyo3::exceptions::PyStopIteration;
136
+
137
+
#[pyclass]
138
+
structPyClassIter {
139
+
count:usize,
140
+
}
141
+
142
+
#[pymethods]
143
+
implPyClassIter {
144
+
fn__next__(&mutself) ->PyResult<usize> {
145
+
ifself.count <5 {
146
+
self.count +=1;
147
+
Ok(self.count)
148
+
} else {
149
+
Err(PyStopIteration::new_err("done"))
150
+
}
151
+
}
152
+
}
153
+
```
154
+
155
+
Finally, an asynchronous iterator can directly return an awaitable without confusing wrapping
156
+
157
+
```rust
158
+
usepyo3::prelude::*;
159
+
160
+
#[pyclass]
161
+
structPyClassAwaitable {
162
+
number:usize,
163
+
}
164
+
165
+
#[pymethods]
166
+
implPyClassAwaitable {
167
+
fn__next__(&self) ->usize {
168
+
self.number
169
+
}
170
+
171
+
fn__await__(slf:Py<Self>) ->Py<Self> {
172
+
slf
173
+
}
174
+
}
175
+
176
+
#[pyclass]
177
+
structPyClassAsyncIter {
178
+
number:usize,
179
+
}
180
+
181
+
#[pymethods]
182
+
implPyClassAsyncIter {
183
+
fn__anext__(&mutself) ->PyClassAwaitable {
184
+
self.number +=1;
185
+
PyClassAwaitable { number:self.number }
186
+
}
187
+
188
+
fn__aiter__(slf:Py<Self>) ->Py<Self> {
189
+
slf
190
+
}
191
+
}
192
+
```
193
+
194
+
### `PyType::name` has been renamed to `PyType::qualname`
78
195
79
196
`PyType::name` has been renamed to `PyType::qualname` to indicate that it does indeed return the [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name), matching the `__qualname__` attribute. The newly added `PyType::name` yields the full name including the module name now which corresponds to `__module__.__name__` on the level of attributes.
The `Iter(A)NextOutput` types are now deprecated and `__(a)next__` can directly return anything which can be converted into Python objects, i.e. awaitables do not need to be wrapped into `IterANextOutput` or `Option` any more. `Option` can still be used as well and returning `None` will trigger the fast path for `__next__`, stopping iteration without having to raise a `StopIteration` exception.
0 commit comments