Handle all py::iterator errors

Before this, `py::iterator` didn't do any error handling, so code like:
```c++
for (auto item : py::int_(1)) {
    // ...
}
```
would just silently skip the loop. The above now throws `TypeError` as
expected. This is a breaking behavior change, but any code which relied
on the silent skip was probably broken anyway.

Also, errors returned by `PyIter_Next()` are now properly handled.
This commit is contained in:
Dean Moldovan
2017-02-08 14:31:49 +01:00
committed by Wenzel Jakob
parent cecb577a19
commit f7685826e2
3 changed files with 92 additions and 28 deletions

View File

@@ -169,7 +169,8 @@ bool operator==(const NonZeroIterator<std::pair<A, B>>& it, const NonZeroSentine
return !(*it).first || !(*it).second;
}
test_initializer sequences_and_iterators([](py::module &m) {
test_initializer sequences_and_iterators([](py::module &pm) {
auto m = pm.def_submodule("sequences_and_iterators");
py::class_<Sequence> seq(m, "Sequence");
@@ -272,4 +273,21 @@ test_initializer sequences_and_iterators([](py::module &m) {
On the actual Sequence object, the iterator would be constructed as follows:
.def("__iter__", [](py::object s) { return PySequenceIterator(s.cast<const Sequence &>(), s); })
#endif
m.def("object_to_list", [](py::object o) {
auto l = py::list();
for (auto item : o) {
l.append(item);
}
return l;
});
m.def("iterator_to_list", [](py::iterator it) {
auto l = py::list();
while (it != py::iterator::sentinel()) {
l.append(*it);
++it;
}
return l;
});
});