From 107285b3539da43c71201baf9c78af49adc1a6de Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sun, 27 Nov 2016 20:32:04 +0100 Subject: [PATCH] Accept any sequence type as std::tuple or std::pair This is more Pythonic and compliments the std::vector and std::list casters which also accept sequences. --- include/pybind11/cast.h | 21 ++++++++++++--------- tests/test_python_types.py | 3 +++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 42d381bb9..f847b084b 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -737,12 +737,12 @@ template class type_caster> { typedef std::pair type; public: bool load(handle src, bool convert) { - if (!src) + if (!isinstance(src)) return false; - else if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2) + const auto seq = reinterpret_borrow(src); + if (seq.size() != 2) return false; - return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) && - second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert); + return first.load(seq[0], convert) && second.load(seq[1], convert); } static handle cast(const type &src, return_value_policy policy, handle parent) { @@ -779,9 +779,12 @@ template class type_caster> { public: bool load(handle src, bool convert) { - if (!src || !PyTuple_Check(src.ptr()) || PyTuple_GET_SIZE(src.ptr()) != size) + if (!isinstance(src)) return false; - return load_impl(src, convert, indices{}); + const auto seq = reinterpret_borrow(src); + if (seq.size() != size) + return false; + return load_impl(seq, convert, indices{}); } static handle cast(const type &src, return_value_policy policy, handle parent) { @@ -800,11 +803,11 @@ protected: template type implicit_cast(index_sequence) { return type(cast_op(std::get(value))...); } - static constexpr bool load_impl(handle, bool, index_sequence<>) { return true; } + static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; } template - bool load_impl(handle src, bool convert, index_sequence) { - for (bool r : {std::get(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...}) + bool load_impl(const sequence &seq, bool convert, index_sequence) { + for (bool r : {std::get(value).load(seq[Is], convert)...}) if (!r) return false; return true; diff --git a/tests/test_python_types.py b/tests/test_python_types.py index dcd5d6245..abffa1a94 100644 --- a/tests/test_python_types.py +++ b/tests/test_python_types.py @@ -93,6 +93,9 @@ def test_instance(capture): assert instance.pair_passthrough((True, "test")) == ("test", True) assert instance.tuple_passthrough((True, "test", 5)) == (5, "test", True) + # Any sequence can be cast to a std::pair or std::tuple + assert instance.pair_passthrough([True, "test"]) == ("test", True) + assert instance.tuple_passthrough([True, "test", 5]) == (5, "test", True) assert instance.get_bytes_from_string().decode() == "foo" assert instance.get_bytes_from_str().decode() == "bar"