Skip to content

Commit 445a5ed

Browse files
committed
Add py::module_local documentation
1 parent efc405a commit 445a5ed

File tree

3 files changed

+179
-6
lines changed

3 files changed

+179
-6
lines changed

docs/advanced/cast/stl.rst

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,20 @@ Python, and to define a set of available operations, e.g.:
167167
}, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
168168
// ....
169169
170+
Please take a look at the :ref:`macro_notes` before using the
171+
``PYBIND11_MAKE_OPAQUE`` macro.
172+
173+
.. seealso::
174+
175+
The file :file:`tests/test_opaque_types.cpp` contains a complete
176+
example that demonstrates how to create and expose opaque types using
177+
pybind11 in more detail.
178+
179+
.. _stl_bind:
180+
181+
Binding STL containers
182+
======================
183+
170184
The ability to expose STL containers as native Python objects is a fairly
171185
common request, hence pybind11 also provides an optional header file named
172186
:file:`pybind11/stl_bind.h` that does exactly this. The mapped containers try
@@ -188,14 +202,34 @@ The following example showcases usage of :file:`pybind11/stl_bind.h`:
188202
py::bind_vector<std::vector<int>>(m, "VectorInt");
189203
py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");
190204
191-
Please take a look at the :ref:`macro_notes` before using the
192-
``PYBIND11_MAKE_OPAQUE`` macro.
205+
When binding STL containers pybind11 considers the types of the container's
206+
elements to decide whether the container should be confined to the local module
207+
(via the :ref:`module_local` feature). If the container element types are
208+
anything other than already-bound custom types bound without
209+
``py::module_local()`` the container binding will have ``py::module_local()``
210+
applied. This includes converting types such as numeric types, strings, Eigen
211+
types; and types that have not yet been bound at the time of the stl container
212+
binding. This module-local binding is designed to avoid potential conflicts
213+
between module bindings (for example, from two separate modules each attempting
214+
to bind ``std::vector<int>`` as a python type).
215+
216+
It is possible to override this behavior to force a definition to be either
217+
module-local or global. To do so, you can pass the attributes
218+
``py::module_local()`` (to make the binding module-local) or
219+
``py::module_local(false)`` (to make the binding global) into the
220+
``py::bind_vector`` or ``py::bind_map`` arguments:
193221

194-
.. seealso::
222+
.. code-block:: cpp
195223
196-
The file :file:`tests/test_opaque_types.cpp` contains a complete
197-
example that demonstrates how to create and expose opaque types using
198-
pybind11 in more detail.
224+
py::bind_vector<std::vector<int>>(m, "VectorInt", py::module_local(false));
225+
226+
Note, however, that such a global binding would make it impossible to load this
227+
module at the same time as any other pybind module that also attempts to bind
228+
the same container type (``std::vector<int>`` in the above example).
229+
230+
See :ref:`module_local` for more details on module-local bindings.
231+
232+
.. seealso::
199233

200234
The file :file:`tests/test_stl_binders.cpp` shows how to use the
201235
convenience STL container wrappers.

