diff --git a/tests/test_async.cpp b/tests/test_async.cpp index a5d722465..833022c54 100644 --- a/tests/test_async.cpp +++ b/tests/test_async.cpp @@ -9,6 +9,48 @@ #include "pybind11_tests.h" +namespace mrc_ns { // minimal real caster + +struct minimal_real_caster; + +struct type_mrc { + int value = -9999; +}; + +struct minimal_real_caster { + static constexpr auto name = py::detail::const_name(); + + static py::handle + cast(type_mrc const &src, py::return_value_policy /*policy*/, py::handle /*parent*/) { + return py::int_(src.value + 1010).release(); + } + + // Maximizing simplicity. This will go terribly wrong for other arg types. + template + using cast_op_type = const type_mrc &; + + // NOLINTNEXTLINE(google-explicit-constructor) + operator type_mrc const &() { + static type_mrc obj; + obj.value = 11; + return obj; + } + + bool load(py::handle src, bool /*convert*/) { + // Only accepts str, but the value is ignored. + return py::isinstance(src); + } +}; + +} // namespace mrc_ns + +namespace pybind11 { +namespace detail { +template <> +struct type_caster : mrc_ns::minimal_real_caster {}; +} // namespace detail +} // namespace pybind11 + TEST_SUBMODULE(async_module, m) { struct DoesNotSupportAsync {}; py::class_(m, "DoesNotSupportAsync").def(py::init<>()); @@ -22,4 +64,6 @@ TEST_SUBMODULE(async_module, m) { f.attr("set_result")(5); return f.attr("__await__")(); }); + m.def("type_mrc_to_python", []() { return mrc_ns::type_mrc{101}; }); + m.def("type_mrc_from_python", [](const mrc_ns::type_mrc &obj) { return obj.value + 100; }); } diff --git a/tests/test_async.py b/tests/test_async.py index b9ff9514d..c33d2113e 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -22,3 +22,8 @@ def test_await(event_loop): def test_await_missing(event_loop): with pytest.raises(TypeError): event_loop.run_until_complete(get_await_result(m.DoesNotSupportAsync())) + + +def test_mrc(): + assert m.type_mrc_to_python() == 1111 + assert m.type_mrc_from_python("ignored") == 111 diff --git a/tests/test_buffers.cpp b/tests/test_buffers.cpp index 6b6e8cba7..f1a134282 100644 --- a/tests/test_buffers.cpp +++ b/tests/test_buffers.cpp @@ -12,6 +12,48 @@ #include "constructor_stats.h" #include "pybind11_tests.h" +namespace mrc_ns { // minimal real caster + +struct minimal_real_caster; + +struct type_mrc { + int value = -9999; +}; + +struct minimal_real_caster { + static constexpr auto name = py::detail::const_name(); + + static py::handle + cast(type_mrc const &src, py::return_value_policy /*policy*/, py::handle /*parent*/) { + return py::int_(src.value + 2020).release(); + } + + // Maximizing simplicity. This will go terribly wrong for other arg types. + template + using cast_op_type = const type_mrc &; + + // NOLINTNEXTLINE(google-explicit-constructor) + operator type_mrc const &() { + static type_mrc obj; + obj.value = 22; + return obj; + } + + bool load(py::handle src, bool /*convert*/) { + // Only accepts str, but the value is ignored. + return py::isinstance(src); + } +}; + +} // namespace mrc_ns + +namespace pybind11 { +namespace detail { +template <> +struct type_caster : mrc_ns::minimal_real_caster {}; +} // namespace detail +} // namespace pybind11 + TEST_SUBMODULE(buffers, m) { // test_from_python / test_to_python: class Matrix { @@ -221,4 +263,7 @@ TEST_SUBMODULE(buffers, m) { }); m.def("get_buffer_info", [](const py::buffer &buffer) { return buffer.request(); }); + + m.def("type_mrc_to_python", []() { return mrc_ns::type_mrc{202}; }); + m.def("type_mrc_from_python", [](const mrc_ns::type_mrc &obj) { return obj.value + 200; }); } diff --git a/tests/test_buffers.py b/tests/test_buffers.py index 8354b68cd..515af4b10 100644 --- a/tests/test_buffers.py +++ b/tests/test_buffers.py @@ -161,3 +161,8 @@ def test_ctypes_from_buffer(): assert cinfo.shape == pyinfo.shape assert cinfo.strides == pyinfo.strides assert not cinfo.readonly + + +def test_mrc(): + assert m.type_mrc_to_python() == 1111 + assert m.type_mrc_from_python("ignored") == 111