|
| WrapperCollection (pybind11::module module_, std::string const &package) |
| Construct a new WrapperCollection. More...
|
|
| WrapperCollection (WrapperCollection &&other) noexcept |
|
| WrapperCollection (WrapperCollection const &)=delete |
|
WrapperCollection & | operator= (WrapperCollection const &)=delete |
|
WrapperCollection & | operator= (WrapperCollection &&)=delete |
|
| ~WrapperCollection () noexcept |
|
WrapperCollection | makeSubmodule (std::string const &name) |
| Create a WrapperCollection for a submodule defined in the same binary. More...
|
|
void | collectSubmodule (WrapperCollection &&submodule) |
| Merge deferred definitions in the given submodule into the parent WrapperCollection. More...
|
|
void | addInheritanceDependency (std::string const &name) |
| Indicate an external module that provides a base class for a subsequent addType call. More...
|
|
void | addSignatureDependency (std::string const &name) |
| Indicate an external module that provides a type used in function/method signatures. More...
|
|
void | wrap (WrapperCallback function) |
| Add a set of wrappers without defining a class. More...
|
|
template<typename PyType , typename ClassWrapperCallback > |
PyType | wrapType (PyType cls, ClassWrapperCallback function, bool setModuleName=true) |
| Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() is called. More...
|
|
template<typename CxxException , typename CxxBase > |
auto | wrapException (std::string const &pyName, std::string const &pyBase, bool setModuleName=true) |
| Wrap a C++ exception as a Python exception. More...
|
|
void | finish () |
| Invoke all deferred wrapper-declaring callables. More...
|
|
| WrapperCollection (pybind11::module module_, std::string const &package) |
| Construct a new WrapperCollection. More...
|
|
| WrapperCollection (WrapperCollection &&other) noexcept |
|
| WrapperCollection (WrapperCollection const &)=delete |
|
WrapperCollection & | operator= (WrapperCollection const &)=delete |
|
WrapperCollection & | operator= (WrapperCollection &&)=delete |
|
| ~WrapperCollection () noexcept |
|
WrapperCollection | makeSubmodule (std::string const &name) |
| Create a WrapperCollection for a submodule defined in the same binary. More...
|
|
void | collectSubmodule (WrapperCollection &&submodule) |
| Merge deferred definitions in the given submodule into the parent WrapperCollection. More...
|
|
void | addInheritanceDependency (std::string const &name) |
| Indicate an external module that provides a base class for a subsequent addType call. More...
|
|
void | addSignatureDependency (std::string const &name) |
| Indicate an external module that provides a type used in function/method signatures. More...
|
|
void | wrap (WrapperCallback function) |
| Add a set of wrappers without defining a class. More...
|
|
template<typename PyType , typename ClassWrapperCallback > |
PyType | wrapType (PyType cls, ClassWrapperCallback function, bool setModuleName=true) |
| Add a type (class or enum) wrapper, deferring method and other attribute definitions until finish() is called. More...
|
|
template<typename CxxException , typename CxxBase > |
auto | wrapException (std::string const &pyName, std::string const &pyBase, bool setModuleName=true) |
| Wrap a C++ exception as a Python exception. More...
|
|
void | finish () |
| Invoke all deferred wrapper-declaring callables. More...
|
|
A helper class for subdividing pybind11 module across multiple translation units (i.e.
source files).
Merging wrappers for different classes into a single compiled module can dramatically decrease the total size of the binary, but putting the source for multiple wrappers into a single file slows down incremental rebuilds and makes editing unwieldy. The right approach is to define wrappers in different source files and link them into a single module at build time. In simple cases, that's quite straightforward: pybind11 declarations are just regular C++ statements, and you can factor them out into different functions in different source files.
That approach doesn't work so well when the classes being wrapped are interdependent, because bindings are only guaranteed to work when all types used in a wrapped method signature have been declared to pybind11 before the method using them is itself declared. Naively, then, each source file would thus have to have multiple wrapper-declaring functions, so all type-wrapping functions could be executed before any method-wrapping functions. Of course, each type-wrapping function would also have to pass its type object to at least one method-wrapping function (to wrap the types own methods), and the result is a tangled mess of wrapper-declaring functions that obfuscate the code with a lot of boilerplate.
WrapperCollection provides a way out of that by allowing type wrappers and their associated methods to be declared at a single point, but the method wrappers wrapped in a lambda to defer their execution. A single WrapperCollection instance is typically constructed at the beginning of a PYBIND11_MODULE block, then passed by reference to wrapper-declaring functions defined in other source files. As type and method wrappers are added to the WrapperCollection by those functions, the types are registered immediately, and the method-wrapping lambdas are collected. After all wrapper-declaring functions have been called, finish() is called at the end of the PYBIND11_MODULE block to execute the collecting method-wrapping lambdas.
Typical usage:
wrapClassA(wrappers);
wrapClassB(wrappers);
wrappers.finish();
}
pybind11::module module
The module object passed to the PYBIND11_MODULE block that contains this WrapperCollection.
WrapperCollection(pybind11::module module_, std::string const &package)
Construct a new WrapperCollection.
PYBIND11_MODULE(_cpputils, mod)
wrappers.wrapType(
py::class_<ClassA>(wrappers.module, "ClassA"),
[](auto & mod, auto & cls) {
cls.def("methodOnClassA", &methodOnClassA);
}
);
}
wrappers.wrapType(
py::class_<ClassB>(wrappers.module, "ClassB"),
[](auto & mod, auto & cls) {
cls.def("methodOnClassB", &methodOnClassB);
mod.def("freeFunction", &freeFunction);
}
);
}
Note that we recommend the use of universal lambdas (i.e. auto &
parameters) to reduce verbosity.
Definition at line 242 of file python.h.
Create a WrapperCollection for a submodule defined in the same binary.
WrapperCollections created with makeSubmodule should generally be destroyed by moving them into a call to collectSubmodule; this will cause all deferred definitions to be executed when the parent WrapperCollection's finish() method is called.
- Parameters
-
name | Relative name of the submodule. |
Attributes added to the returned WrapperCollection will actually be put in a submodule that adds an underscore prefix to name
, with __module__
set with the expectation that they will be lifted into a package without that leading underscore by a line in __init__.py
like:
from ._package import _submodule as submodule
This is necessary to make importing _package
possible when submodule
already exists as a normal (i.e. directory-based) package. Of course, in that case, you'd instead use a submodule/__init__.py
with a line like:
from .._package._submodule import *
- Returns
- a new WrapperCollection instance that sets the
__module__
of any classes added to it to {package}.{name}
.
Definition at line 318 of file python.h.
Create a WrapperCollection for a submodule defined in the same binary.
WrapperCollections created with makeSubmodule should generally be destroyed by moving them into a call to collectSubmodule; this will cause all deferred definitions to be executed when the parent WrapperCollection's finish() method is called.
- Parameters
-
name | Relative name of the submodule. |
Attributes added to the returned WrapperCollection will actually be put in a submodule that adds an underscore prefix to name
, with __module__
set with the expectation that they will be lifted into a package without that leading underscore by a line in __init__.py
like:
from ._package import _submodule as submodule
This is necessary to make importing _package
possible when submodule
already exists as a normal (i.e. directory-based) package. Of course, in that case, you'd instead use a submodule/__init__.py
with a line like:
from .._package._submodule import *
- Returns
- a new WrapperCollection instance that sets the
__module__
of any classes added to it to {package}.{name}
.
Definition at line 318 of file python.h.