docs/advanced/classes.rst

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,3 +635,139 @@ inheritance, which can lead to undefined behavior. In such cases, add the tag
635635
636636
The tag is redundant and does not need to be specified when multiple base types
637637
are listed.
638+
639+
.. _module_local:
640+
641+
Module-local class bindings
642+
===========================
643+
644+
When creating a binding for a class, pybind by default makes that binding
645+
"global" across modules. What this means is that a type defined in one module
646+
can be passed to functions of other modules that expect the same C++ type. For
647+
example, this allows the following:
648+
649+
.. code-block:: cpp
650+
651+
// In the module1.cpp binding code for module1:
652+
py::class_<Pet>(m, "Pet")
653+
.def(py::init<std::string>());
654+
655+
.. code-block:: cpp
656+
657+
// In the module2.cpp binding code for module2:
658+
m.def("pet_name", [](Pet &p) { return p.name(); });
659+
660+
.. code-block:: pycon
661+
662+
>>> from module1 import Pet
663+
>>> from module2 import pet_name
664+
>>> mypet = Pet("Kitty")
665+
>>> pet_name(mypet)
666+
'Kitty'
667+
668+
When writing binding code for a library, this is usually desirable: this
669+
allows, for example, splitting up a complex library into multiple Python
670+
modules.
671+
672+
In some cases, however, this can cause conflicts. For example, suppose two
673+
unrelated modules make use of an external C++ library and each provide custom
674+
bindings for one of that library's classes. This will result in an error when
675+
a Python program attempts to import both modules (directly or indirectly)
676+
because of conflicting definitions on the external type:
677+
678+
.. code-block:: cpp
679+
680+
// dogs.cpp
681+
682+
// Binding for external library class:
683+
py::class<pets::Pet>(m, "Pet")
684+
.def("name", &pets::Pet::name);
685+
686+
// Binding for local extension class:
687+
py::class<Dog, pets::Pet>(m, "Dog")
688+
.def(py::init<std::string>());
689+
690+
.. code-block:: cpp
691+
692+
// cats.cpp, in a completely separate project from the above dogs.cpp.
693+
694+
// Binding for external library class:
695+
py::class<pets::Pet>(m, "Pet")
696+
.def("get_name", &pets::Pet::name);
697+
698+
// Binding for local extending class:
699+
py::class<Cat, pets::Pet>(m, "Cat")
700+
.def(py::init<std::string>());
701+
702+
.. code-block:: pycon
703+
704+
>>> import cats
705+
>>> import dogs
706+
Traceback (most recent call last):
707+
File "<stdin>", line 1, in <module>
708+
ImportError: generic_type: type "Pet" is already registered!
709+
710+
To get around this, you can tell pybind11 to keep the external class binding
711+
localized to the module by passing the ``py::module_local()`` attribute into
712+
the ``py::class_`` constructor:
713+
714+
.. code-block:: cpp
715+
716+
// Pet binding in dogs.cpp:
717+
py::class<pets::Pet>(m, "Pet", py::module_local())
718+
.def("name", &pets::Pet::name);
719+
720+
.. code-block:: cpp
721+
722+
// Pet binding in cats.cpp:
723+
py::class<pets::Pet>(m, "Pet", py::module_local())
724+
.def("get_name", &pets::Pet::name);
725+
726+
This makes the Python-side ``dogs.Pet`` and ``cats.Pet`` into distinct classes
727+
that can only be accepted as ``Pet`` arguments within those classes. This
728+
avoids the conflict and allows both modules to be loaded.
729+
730+
One limitation of this approach is that because ``py::module_local`` types are
731+
distinct on the Python side, it is not possible to pass such a module-local
732+
type as a C++ ``Pet``-taking function outside that module. For example, if the
733+
above ``cats`` and ``dogs`` module are each extended with a function:
734+
735+
.. code-block:: cpp
736+
737+
m.def("petname", [](pets::Pet &p) { return p.name(); });
738+
739+
you will only be able to call the function with the local module's class:
740+
741+
.. code-block:: pycon
742+
743+
>>> import cats, dogs # No error because of the added py::module_local()
744+
>>> mycat, mydog = cats.Cat("Fluffy"), dogs.Dog("Rover")
745+
>>> (cats.petname(mycat), dogs.petname(mydog))
746+
('Fluffy', 'Rover')
747+
>>> cats.petname(mydog)
748+
Traceback (most recent call last):
749+
File "<stdin>", line 1, in <module>
750+
TypeError: petname(): incompatible function arguments. The following argument types are supported:
751+
1. (arg0: cats.Pet) -> str
752+
753+
Invoked with: <dogs.Dog object at 0x123>
754+
755+
.. note::
756+
757+
STL bindings (as provided via the optional :file:`pybind11/stl_bind.h`
758+
header) apply ``py::module_local`` by default when the bound type might
759+
conflict with other modules; see :ref:`stl_bind` for details.
760+
761+
.. note::
762+
763+
The localization of the bound types is actually tied to the shared object
764+
or binary generated by the compiler/linker. For typical modules created
765+
with ``PYBIND11_MODULE()``, this distinction is not significant. It is
766+
possible, however, when :ref:`embedding` to embed multiple modules in the
767+
same binary (see :ref:`embedding_modules`). In such a case, the
768+
localization will apply across all embedded modules within the same binary.
769+
770+
.. seealso::
771+
772+
The file :file:`tests/test_local_bindings.cpp` contains additional examples
773+
that demonstrate how ``py::module_local()`` works.

docs/advanced/embedding.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
.. _embedding:
2+
13
Embedding the interpreter
24
#########################
35

@@ -131,6 +133,7 @@ embedding the interpreter. This makes it easy to import local Python files:
131133
int n = result.cast<int>();
132134
assert(n == 3);
133135
136+
.. _embedding_modules:
134137

135138
Adding embedded modules
136139
=======================

0 commit comments

Comments
 (0)