Skip to content

Render typed iterators (e.g. Iterator[int]) in docstrings #2244

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 29 additions & 7 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -1680,6 +1680,23 @@ struct iterator_state {
bool first_or_done;
};

template<typename Iterator, typename Sentinel, return_value_policy Policy>
struct type_caster<iterator_state<Iterator, Sentinel, false, Policy>> :
type_caster_base<iterator_state<Iterator, Sentinel, false, Policy>> {
using ValueType = decltype(*std::declval<Iterator>());
public:
static constexpr auto name = _("Iterator[") + make_caster<ValueType>::name + _("]");
};

template<typename Iterator, typename Sentinel, return_value_policy Policy>
struct type_caster<iterator_state<Iterator, Sentinel, true, Policy>> :
type_caster_base<iterator_state<Iterator, Sentinel, true, Policy>> {
using ValueType = decltype((*std::declval<Iterator>()).first);
public:
static constexpr auto name = _("Iterator[") + make_caster<ValueType>::name + _("]");
};


NAMESPACE_END(detail)

/// Makes a python iterator from a first and past-the-end C++ InputIterator.
Expand All @@ -1688,7 +1705,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Sentinel,
typename ValueType = decltype(*std::declval<Iterator>()),
typename... Extra>
iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
detail::iterator_state<Iterator, Sentinel, false, Policy>
make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
typedef detail::iterator_state<Iterator, Sentinel, false, Policy> state;

if (!detail::get_type_info(typeid(state), false)) {
Expand All @@ -1706,8 +1724,7 @@ iterator make_iterator(Iterator first, Sentinel last, Extra &&... extra) {
return *s.it;
}, std::forward<Extra>(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
Expand All @@ -1717,7 +1734,8 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
typename Sentinel,
typename KeyType = decltype((*std::declval<Iterator>()).first),
typename... Extra>
iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
detail::iterator_state<Iterator, Sentinel, true, Policy>
make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
typedef detail::iterator_state<Iterator, Sentinel, true, Policy> state;

if (!detail::get_type_info(typeid(state), false)) {
Expand All @@ -1736,20 +1754,24 @@ iterator make_key_iterator(Iterator first, Sentinel last, Extra &&... extra) {
}, std::forward<Extra>(extra)..., Policy);
}

return cast(state{first, last, true});
return state{first, last, true};
}

/// Makes an iterator over values of an stl container or other container supporting
/// `std::begin()`/`std::end()`
template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type, typename... Extra> iterator make_iterator(Type &value, Extra&&... extra) {
typename Type, typename... Extra>
detail::iterator_state<decltype(std::begin(std::declval<Type&>())), decltype(std::end(std::declval<Type&>())), false, Policy>
make_iterator(Type &value, Extra&&... extra) {
return make_iterator<Policy>(std::begin(value), std::end(value), extra...);
}

/// Makes an iterator over the keys (`.first`) of a stl map-like container supporting
/// `std::begin()`/`std::end()`
template <return_value_policy Policy = return_value_policy::reference_internal,
typename Type, typename... Extra> iterator make_key_iterator(Type &value, Extra&&... extra) {
typename Type, typename... Extra>
detail::iterator_state<decltype(std::begin(std::declval<Type&>())), decltype(std::end(std::declval<Type&>())), true, Policy>
make_key_iterator(Type &value, Extra&&... extra) {
return make_key_iterator<Policy>(std::begin(value), std::end(value), extra...);
}

Expand Down
2 changes: 1 addition & 1 deletion tests/test_sequences_and_iterators.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,7 @@ TEST_SUBMODULE(sequences_and_iterators, m) {

// test_iterator_passthrough
// #181: iterator passthrough did not compile
m.def("iterator_passthrough", [](py::iterator s) -> py::iterator {
m.def("iterator_passthrough", [](py::iterator s) {
return py::make_iterator(std::begin(s), std::end(s));
});

Expand Down
29 changes: 29 additions & 0 deletions tests/test_stl_binders.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,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]")