Allow module-local classes to be loaded externally
The main point of `py::module_local` is to make the C++ -> Python cast
unique so that returning/casting a C++ instance is well-defined.
Unfortunately it also makes loading unique, but this isn't particularly
desirable: when an instance contains `Type` instance there's no reason
it shouldn't be possible to pass that instance to a bound function
taking a `Type` parameter, even if that function is in another module.
This commit solves the issue by allowing foreign module (and global)
type loaders have a chance to load the value if the local module loader
fails. The implementation here does this by storing a module-local
loading function in a capsule in the python type, which we can then call
if the local (and possibly global, if the local type is masking a global
type) version doesn't work.
diff --git a/tests/test_local_bindings.cpp b/tests/test_local_bindings.cpp
index fdb67a1..359d6c6 100644
--- a/tests/test_local_bindings.cpp
+++ b/tests/test_local_bindings.cpp
@@ -14,13 +14,6 @@
#include <pybind11/stl_bind.h>
#include <numeric>
-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:
@@ -84,4 +77,21 @@
m.def("load_vector_via_caster", [](std::vector<int> v) {
return std::accumulate(v.begin(), v.end(), 0);
});
+
+ // test_cross_module_calls
+ m.def("return_self", [](LocalVec *v) { return v; });
+ m.def("return_copy", [](const LocalVec &v) { return LocalVec(v); });
+
+ class Cat : public pets::Pet { public: Cat(std::string name) : Pet(name) {}; };
+ py::class_<pets::Pet>(m, "Pet", py::module_local())
+ .def("get_name", &pets::Pet::name);
+ // Binding for local extending class:
+ py::class_<Cat, pets::Pet>(m, "Cat")
+ .def(py::init<std::string>());
+ m.def("pet_name", [](pets::Pet &p) { return p.name(); });
+
+ py::class_<MixGL>(m, "MixGL").def(py::init<int>());
+ m.def("get_gl_value", [](MixGL &o) { return o.i + 10; });
+
+ py::class_<MixGL2>(m, "MixGL2").def(py::init<int>());
}