Skip to content

Commit 107285b

Browse files
dean0x7dwjakob
authored andcommitted
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.
1 parent 719c173 commit 107285b

File tree

2 files changed

+15
-9
lines changed

2 files changed

+15
-9
lines changed

include/pybind11/cast.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -737,12 +737,12 @@ template <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
737737
typedef std::pair<T1, T2> type;
738738
public:
739739
bool load(handle src, bool convert) {
740-
if (!src)
740+
if (!isinstance<sequence>(src))
741741
return false;
742-
else if (!PyTuple_Check(src.ptr()) || PyTuple_Size(src.ptr()) != 2)
742+
const auto seq = reinterpret_borrow<sequence>(src);
743+
if (seq.size() != 2)
743744
return false;
744-
return first.load(PyTuple_GET_ITEM(src.ptr(), 0), convert) &&
745-
second.load(PyTuple_GET_ITEM(src.ptr(), 1), convert);
745+
return first.load(seq[0], convert) && second.load(seq[1], convert);
746746
}
747747

748748
static handle cast(const type &src, return_value_policy policy, handle parent) {
@@ -779,9 +779,12 @@ template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
779779

780780
public:
781781
bool load(handle src, bool convert) {
782-
if (!src || !PyTuple_Check(src.ptr()) || PyTuple_GET_SIZE(src.ptr()) != size)
782+
if (!isinstance<sequence>(src))
783+
return false;
784+
const auto seq = reinterpret_borrow<sequence>(src);
785+
if (seq.size() != size)
783786
return false;
784-
return load_impl(src, convert, indices{});
787+
return load_impl(seq, convert, indices{});
785788
}
786789

787790
static handle cast(const type &src, return_value_policy policy, handle parent) {
@@ -800,11 +803,11 @@ template <typename... Tuple> class type_caster<std::tuple<Tuple...>> {
800803
template <size_t... Is>
801804
type implicit_cast(index_sequence<Is...>) { return type(cast_op<Tuple>(std::get<Is>(value))...); }
802805

803-
static constexpr bool load_impl(handle, bool, index_sequence<>) { return true; }
806+
static constexpr bool load_impl(const sequence &, bool, index_sequence<>) { return true; }
804807

805808
template <size_t... Is>
806-
bool load_impl(handle src, bool convert, index_sequence<Is...>) {
807-
for (bool r : {std::get<Is>(value).load(PyTuple_GET_ITEM(src.ptr(), Is), convert)...})
809+
bool load_impl(const sequence &seq, bool convert, index_sequence<Is...>) {
810+
for (bool r : {std::get<Is>(value).load(seq[Is], convert)...})
808811
if (!r)
809812
return false;
810813
return true;

tests/test_python_types.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ def test_instance(capture):
9393

9494
assert instance.pair_passthrough((True, "test")) == ("test", True)
9595
assert instance.tuple_passthrough((True, "test", 5)) == (5, "test", True)
96+
# Any sequence can be cast to a std::pair or std::tuple
97+
assert instance.pair_passthrough([True, "test"]) == ("test", True)
98+
assert instance.tuple_passthrough([True, "test", 5]) == (5, "test", True)
9699

97100
assert instance.get_bytes_from_string().decode() == "foo"
98101
assert instance.get_bytes_from_str().decode() == "bar"

0 commit comments

Comments
 (0)