mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-21 20:55:11 +00:00
fix: <ranges>
support for py::tuple
and py::list
(#5314)
* feat: add `<ranges>` support for `py::tuple` and `py::list` * fix: format the code * fix: disable `ranges` in clang < 16 * refactor: move `<ranges>` test macro to `test_pytypes.h` * refactor: seperate `ranges` test into 3 funcs * style: compress the if statement * style: pre-commit fixes * style: better formatting --------- Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
7d85baa6a1
commit
2baf9d6833
@ -1259,6 +1259,7 @@ protected:
|
||||
using pointer = arrow_proxy<const handle>;
|
||||
|
||||
sequence_fast_readonly(handle obj, ssize_t n) : ptr(PySequence_Fast_ITEMS(obj.ptr()) + n) {}
|
||||
sequence_fast_readonly() = default;
|
||||
|
||||
// NOLINTNEXTLINE(readability-const-return-type) // PR #3263
|
||||
reference dereference() const { return *ptr; }
|
||||
@ -1281,6 +1282,7 @@ protected:
|
||||
using pointer = arrow_proxy<const sequence_accessor>;
|
||||
|
||||
sequence_slow_readwrite(handle obj, ssize_t index) : obj(obj), index(index) {}
|
||||
sequence_slow_readwrite() = default;
|
||||
|
||||
reference dereference() const { return {obj, static_cast<size_t>(index)}; }
|
||||
void increment() { ++index; }
|
||||
|
@ -13,6 +13,14 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
//__has_include has been part of C++17, no need to check it
|
||||
#if defined(PYBIND11_CPP20) && __has_include(<ranges>)
|
||||
# if !defined(PYBIND11_COMPILER_CLANG) || __clang_major__ >= 16 // llvm/llvm-project#52696
|
||||
# define PYBIND11_TEST_PYTYPES_HAS_RANGES
|
||||
# include <ranges>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace external {
|
||||
namespace detail {
|
||||
bool check(PyObject *o) { return PyFloat_Check(o) != 0; }
|
||||
@ -923,4 +931,59 @@ TEST_SUBMODULE(pytypes, m) {
|
||||
#else
|
||||
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
|
||||
#endif
|
||||
|
||||
#if defined(PYBIND11_TEST_PYTYPES_HAS_RANGES)
|
||||
|
||||
// test_tuple_ranges
|
||||
m.def("tuple_iterator_default_initialization", []() {
|
||||
using TupleIterator = decltype(std::declval<py::tuple>().begin());
|
||||
static_assert(std::random_access_iterator<TupleIterator>);
|
||||
return TupleIterator{} == TupleIterator{};
|
||||
});
|
||||
|
||||
m.def("transform_tuple_plus_one", [](py::tuple &tpl) {
|
||||
py::list ret{};
|
||||
for (auto it : tpl | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
|
||||
ret.append(py::int_(it));
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
// test_list_ranges
|
||||
m.def("list_iterator_default_initialization", []() {
|
||||
using ListIterator = decltype(std::declval<py::list>().begin());
|
||||
static_assert(std::random_access_iterator<ListIterator>);
|
||||
return ListIterator{} == ListIterator{};
|
||||
});
|
||||
|
||||
m.def("transform_list_plus_one", [](py::list &lst) {
|
||||
py::list ret{};
|
||||
for (auto it : lst | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
|
||||
ret.append(py::int_(it));
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
// test_dict_ranges
|
||||
m.def("dict_iterator_default_initialization", []() {
|
||||
using DictIterator = decltype(std::declval<py::dict>().begin());
|
||||
static_assert(std::forward_iterator<DictIterator>);
|
||||
return DictIterator{} == DictIterator{};
|
||||
});
|
||||
|
||||
m.def("transform_dict_plus_one", [](py::dict &dct) {
|
||||
py::list ret{};
|
||||
for (auto it : dct | std::views::transform([](auto &o) {
|
||||
return std::pair{py::cast<int>(o.first) + 1,
|
||||
py::cast<int>(o.second) + 1};
|
||||
})) {
|
||||
ret.append(py::make_tuple(py::int_(it.first), py::int_(it.second)));
|
||||
}
|
||||
return ret;
|
||||
});
|
||||
|
||||
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = true;
|
||||
#else
|
||||
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false;
|
||||
#endif
|
||||
}
|
||||
|
@ -1048,3 +1048,45 @@ def test_typevar(doc):
|
||||
assert doc(m.annotate_listT_to_T) == "annotate_listT_to_T(arg0: list[T]) -> T"
|
||||
|
||||
assert doc(m.annotate_object_to_T) == "annotate_object_to_T(arg0: object) -> T"
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
|
||||
reason="<ranges> not available.",
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("tested_tuple", "expected"),
|
||||
[((1,), [2]), ((3, 4), [4, 5]), ((7, 8, 9), [8, 9, 10])],
|
||||
)
|
||||
def test_tuple_ranges(tested_tuple, expected):
|
||||
assert m.tuple_iterator_default_initialization()
|
||||
assert m.transform_tuple_plus_one(tested_tuple) == expected
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
|
||||
reason="<ranges> not available.",
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("tested_list", "expected"), [([1], [2]), ([3, 4], [4, 5]), ([7, 8, 9], [8, 9, 10])]
|
||||
)
|
||||
def test_list_ranges(tested_list, expected):
|
||||
assert m.list_iterator_default_initialization()
|
||||
assert m.transform_list_plus_one(tested_list) == expected
|
||||
|
||||
|
||||
@pytest.mark.skipif(
|
||||
not m.defined_PYBIND11_TEST_PYTYPES_HAS_RANGES,
|
||||
reason="<ranges> not available.",
|
||||
)
|
||||
@pytest.mark.parametrize(
|
||||
("tested_dict", "expected"),
|
||||
[
|
||||
({1: 2}, [(2, 3)]),
|
||||
({3: 4, 5: 6}, [(4, 5), (6, 7)]),
|
||||
({7: 8, 9: 10, 11: 12}, [(8, 9), (10, 11), (12, 13)]),
|
||||
],
|
||||
)
|
||||
def test_dict_ranges(tested_dict, expected):
|
||||
assert m.dict_iterator_default_initialization()
|
||||
assert m.transform_dict_plus_one(tested_dict) == expected
|
||||
|
Loading…
Reference in New Issue
Block a user