From 8d3cedbe2bb6ae5c68e1543b8a1c78ae07370ccc Mon Sep 17 00:00:00 2001 From: Dean Moldovan Date: Sun, 13 Aug 2017 03:03:06 +0200 Subject: [PATCH] Add test for mixing STL casters and local binders across modules One module uses a generic vector caster from `` while the other exports `std::vector` with a local `py:bind_vector`. --- tests/local_bindings.h | 8 ++++++++ tests/pybind11_cross_module_tests.cpp | 24 ++++++++++++++++-------- tests/test_local_bindings.cpp | 27 ++++++++++++++++++++------- tests/test_local_bindings.py | 24 ++++++++++++++++++++++-- 4 files changed, 66 insertions(+), 17 deletions(-) diff --git a/tests/local_bindings.h b/tests/local_bindings.h index 4c031fb7f..06a56fcd1 100644 --- a/tests/local_bindings.h +++ b/tests/local_bindings.h @@ -21,6 +21,14 @@ using MixedLocalGlobal = LocalBase<4>; /// Mixed: global first, then local (which fails) using MixedGlobalLocal = LocalBase<5>; +using LocalVec = std::vector; +using LocalVec2 = std::vector; +using LocalMap = std::unordered_map; +using NonLocalVec = std::vector; +using NonLocalVec2 = std::vector; +using NonLocalMap = std::unordered_map; +using NonLocalMap2 = std::unordered_map; + // Simple bindings (used with the above): template py::class_ bind_local(Args && ...args) { diff --git a/tests/pybind11_cross_module_tests.cpp b/tests/pybind11_cross_module_tests.cpp index dca8ca2e2..252f89360 100644 --- a/tests/pybind11_cross_module_tests.cpp +++ b/tests/pybind11_cross_module_tests.cpp @@ -10,6 +10,7 @@ #include "pybind11_tests.h" #include "local_bindings.h" #include +#include PYBIND11_MODULE(pybind11_cross_module_tests, m) { m.doc() = "pybind11 cross-module test module"; @@ -44,25 +45,25 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { // test_stl_bind_local // stl_bind.h binders defaults to py::module_local if the types are local or converting: - py::bind_vector>(m, "LocalVec"); - py::bind_map>(m, "LocalMap"); + py::bind_vector(m, "LocalVec"); + py::bind_map(m, "LocalMap"); + + // test_stl_bind_global // and global if the type (or one of the types, for the map) is global (so these will fail, // assuming pybind11_tests is already loaded): m.def("register_nonlocal_vec", [m]() { - py::bind_vector>(m, "NonLocalVec"); + py::bind_vector(m, "NonLocalVec"); }); m.def("register_nonlocal_map", [m]() { - py::bind_map>(m, "NonLocalMap"); + py::bind_map(m, "NonLocalMap"); }); - - // test_stl_bind_global // The default can, however, be overridden to global using `py::module_local()` or // `py::module_local(false)`. // Explicitly made local: - py::bind_vector>(m, "NonLocalVec2", py::module_local()); + py::bind_vector(m, "NonLocalVec2", py::module_local()); // Explicitly made global (and so will fail to bind): m.def("register_nonlocal_map2", [m]() { - py::bind_map>(m, "NonLocalMap2", py::module_local(false)); + py::bind_map(m, "NonLocalMap2", py::module_local(false)); }); // test_mixed_local_global @@ -79,4 +80,11 @@ PYBIND11_MODULE(pybind11_cross_module_tests, m) { // test_internal_locals_differ m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); }); + + // test_stl_caster_vs_stl_bind + py::bind_vector>(m, "VectorInt"); + + m.def("load_vector_via_binding", [](std::vector &v) { + return std::accumulate(v.begin(), v.end(), 0); + }); } diff --git a/tests/test_local_bindings.cpp b/tests/test_local_bindings.cpp index e46f8f5f2..fdb67a1a6 100644 --- a/tests/test_local_bindings.cpp +++ b/tests/test_local_bindings.cpp @@ -10,10 +10,18 @@ #include "pybind11_tests.h" #include "local_bindings.h" +#include #include +#include + +PYBIND11_MAKE_OPAQUE(LocalVec); +PYBIND11_MAKE_OPAQUE(LocalVec2); +PYBIND11_MAKE_OPAQUE(LocalMap); +PYBIND11_MAKE_OPAQUE(NonLocalVec); +PYBIND11_MAKE_OPAQUE(NonLocalMap); +PYBIND11_MAKE_OPAQUE(NonLocalMap2); TEST_SUBMODULE(local_bindings, m) { - // test_local_bindings // Register a class with py::module_local: bind_local(m, "LocalType", py::module_local()) @@ -45,17 +53,17 @@ TEST_SUBMODULE(local_bindings, m) { // test_stl_bind_local // stl_bind.h binders defaults to py::module_local if the types are local or converting: - py::bind_vector>(m, "LocalVec"); - py::bind_map>(m, "LocalMap"); + py::bind_vector(m, "LocalVec"); + py::bind_map(m, "LocalMap"); // and global if the type (or one of the types, for the map) is global: - py::bind_vector>(m, "NonLocalVec"); - py::bind_map>(m, "NonLocalMap"); + py::bind_vector(m, "NonLocalVec"); + py::bind_map(m, "NonLocalMap"); // test_stl_bind_global // They can, however, be overridden to global using `py::module_local(false)`: bind_local(m, "NonLocal2"); - py::bind_vector>(m, "LocalVec2", py::module_local()); - py::bind_map>(m, "NonLocalMap2", py::module_local(false)); + py::bind_vector(m, "LocalVec2", py::module_local()); + py::bind_map(m, "NonLocalMap2", py::module_local(false)); // test_mixed_local_global // We try this both with the global type registered first and vice versa (the order shouldn't @@ -71,4 +79,9 @@ TEST_SUBMODULE(local_bindings, m) { // test_internal_locals_differ m.def("local_cpp_types_addr", []() { return (uintptr_t) &py::detail::registered_local_types_cpp(); }); + + // test_stl_caster_vs_stl_bind + m.def("load_vector_via_caster", [](std::vector v) { + return std::accumulate(v.begin(), v.end(), 0); + }); } diff --git a/tests/test_local_bindings.py b/tests/test_local_bindings.py index 4e356653c..3a6ad8b27 100644 --- a/tests/test_local_bindings.py +++ b/tests/test_local_bindings.py @@ -4,13 +4,12 @@ from pybind11_tests import local_bindings as m def test_local_bindings(): - """Tests that duplicate py::local class bindings work across modules""" + """Tests that duplicate `py::module_local` class bindings work across modules""" # Make sure we can load the second module with the conflicting (but local) definition: import pybind11_cross_module_tests as cm i1 = m.LocalType(5) - assert i1.get() == 4 assert i1.get3() == 8 @@ -138,3 +137,24 @@ def test_internal_locals_differ(): """Makes sure the internal local type map differs across the two modules""" import pybind11_cross_module_tests as cm assert m.local_cpp_types_addr() != cm.local_cpp_types_addr() + + +def test_stl_caster_vs_stl_bind(msg): + """One module uses a generic vector caster from `` while the other + exports `std::vector` via `py:bind_vector` and `py::module_local`""" + import pybind11_cross_module_tests as cm + + v1 = cm.VectorInt([1, 2, 3]) + assert m.load_vector_via_caster(v1) == 6 + assert cm.load_vector_via_binding(v1) == 6 + + v2 = [1, 2, 3] + assert m.load_vector_via_caster(v2) == 6 + with pytest.raises(TypeError) as excinfo: + cm.load_vector_via_binding(v2) == 6 + assert msg(excinfo.value) == """ + load_vector_via_binding(): incompatible function arguments. The following argument types are supported: + 1. (arg0: pybind11_cross_module_tests.VectorInt) -> int + + Invoked with: [1, 2, 3] + """ # noqa: E501 line too long