diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index d34c92c24a..a1f7759fca 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -1712,6 +1712,22 @@ struct iterator_state { bool first_or_done; }; +template +struct type_caster> : + type_caster_base> { + using ValueType = decltype(*std::declval()); +public: + static constexpr auto name = _("Iterator[") + make_caster::name + _("]"); +}; + +template +struct type_caster> : + type_caster_base> { + using ValueType = decltype((*std::declval()).first); +public: + static constexpr auto name = _("Iterator[") + make_caster::name + _("]"); +}; + PYBIND11_NAMESPACE_END(detail) /// Makes a python iterator from a first and past-the-end C++ InputIterator. @@ -1720,7 +1736,8 @@ template ()), typename... Extra> -iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { +detail::iterator_state +make_iterator_ng(Iterator first, Sentinel last, Extra &&... extra) { typedef detail::iterator_state state; if (!detail::get_type_info(typeid(state), false)) { @@ -1738,8 +1755,7 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { return *s.it; }, std::forward(extra)..., Policy); } - - return cast(state{first, last, true}); + return state{first, last, true}; } /// Makes an python iterator over the keys (`.first`) of a iterator over pairs from a @@ -1749,7 +1765,8 @@ template ()).first), typename... Extra> -iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { +detail::iterator_state + make_key_iterator_ng(Iterator first, Sentinel last, Extra &&... extra) { typedef detail::iterator_state state; if (!detail::get_type_info(typeid(state), false)) { @@ -1768,23 +1785,66 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { }, std::forward(extra)..., Policy); } - return cast(state{first, last, true}); + return state{first, last, true}; +} + +/// Makes a python iterator from a first and past-the-end C++ InputIterator. +template ()), + typename... Extra> +PYBIND11_DEPRECATED("Superseded by make_iterator_ng") +iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) { + return cast(make_iterator_ng(first, last, std::forward(extra)...)); +} + +/// Makes a python iterator from a first and past-the-end C++ InputIterator. +template ()), + typename... Extra> +PYBIND11_DEPRECATED("Superseded by make_key_iterator_ng") +iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) { + return cast(make_key_iterator_ng(first, last, std::forward(extra)...)); +} + +template +detail::iterator_state())), decltype(std::end(std::declval())), false, Policy> +make_iterator_ng(Type &value, Extra &&... extra) { + return make_iterator_ng(std::begin(value), std::end(value), std::forward(extra)...); +} + +/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting +/// `std::begin()`/`std::end()` +template +detail::iterator_state())), decltype(std::end(std::declval())), true, Policy> +make_key_iterator_ng(Type &value, Extra &&... extra) { + return make_key_iterator_ng(std::begin(value), std::end(value), std::forward(extra)...); } /// Makes an iterator over values of an stl container or other container supporting /// `std::begin()`/`std::end()` template iterator make_iterator(Type &value, Extra&&... extra) { - return make_iterator(std::begin(value), std::end(value), extra...); + typename Type, typename... Extra> +PYBIND11_DEPRECATED("Superseded by make_iterator_ng") +iterator make_iterator(Type &value, Extra&&... extra) { + return cast(make_iterator_ng(value, std::forward(extra)...)); } /// Makes an iterator over the keys (`.first`) of a stl map-like container supporting /// `std::begin()`/`std::end()` template iterator make_key_iterator(Type &value, Extra&&... extra) { - return make_key_iterator(std::begin(value), std::end(value), extra...); + typename Type, typename... Extra> +PYBIND11_DEPRECATED("Superseded by make_key_iterator_ng") +iterator make_key_iterator(Type &value, Extra&&... extra) { + return cast(make_key_iterator(value, std::forward(extra)...)); } + template void implicitly_convertible() { struct set_flag { bool &flag; diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index 61b94b6220..fa319199c0 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -313,7 +313,7 @@ void vector_accessor(enable_if_t::value, Class_> &cl) cl.def("__iter__", [](Vector &v) { - return make_iterator< + return make_iterator_ng< return_value_policy::reference_internal, ItType, ItType, T&>( v.begin(), v.end()); }, @@ -340,7 +340,7 @@ void vector_accessor(enable_if_t::value, Class_> &cl) cl.def("__iter__", [](Vector &v) { - return make_iterator< + return make_iterator_ng< return_value_policy::copy, ItType, ItType, T>( v.begin(), v.end()); }, @@ -608,12 +608,12 @@ class_ bind_map(handle scope, const std::string &name, Args&&. ); cl.def("__iter__", - [](Map &m) { return make_key_iterator(m.begin(), m.end()); }, + [](Map &m) { return make_key_iterator_ng(m.begin(), m.end()); }, keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ ); cl.def("items", - [](Map &m) { return make_iterator(m.begin(), m.end()); }, + [](Map &m) { return make_iterator_ng(m.begin(), m.end()); }, keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */ ); diff --git a/tests/test_opaque_types.cpp b/tests/test_opaque_types.cpp index 0d20d9a01c..499da18b8d 100644 --- a/tests/test_opaque_types.cpp +++ b/tests/test_opaque_types.cpp @@ -30,7 +30,7 @@ TEST_SUBMODULE(opaque_types, m) { .def("back", (std::string &(StringList::*)()) &StringList::back) .def("__len__", [](const StringList &v) { return v.size(); }) .def("__iter__", [](StringList &v) { - return py::make_iterator(v.begin(), v.end()); + return py::make_iterator_ng(v.begin(), v.end()); }, py::keep_alive<0, 1>()); class ClassWithSTLVecProperty { diff --git a/tests/test_sequences_and_iterators.cpp b/tests/test_sequences_and_iterators.cpp index 05f999bb3b..7a01d32287 100644 --- a/tests/test_sequences_and_iterators.cpp +++ b/tests/test_sequences_and_iterators.cpp @@ -189,7 +189,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) { }) .def("__len__", &Sequence::size) /// Optional sequence protocol operations - .def("__iter__", [](const Sequence &s) { return py::make_iterator(s.begin(), s.end()); }, + .def("__iter__", [](const Sequence &s) { return py::make_iterator_ng(s.begin(), s.end()); }, py::keep_alive<0, 1>() /* Essential: keep object alive while iterator exists */) .def("__contains__", [](const Sequence &s, float v) { return s.contains(v); }) .def("__reversed__", [](const Sequence &s) -> Sequence { return s.reversed(); }) @@ -249,9 +249,9 @@ TEST_SUBMODULE(sequences_and_iterators, m) { }) .def("__setitem__", &StringMap::set) .def("__len__", &StringMap::size) - .def("__iter__", [](const StringMap &map) { return py::make_key_iterator(map.begin(), map.end()); }, + .def("__iter__", [](const StringMap &map) { return py::make_key_iterator_ng(map.begin(), map.end()); }, py::keep_alive<0, 1>()) - .def("items", [](const StringMap &map) { return py::make_iterator(map.begin(), map.end()); }, + .def("items", [](const StringMap &map) { return py::make_iterator_ng(map.begin(), map.end()); }, py::keep_alive<0, 1>()) ; @@ -266,10 +266,10 @@ TEST_SUBMODULE(sequences_and_iterators, m) { py::class_(m, "IntPairs") .def(py::init>>()) .def("nonzero", [](const IntPairs& s) { - return py::make_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + return py::make_iterator_ng(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) .def("nonzero_keys", [](const IntPairs& s) { - return py::make_key_iterator(NonZeroIterator>(s.begin()), NonZeroSentinel()); + return py::make_key_iterator_ng(NonZeroIterator>(s.begin()), NonZeroSentinel()); }, py::keep_alive<0, 1>()) ; @@ -345,12 +345,12 @@ TEST_SUBMODULE(sequences_and_iterators, m) { // test_iterator_passthrough // #181: iterator passthrough did not compile m.def("iterator_passthrough", [](py::iterator s) -> py::iterator { - return py::make_iterator(std::begin(s), std::end(s)); + return py::cast(py::make_iterator_ng(std::begin(s), std::end(s))); }); // test_iterator_rvp // #388: Can't make iterators via make_iterator() with different r/v policies static std::vector list = { 1, 2, 3 }; - m.def("make_iterator_1", []() { return py::make_iterator(list); }); - m.def("make_iterator_2", []() { return py::make_iterator(list); }); + m.def("make_iterator_1", []() { return py::make_iterator_ng(list); }); + m.def("make_iterator_2", []() { return py::make_iterator_ng(list); }); } diff --git a/tests/test_stl_binders.py b/tests/test_stl_binders.py index 27b326f070..a16d028d38 100644 --- a/tests/test_stl_binders.py +++ b/tests/test_stl_binders.py @@ -277,3 +277,32 @@ def test_map_delitem(): del um['ua'] assert sorted(list(um)) == ['ub'] assert sorted(list(um.items())) == [('ub', 2.6)] + + +def test_map_docstrings(doc): + assert (doc(m.MapStringDouble.__iter__) == + "__iter__(self: m.stl_binders.MapStringDouble)" + " -> Iterator[str]") + assert (doc(m.MapStringDouble.items) == + "items(self: m.stl_binders.MapStringDouble)" + " -> Iterator[Tuple[str, float]]") + assert (doc(m.UnorderedMapStringDouble.__iter__) == + "__iter__(self: m.stl_binders.UnorderedMapStringDouble)" + " -> Iterator[str]\n") + assert (doc(m.UnorderedMapStringDouble.items) == + "items(self: m.stl_binders.UnorderedMapStringDouble)" + " -> Iterator[Tuple[str, float]]\n") + + +def test_vector_docstrings(doc): + assert (doc(m.VectorInt.__iter__) == + "__iter__(self: m.stl_binders.VectorInt)" + " -> Iterator[int]\n") + + +@pytest.unsupported_on_pypy +@pytest.requires_numpy +def test_vector_docstring2(doc): + assert (doc(m.VectorStruct.__iter__) == + "__iter__(self: m.stl_binders.VectorStruct)" + " -> Iterator[m.stl_binders.VStruct]")