mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
refactor: module -> module_ with typedef (#2544)
* WIP: module -> module_ without typedef * refactor: allow py::module to work again
This commit is contained in:
parent
560ed3e34f
commit
6bcd220c8d
@ -108,11 +108,11 @@ The two approaches can also be combined:
|
|||||||
Importing modules
|
Importing modules
|
||||||
=================
|
=================
|
||||||
|
|
||||||
Python modules can be imported using `module::import()`:
|
Python modules can be imported using `module_::import()`:
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::module sys = py::module::import("sys");
|
py::module_ sys = py::module_::import("sys");
|
||||||
py::print(sys.attr("path"));
|
py::print(sys.attr("path"));
|
||||||
|
|
||||||
For convenience, the current working directory is included in ``sys.path`` when
|
For convenience, the current working directory is included in ``sys.path`` when
|
||||||
@ -128,12 +128,12 @@ embedding the interpreter. This makes it easy to import local Python files:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::module calc = py::module::import("calc");
|
py::module_ calc = py::module_::import("calc");
|
||||||
py::object result = calc.attr("add")(1, 2);
|
py::object result = calc.attr("add")(1, 2);
|
||||||
int n = result.cast<int>();
|
int n = result.cast<int>();
|
||||||
assert(n == 3);
|
assert(n == 3);
|
||||||
|
|
||||||
Modules can be reloaded using `module::reload()` if the source is modified e.g.
|
Modules can be reloaded using `module_::reload()` if the source is modified e.g.
|
||||||
by an external process. This can be useful in scenarios where the application
|
by an external process. This can be useful in scenarios where the application
|
||||||
imports a user defined data processing script which needs to be updated after
|
imports a user defined data processing script which needs to be updated after
|
||||||
changes by the user. Note that this function does not reload modules recursively.
|
changes by the user. Note that this function does not reload modules recursively.
|
||||||
@ -153,7 +153,7 @@ like any other module.
|
|||||||
namespace py = pybind11;
|
namespace py = pybind11;
|
||||||
|
|
||||||
PYBIND11_EMBEDDED_MODULE(fast_calc, m) {
|
PYBIND11_EMBEDDED_MODULE(fast_calc, m) {
|
||||||
// `m` is a `py::module` which is used to bind functions and classes
|
// `m` is a `py::module_` which is used to bind functions and classes
|
||||||
m.def("add", [](int i, int j) {
|
m.def("add", [](int i, int j) {
|
||||||
return i + j;
|
return i + j;
|
||||||
});
|
});
|
||||||
@ -162,7 +162,7 @@ like any other module.
|
|||||||
int main() {
|
int main() {
|
||||||
py::scoped_interpreter guard{};
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
auto fast_calc = py::module::import("fast_calc");
|
auto fast_calc = py::module_::import("fast_calc");
|
||||||
auto result = fast_calc.attr("add")(1, 2).cast<int>();
|
auto result = fast_calc.attr("add")(1, 2).cast<int>();
|
||||||
assert(result == 3);
|
assert(result == 3);
|
||||||
}
|
}
|
||||||
@ -196,7 +196,7 @@ naturally:
|
|||||||
int main() {
|
int main() {
|
||||||
py::scoped_interpreter guard{};
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
auto py_module = py::module::import("py_module");
|
auto py_module = py::module_::import("py_module");
|
||||||
|
|
||||||
auto locals = py::dict("fmt"_a="{} + {} = {}", **py_module.attr("__dict__"));
|
auto locals = py::dict("fmt"_a="{} + {} = {}", **py_module.attr("__dict__"));
|
||||||
assert(locals["a"].cast<int>() == 1);
|
assert(locals["a"].cast<int>() == 1);
|
||||||
|
@ -182,7 +182,7 @@ For example:
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// open("missing.txt", "r")
|
// open("missing.txt", "r")
|
||||||
auto file = py::module::import("io").attr("open")("missing.txt", "r");
|
auto file = py::module_::import("io").attr("open")("missing.txt", "r");
|
||||||
auto text = file.attr("read")();
|
auto text = file.attr("read")();
|
||||||
file.attr("close")();
|
file.attr("close")();
|
||||||
} catch (py::error_already_set &e) {
|
} catch (py::error_already_set &e) {
|
||||||
|
@ -17,7 +17,7 @@ bindings for functions that return a non-trivial type. Just by looking at the
|
|||||||
type information, it is not clear whether Python should take charge of the
|
type information, it is not clear whether Python should take charge of the
|
||||||
returned value and eventually free its resources, or if this is handled on the
|
returned value and eventually free its resources, or if this is handled on the
|
||||||
C++ side. For this reason, pybind11 provides a several *return value policy*
|
C++ side. For this reason, pybind11 provides a several *return value policy*
|
||||||
annotations that can be passed to the :func:`module::def` and
|
annotations that can be passed to the :func:`module_::def` and
|
||||||
:func:`class_::def` functions. The default policy is
|
:func:`class_::def` functions. The default policy is
|
||||||
:enum:`return_value_policy::automatic`.
|
:enum:`return_value_policy::automatic`.
|
||||||
|
|
||||||
|
@ -132,7 +132,7 @@ However, it can be acquired as follows:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::object pet = (py::object) py::module::import("basic").attr("Pet");
|
py::object pet = (py::object) py::module_::import("basic").attr("Pet");
|
||||||
|
|
||||||
py::class_<Dog>(m, "Dog", pet)
|
py::class_<Dog>(m, "Dog", pet)
|
||||||
.def(py::init<const std::string &>())
|
.def(py::init<const std::string &>())
|
||||||
@ -146,7 +146,7 @@ has been executed:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::module::import("basic");
|
py::module_::import("basic");
|
||||||
|
|
||||||
py::class_<Dog, Pet>(m, "Dog")
|
py::class_<Dog, Pet>(m, "Dog")
|
||||||
.def(py::init<const std::string &>())
|
.def(py::init<const std::string &>())
|
||||||
@ -243,7 +243,7 @@ avoids this issue involves weak reference with a cleanup callback:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
auto atexit = py::module::import("atexit");
|
auto atexit = py::module_::import("atexit");
|
||||||
atexit.attr("register")(py::cpp_function([]() {
|
atexit.attr("register")(py::cpp_function([]() {
|
||||||
// perform cleanup here -- this function is called with the GIL held
|
// perform cleanup here -- this function is called with the GIL held
|
||||||
}));
|
}));
|
||||||
@ -284,7 +284,7 @@ work, it is important that all lines are indented consistently, i.e.:
|
|||||||
)mydelimiter");
|
)mydelimiter");
|
||||||
|
|
||||||
By default, pybind11 automatically generates and prepends a signature to the docstring of a function
|
By default, pybind11 automatically generates and prepends a signature to the docstring of a function
|
||||||
registered with ``module::def()`` and ``class_::def()``. Sometimes this
|
registered with ``module_::def()`` and ``class_::def()``. Sometimes this
|
||||||
behavior is not desirable, because you want to provide your own signature or remove
|
behavior is not desirable, because you want to provide your own signature or remove
|
||||||
the docstring completely to exclude the function from the Sphinx documentation.
|
the docstring completely to exclude the function from the Sphinx documentation.
|
||||||
The class ``options`` allows you to selectively suppress auto-generated signatures:
|
The class ``options`` allows you to selectively suppress auto-generated signatures:
|
||||||
|
@ -56,12 +56,12 @@ This example obtains a reference to the Python ``Decimal`` class.
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
// Equivalent to "from decimal import Decimal"
|
// Equivalent to "from decimal import Decimal"
|
||||||
py::object Decimal = py::module::import("decimal").attr("Decimal");
|
py::object Decimal = py::module_::import("decimal").attr("Decimal");
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
// Try to import scipy
|
// Try to import scipy
|
||||||
py::object scipy = py::module::import("scipy");
|
py::object scipy = py::module_::import("scipy");
|
||||||
return scipy.attr("__version__");
|
return scipy.attr("__version__");
|
||||||
|
|
||||||
|
|
||||||
@ -81,7 +81,7 @@ via ``operator()``.
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
// Use Python to make our directories
|
// Use Python to make our directories
|
||||||
py::object os = py::module::import("os");
|
py::object os = py::module_::import("os");
|
||||||
py::object makedirs = os.attr("makedirs");
|
py::object makedirs = os.attr("makedirs");
|
||||||
makedirs("/tmp/path/to/somewhere");
|
makedirs("/tmp/path/to/somewhere");
|
||||||
|
|
||||||
@ -196,9 +196,9 @@ C++ functions that require a specific subtype rather than a generic :class:`obje
|
|||||||
#include <pybind11/numpy.h>
|
#include <pybind11/numpy.h>
|
||||||
using namespace pybind11::literals;
|
using namespace pybind11::literals;
|
||||||
|
|
||||||
py::module os = py::module::import("os");
|
py::module_ os = py::module_::import("os");
|
||||||
py::module path = py::module::import("os.path"); // like 'import os.path as path'
|
py::module_ path = py::module_::import("os.path"); // like 'import os.path as path'
|
||||||
py::module np = py::module::import("numpy"); // like 'import numpy as np'
|
py::module_ np = py::module_::import("numpy"); // like 'import numpy as np'
|
||||||
|
|
||||||
py::str curdir_abs = path.attr("abspath")(path.attr("curdir"));
|
py::str curdir_abs = path.attr("abspath")(path.attr("curdir"));
|
||||||
py::print(py::str("Current directory: ") + curdir_abs);
|
py::print(py::str("Current directory: ") + curdir_abs);
|
||||||
|
@ -42,7 +42,7 @@ redirects output to the corresponding Python streams:
|
|||||||
m.def("noisy_func", []() {
|
m.def("noisy_func", []() {
|
||||||
py::scoped_ostream_redirect stream(
|
py::scoped_ostream_redirect stream(
|
||||||
std::cout, // std::ostream&
|
std::cout, // std::ostream&
|
||||||
py::module::import("sys").attr("stdout") // Python output
|
py::module_::import("sys").attr("stdout") // Python output
|
||||||
);
|
);
|
||||||
call_noisy_func();
|
call_noisy_func();
|
||||||
});
|
});
|
||||||
@ -104,7 +104,7 @@ can be used.
|
|||||||
...
|
...
|
||||||
|
|
||||||
// Evaluate in scope of main module
|
// Evaluate in scope of main module
|
||||||
py::object scope = py::module::import("__main__").attr("__dict__");
|
py::object scope = py::module_::import("__main__").attr("__dict__");
|
||||||
|
|
||||||
// Evaluate an isolated expression
|
// Evaluate an isolated expression
|
||||||
int result = py::eval("my_variable + 10", scope).cast<int>();
|
int result = py::eval("my_variable + 10", scope).cast<int>();
|
||||||
|
@ -118,8 +118,8 @@ a file named :file:`example.cpp` with the following contents:
|
|||||||
The :func:`PYBIND11_MODULE` macro creates a function that will be called when an
|
The :func:`PYBIND11_MODULE` macro creates a function that will be called when an
|
||||||
``import`` statement is issued from within Python. The module name (``example``)
|
``import`` statement is issued from within Python. The module name (``example``)
|
||||||
is given as the first macro argument (it should not be in quotes). The second
|
is given as the first macro argument (it should not be in quotes). The second
|
||||||
argument (``m``) defines a variable of type :class:`py::module <module>` which
|
argument (``m``) defines a variable of type :class:`py::module_ <module>` which
|
||||||
is the main interface for creating bindings. The method :func:`module::def`
|
is the main interface for creating bindings. The method :func:`module_::def`
|
||||||
generates binding code that exposes the ``add()`` function to Python.
|
generates binding code that exposes the ``add()`` function to Python.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
@ -181,7 +181,7 @@ names of the arguments ("i" and "j" in this case).
|
|||||||
py::arg("i"), py::arg("j"));
|
py::arg("i"), py::arg("j"));
|
||||||
|
|
||||||
:class:`arg` is one of several special tag classes which can be used to pass
|
:class:`arg` is one of several special tag classes which can be used to pass
|
||||||
metadata into :func:`module::def`. With this modified binding code, we can now
|
metadata into :func:`module_::def`. With this modified binding code, we can now
|
||||||
call the function using keyword arguments, which is a more readable alternative
|
call the function using keyword arguments, which is a more readable alternative
|
||||||
particularly for functions taking many parameters:
|
particularly for functions taking many parameters:
|
||||||
|
|
||||||
|
@ -11,9 +11,9 @@ v2.6.0 (IN PROGRESS)
|
|||||||
|
|
||||||
See :ref:`upgrade-guide-2.6` for help upgrading to the new version.
|
See :ref:`upgrade-guide-2.6` for help upgrading to the new version.
|
||||||
|
|
||||||
* Provide an additional spelling of ``py::module`` - ``py::module_`` (with a
|
* ``py::module`` was renamed ``py::module_`` to avoid issues with C++20 when
|
||||||
trailing underscore), for C++20 compatibility. Only relevant when used
|
used unqualified, but an alias ``py::module`` is provided for backward
|
||||||
unqualified.
|
compatibility.
|
||||||
`#2489 <https://github.com/pybind/pybind11/pull/2489>`_
|
`#2489 <https://github.com/pybind/pybind11/pull/2489>`_
|
||||||
|
|
||||||
* ``pybind11_add_module()`` now accepts an optional ``OPT_SIZE`` flag that
|
* ``pybind11_add_module()`` now accepts an optional ``OPT_SIZE`` flag that
|
||||||
@ -529,7 +529,7 @@ v2.2.2 (February 7, 2018)
|
|||||||
v2.2.1 (September 14, 2017)
|
v2.2.1 (September 14, 2017)
|
||||||
-----------------------------------------------------
|
-----------------------------------------------------
|
||||||
|
|
||||||
* Added ``py::module::reload()`` member function for reloading a module.
|
* Added ``py::module_::reload()`` member function for reloading a module.
|
||||||
`#1040 <https://github.com/pybind/pybind11/pull/1040>`_.
|
`#1040 <https://github.com/pybind/pybind11/pull/1040>`_.
|
||||||
|
|
||||||
* Fixed a reference leak in the number converter.
|
* Fixed a reference leak in the number converter.
|
||||||
|
@ -100,8 +100,8 @@ following example:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
void init_ex1(py::module &);
|
void init_ex1(py::module_ &);
|
||||||
void init_ex2(py::module &);
|
void init_ex2(py::module_ &);
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
PYBIND11_MODULE(example, m) {
|
PYBIND11_MODULE(example, m) {
|
||||||
@ -114,7 +114,7 @@ following example:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
void init_ex1(py::module &m) {
|
void init_ex1(py::module_ &m) {
|
||||||
m.def("add", [](int a, int b) { return a + b; });
|
m.def("add", [](int a, int b) { return a + b; });
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ following example:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
void init_ex2(py::module &m) {
|
void init_ex2(py::module_ &m) {
|
||||||
m.def("sub", [](int a, int b) { return a - b; });
|
m.def("sub", [](int a, int b) { return a - b; });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,17 +569,17 @@ inline PyObject* make_new_python_type(const type_record &rec) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
object module;
|
object module_;
|
||||||
if (rec.scope) {
|
if (rec.scope) {
|
||||||
if (hasattr(rec.scope, "__module__"))
|
if (hasattr(rec.scope, "__module__"))
|
||||||
module = rec.scope.attr("__module__");
|
module_ = rec.scope.attr("__module__");
|
||||||
else if (hasattr(rec.scope, "__name__"))
|
else if (hasattr(rec.scope, "__name__"))
|
||||||
module = rec.scope.attr("__name__");
|
module_ = rec.scope.attr("__name__");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto full_name = c_str(
|
auto full_name = c_str(
|
||||||
#if !defined(PYPY_VERSION)
|
#if !defined(PYPY_VERSION)
|
||||||
module ? str(module).cast<std::string>() + "." + rec.name :
|
module_ ? str(module_).cast<std::string>() + "." + rec.name :
|
||||||
#endif
|
#endif
|
||||||
rec.name);
|
rec.name);
|
||||||
|
|
||||||
@ -658,8 +658,8 @@ inline PyObject* make_new_python_type(const type_record &rec) {
|
|||||||
else
|
else
|
||||||
Py_INCREF(type); // Keep it alive forever (reference leak)
|
Py_INCREF(type); // Keep it alive forever (reference leak)
|
||||||
|
|
||||||
if (module) // Needed by pydoc
|
if (module_) // Needed by pydoc
|
||||||
setattr((PyObject *) type, "__module__", module);
|
setattr((PyObject *) type, "__module__", module_);
|
||||||
|
|
||||||
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
|
PYBIND11_SET_OLDPY_QUALNAME(type, qualname);
|
||||||
|
|
||||||
|
@ -263,13 +263,13 @@ extern "C" {
|
|||||||
***Deprecated in favor of PYBIND11_MODULE***
|
***Deprecated in favor of PYBIND11_MODULE***
|
||||||
|
|
||||||
This macro creates the entry point that will be invoked when the Python interpreter
|
This macro creates the entry point that will be invoked when the Python interpreter
|
||||||
imports a plugin library. Please create a `module` in the function body and return
|
imports a plugin library. Please create a `module_` in the function body and return
|
||||||
the pointer to its underlying Python object at the end.
|
the pointer to its underlying Python object at the end.
|
||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
PYBIND11_PLUGIN(example) {
|
PYBIND11_PLUGIN(example) {
|
||||||
pybind11::module m("example", "pybind11 example plugin");
|
pybind11::module_ m("example", "pybind11 example plugin");
|
||||||
/// Set up bindings here
|
/// Set up bindings here
|
||||||
return m.ptr();
|
return m.ptr();
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ extern "C" {
|
|||||||
This macro creates the entry point that will be invoked when the Python interpreter
|
This macro creates the entry point that will be invoked when the Python interpreter
|
||||||
imports an extension module. The module name is given as the fist argument and it
|
imports an extension module. The module name is given as the fist argument and it
|
||||||
should not be in quotes. The second macro argument defines a variable of type
|
should not be in quotes. The second macro argument defines a variable of type
|
||||||
`py::module` which can be used to initialize the module.
|
`py::module_` which can be used to initialize the module.
|
||||||
|
|
||||||
The entry point is marked as "maybe unused" to aid dead-code detection analysis:
|
The entry point is marked as "maybe unused" to aid dead-code detection analysis:
|
||||||
since the entry point is typically only looked up at runtime and not referenced
|
since the entry point is typically only looked up at runtime and not referenced
|
||||||
@ -317,12 +317,12 @@ extern "C" {
|
|||||||
#else
|
#else
|
||||||
#define PYBIND11_DETAIL_MODULE_STATIC_DEF(name)
|
#define PYBIND11_DETAIL_MODULE_STATIC_DEF(name)
|
||||||
#define PYBIND11_DETAIL_MODULE_CREATE(name) \
|
#define PYBIND11_DETAIL_MODULE_CREATE(name) \
|
||||||
auto m = pybind11::module(PYBIND11_TOSTRING(name));
|
auto m = pybind11::module_(PYBIND11_TOSTRING(name));
|
||||||
#endif
|
#endif
|
||||||
#define PYBIND11_MODULE(name, variable) \
|
#define PYBIND11_MODULE(name, variable) \
|
||||||
PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \
|
PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \
|
||||||
PYBIND11_MAYBE_UNUSED \
|
PYBIND11_MAYBE_UNUSED \
|
||||||
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
|
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module_ &); \
|
||||||
PYBIND11_PLUGIN_IMPL(name) { \
|
PYBIND11_PLUGIN_IMPL(name) { \
|
||||||
PYBIND11_CHECK_PYTHON_VERSION \
|
PYBIND11_CHECK_PYTHON_VERSION \
|
||||||
PYBIND11_ENSURE_INTERNALS_READY \
|
PYBIND11_ENSURE_INTERNALS_READY \
|
||||||
@ -332,7 +332,7 @@ extern "C" {
|
|||||||
return m.ptr(); \
|
return m.ptr(); \
|
||||||
} PYBIND11_CATCH_INIT_EXCEPTIONS \
|
} PYBIND11_CATCH_INIT_EXCEPTIONS \
|
||||||
} \
|
} \
|
||||||
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
|
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module_ &variable)
|
||||||
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
|
@ -549,7 +549,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto obj = reinterpret_borrow<object>(src);
|
auto obj = reinterpret_borrow<object>(src);
|
||||||
object sparse_module = module::import("scipy.sparse");
|
object sparse_module = module_::import("scipy.sparse");
|
||||||
object matrix_type = sparse_module.attr(
|
object matrix_type = sparse_module.attr(
|
||||||
rowMajor ? "csr_matrix" : "csc_matrix");
|
rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
|
|
||||||
@ -580,7 +580,7 @@ struct type_caster<Type, enable_if_t<is_eigen_sparse<Type>::value>> {
|
|||||||
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
static handle cast(const Type &src, return_value_policy /* policy */, handle /* parent */) {
|
||||||
const_cast<Type&>(src).makeCompressed();
|
const_cast<Type&>(src).makeCompressed();
|
||||||
|
|
||||||
object matrix_type = module::import("scipy.sparse").attr(
|
object matrix_type = module_::import("scipy.sparse").attr(
|
||||||
rowMajor ? "csr_matrix" : "csc_matrix");
|
rowMajor ? "csr_matrix" : "csc_matrix");
|
||||||
|
|
||||||
array data(src.nonZeros(), src.valuePtr());
|
array data(src.nonZeros(), src.valuePtr());
|
||||||
|
@ -46,9 +46,9 @@
|
|||||||
}
|
}
|
||||||
\endrst */
|
\endrst */
|
||||||
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
#define PYBIND11_EMBEDDED_MODULE(name, variable) \
|
||||||
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
|
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module_ &); \
|
||||||
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \
|
||||||
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
|
auto m = pybind11::module_(PYBIND11_TOSTRING(name)); \
|
||||||
try { \
|
try { \
|
||||||
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
PYBIND11_CONCAT(pybind11_init_, name)(m); \
|
||||||
return m.ptr(); \
|
return m.ptr(); \
|
||||||
@ -64,7 +64,7 @@
|
|||||||
pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \
|
pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \
|
||||||
(PYBIND11_TOSTRING(name), \
|
(PYBIND11_TOSTRING(name), \
|
||||||
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
PYBIND11_CONCAT(pybind11_init_impl_, name)); \
|
||||||
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &variable)
|
void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module_ &variable)
|
||||||
|
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
|
||||||
@ -109,7 +109,7 @@ inline void initialize_interpreter(bool init_signal_handlers = true) {
|
|||||||
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
Py_InitializeEx(init_signal_handlers ? 1 : 0);
|
||||||
|
|
||||||
// Make .py files in the working directory available by default
|
// Make .py files in the working directory available by default
|
||||||
module::import("sys").attr("path").cast<list>().append(".");
|
module_::import("sys").attr("path").cast<list>().append(".");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \rst
|
/** \rst
|
||||||
|
@ -52,7 +52,7 @@ object eval(str expr, object global = globals(), object local = object()) {
|
|||||||
template <eval_mode mode = eval_expr, size_t N>
|
template <eval_mode mode = eval_expr, size_t N>
|
||||||
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
object eval(const char (&s)[N], object global = globals(), object local = object()) {
|
||||||
/* Support raw string literals by removing common leading whitespace */
|
/* Support raw string literals by removing common leading whitespace */
|
||||||
auto expr = (s[0] == '\n') ? str(module::import("textwrap").attr("dedent")(s))
|
auto expr = (s[0] == '\n') ? str(module_::import("textwrap").attr("dedent")(s))
|
||||||
: str(s);
|
: str(s);
|
||||||
return eval<mode>(expr, global, local);
|
return eval<mode>(expr, global, local);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
{
|
{
|
||||||
py::scoped_ostream_redirect output{std::cerr, py::module::import("sys").attr("stderr")};
|
py::scoped_ostream_redirect output{std::cerr, py::module_::import("sys").attr("stderr")};
|
||||||
std::cerr << "Hello, World!";
|
std::cerr << "Hello, World!";
|
||||||
}
|
}
|
||||||
\endrst */
|
\endrst */
|
||||||
@ -115,7 +115,7 @@ protected:
|
|||||||
public:
|
public:
|
||||||
scoped_ostream_redirect(
|
scoped_ostream_redirect(
|
||||||
std::ostream &costream = std::cout,
|
std::ostream &costream = std::cout,
|
||||||
object pyostream = module::import("sys").attr("stdout"))
|
object pyostream = module_::import("sys").attr("stdout"))
|
||||||
: costream(costream), buffer(pyostream) {
|
: costream(costream), buffer(pyostream) {
|
||||||
old = costream.rdbuf(&buffer);
|
old = costream.rdbuf(&buffer);
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ class scoped_estream_redirect : public scoped_ostream_redirect {
|
|||||||
public:
|
public:
|
||||||
scoped_estream_redirect(
|
scoped_estream_redirect(
|
||||||
std::ostream &costream = std::cerr,
|
std::ostream &costream = std::cerr,
|
||||||
object pyostream = module::import("sys").attr("stderr"))
|
object pyostream = module_::import("sys").attr("stderr"))
|
||||||
: scoped_ostream_redirect(costream,pyostream) {}
|
: scoped_ostream_redirect(costream,pyostream) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
m.noisy_function_with_error_printing()
|
m.noisy_function_with_error_printing()
|
||||||
|
|
||||||
\endrst */
|
\endrst */
|
||||||
inline class_<detail::OstreamRedirect> add_ostream_redirect(module m, std::string name = "ostream_redirect") {
|
inline class_<detail::OstreamRedirect> add_ostream_redirect(module_ m, std::string name = "ostream_redirect") {
|
||||||
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
return class_<detail::OstreamRedirect>(m, name.c_str(), module_local())
|
||||||
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
|
.def(init<bool,bool>(), arg("stdout")=true, arg("stderr")=true)
|
||||||
.def("__enter__", &detail::OstreamRedirect::enter)
|
.def("__enter__", &detail::OstreamRedirect::enter)
|
||||||
|
@ -222,7 +222,7 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
static npy_api lookup() {
|
static npy_api lookup() {
|
||||||
module_ m = module::import("numpy.core.multiarray");
|
module_ m = module_::import("numpy.core.multiarray");
|
||||||
auto c = m.attr("_ARRAY_API");
|
auto c = m.attr("_ARRAY_API");
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
void **api_ptr = (void **) PyCapsule_GetPointer(c.ptr(), NULL);
|
||||||
@ -505,7 +505,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
static object _dtype_from_pep3118() {
|
static object _dtype_from_pep3118() {
|
||||||
static PyObject *obj = module::import("numpy.core._internal")
|
static PyObject *obj = module_::import("numpy.core._internal")
|
||||||
.attr("_dtype_from_pep3118").cast<object>().release().ptr();
|
.attr("_dtype_from_pep3118").cast<object>().release().ptr();
|
||||||
return reinterpret_borrow<object>(obj);
|
return reinterpret_borrow<object>(obj);
|
||||||
}
|
}
|
||||||
|
@ -904,9 +904,9 @@ public:
|
|||||||
|
|
||||||
.. code-block:: cpp
|
.. code-block:: cpp
|
||||||
|
|
||||||
py::module m("example", "pybind11 example plugin");
|
py::module_ m("example", "pybind11 example plugin");
|
||||||
py::module m2 = m.def_submodule("sub", "A submodule of 'example'");
|
py::module_ m2 = m.def_submodule("sub", "A submodule of 'example'");
|
||||||
py::module m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
|
py::module_ m3 = m2.def_submodule("subsub", "A submodule of 'example.sub'");
|
||||||
\endrst */
|
\endrst */
|
||||||
module_ def_submodule(const char *name, const char *doc = nullptr) {
|
module_ def_submodule(const char *name, const char *doc = nullptr) {
|
||||||
std::string full_name = std::string(PyModule_GetName(m_ptr))
|
std::string full_name = std::string(PyModule_GetName(m_ptr))
|
||||||
@ -965,12 +965,15 @@ private:
|
|||||||
};
|
};
|
||||||
m_ptr = PyModule_Create(def);
|
m_ptr = PyModule_Create(def);
|
||||||
if (m_ptr == nullptr)
|
if (m_ptr == nullptr)
|
||||||
pybind11_fail("Internal error in module::module()");
|
pybind11_fail("Internal error in module_::module_()");
|
||||||
inc_ref();
|
inc_ref();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// When inside a namespace (or anywhere as long as it's not the first item on a line),
|
||||||
|
// C++20 allows "module" to be used. This is provided for backward compatibility, and for
|
||||||
|
// simplicity, if someone wants to use py::module for example, that is perfectly safe.
|
||||||
using module = module_;
|
using module = module_;
|
||||||
|
|
||||||
#if PY_MAJOR_VERSION >= 3
|
#if PY_MAJOR_VERSION >= 3
|
||||||
@ -986,7 +989,7 @@ PYBIND11_NAMESPACE_END(detail)
|
|||||||
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
|
/// or ``__main__.__dict__`` if there is no frame (usually when the interpreter is embedded).
|
||||||
inline dict globals() {
|
inline dict globals() {
|
||||||
PyObject *p = PyEval_GetGlobals();
|
PyObject *p = PyEval_GetGlobals();
|
||||||
return reinterpret_borrow<dict>(p ? p : module::import("__main__").attr("__dict__").ptr());
|
return reinterpret_borrow<dict>(p ? p : module_::import("__main__").attr("__dict__").ptr());
|
||||||
}
|
}
|
||||||
|
|
||||||
PYBIND11_NAMESPACE_BEGIN(detail)
|
PYBIND11_NAMESPACE_BEGIN(detail)
|
||||||
@ -1973,7 +1976,7 @@ PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) {
|
|||||||
file = kwargs["file"].cast<object>();
|
file = kwargs["file"].cast<object>();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
file = module::import("sys").attr("stdout");
|
file = module_::import("sys").attr("stdout");
|
||||||
} catch (const error_already_set &) {
|
} catch (const error_already_set &) {
|
||||||
/* If print() is called from code that is executed as
|
/* If print() is called from code that is executed as
|
||||||
part of garbage collection during interpreter shutdown,
|
part of garbage collection during interpreter shutdown,
|
||||||
|
@ -120,7 +120,7 @@ public:
|
|||||||
throw py::error_already_set();
|
throw py::error_already_set();
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
#else
|
#else
|
||||||
py::module::import("gc").attr("collect")();
|
py::module_::import("gc").attr("collect")();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ productively.
|
|||||||
Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
|
Instead, see the "How can I reduce the build time?" question in the "Frequently asked questions"
|
||||||
section of the documentation for good practice on splitting binding code over multiple files.
|
section of the documentation for good practice on splitting binding code over multiple files.
|
||||||
*/
|
*/
|
||||||
std::list<std::function<void(py::module &)>> &initializers() {
|
std::list<std::function<void(py::module_ &)>> &initializers() {
|
||||||
static std::list<std::function<void(py::module &)>> inits;
|
static std::list<std::function<void(py::module_ &)>> inits;
|
||||||
return inits;
|
return inits;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,13 +36,13 @@ test_initializer::test_initializer(Initializer init) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
test_initializer::test_initializer(const char *submodule_name, Initializer init) {
|
||||||
initializers().emplace_back([=](py::module &parent) {
|
initializers().emplace_back([=](py::module_ &parent) {
|
||||||
auto m = parent.def_submodule(submodule_name);
|
auto m = parent.def_submodule(submodule_name);
|
||||||
init(m);
|
init(m);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void bind_ConstructorStats(py::module &m) {
|
void bind_ConstructorStats(py::module_ &m) {
|
||||||
py::class_<ConstructorStats>(m, "ConstructorStats")
|
py::class_<ConstructorStats>(m, "ConstructorStats")
|
||||||
.def("alive", &ConstructorStats::alive)
|
.def("alive", &ConstructorStats::alive)
|
||||||
.def("values", &ConstructorStats::values)
|
.def("values", &ConstructorStats::values)
|
||||||
|
@ -10,7 +10,7 @@ namespace py = pybind11;
|
|||||||
using namespace pybind11::literals;
|
using namespace pybind11::literals;
|
||||||
|
|
||||||
class test_initializer {
|
class test_initializer {
|
||||||
using Initializer = void (*)(py::module &);
|
using Initializer = void (*)(py::module_ &);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
test_initializer(Initializer init);
|
test_initializer(Initializer init);
|
||||||
@ -18,9 +18,9 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define TEST_SUBMODULE(name, variable) \
|
#define TEST_SUBMODULE(name, variable) \
|
||||||
void test_submodule_##name(py::module &); \
|
void test_submodule_##name(py::module_ &); \
|
||||||
test_initializer name(#name, test_submodule_##name); \
|
test_initializer name(#name, test_submodule_##name); \
|
||||||
void test_submodule_##name(py::module &variable)
|
void test_submodule_##name(py::module_ &variable)
|
||||||
|
|
||||||
|
|
||||||
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
|
/// Dummy type which is not exported anywhere -- something to trigger a conversion error
|
||||||
|
@ -18,7 +18,7 @@ TEST_SUBMODULE(async_module, m) {
|
|||||||
.def(py::init<>())
|
.def(py::init<>())
|
||||||
.def("__await__", [](const SupportsAsync& self) -> py::object {
|
.def("__await__", [](const SupportsAsync& self) -> py::object {
|
||||||
static_cast<void>(self);
|
static_cast<void>(self);
|
||||||
py::object loop = py::module::import("asyncio.events").attr("get_event_loop")();
|
py::object loop = py::module_::import("asyncio.events").attr("get_event_loop")();
|
||||||
py::object f = loop.attr("create_future")();
|
py::object f = loop.attr("create_future")();
|
||||||
f.attr("set_result")(5);
|
f.attr("set_result")(5);
|
||||||
return f.attr("__await__")();
|
return f.attr("__await__")();
|
||||||
|
@ -172,12 +172,12 @@ TEST_SUBMODULE(class_, m) {
|
|||||||
struct MismatchDerived2 : MismatchBase2 { };
|
struct MismatchDerived2 : MismatchBase2 { };
|
||||||
|
|
||||||
m.def("mismatched_holder_1", []() {
|
m.def("mismatched_holder_1", []() {
|
||||||
auto mod = py::module::import("__main__");
|
auto mod = py::module_::import("__main__");
|
||||||
py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
|
py::class_<MismatchBase1, std::shared_ptr<MismatchBase1>>(mod, "MismatchBase1");
|
||||||
py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");
|
py::class_<MismatchDerived1, MismatchBase1>(mod, "MismatchDerived1");
|
||||||
});
|
});
|
||||||
m.def("mismatched_holder_2", []() {
|
m.def("mismatched_holder_2", []() {
|
||||||
auto mod = py::module::import("__main__");
|
auto mod = py::module_::import("__main__");
|
||||||
py::class_<MismatchBase2>(mod, "MismatchBase2");
|
py::class_<MismatchBase2>(mod, "MismatchBase2");
|
||||||
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>,
|
py::class_<MismatchDerived2, std::shared_ptr<MismatchDerived2>,
|
||||||
MismatchBase2>(mod, "MismatchDerived2");
|
MismatchBase2>(mod, "MismatchDerived2");
|
||||||
|
@ -12,10 +12,10 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
py::scoped_interpreter guard{};
|
py::scoped_interpreter guard{};
|
||||||
|
|
||||||
auto m = py::module::import("test_cmake_build");
|
auto m = py::module_::import("test_cmake_build");
|
||||||
if (m.attr("add")(1, 2).cast<int>() != 3)
|
if (m.attr("add")(1, 2).cast<int>() != 3)
|
||||||
throw std::runtime_error("embed.cpp failed");
|
throw std::runtime_error("embed.cpp failed");
|
||||||
|
|
||||||
py::module::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp");
|
py::module_::import("sys").attr("argv") = py::make_tuple("test.py", "embed.cpp");
|
||||||
py::eval_file(test_py_file, py::globals());
|
py::eval_file(test_py_file, py::globals());
|
||||||
}
|
}
|
||||||
|
@ -317,11 +317,11 @@ TEST_SUBMODULE(eigen, m) {
|
|||||||
// a new array (np.ones(10)) increases the chances that the temp array will be garbage
|
// a new array (np.ones(10)) increases the chances that the temp array will be garbage
|
||||||
// collected and/or that its memory will be overridden with different values.
|
// collected and/or that its memory will be overridden with different values.
|
||||||
m.def("get_elem_direct", [](Eigen::Ref<const Eigen::VectorXd> v) {
|
m.def("get_elem_direct", [](Eigen::Ref<const Eigen::VectorXd> v) {
|
||||||
py::module::import("numpy").attr("ones")(10);
|
py::module_::import("numpy").attr("ones")(10);
|
||||||
return v(5);
|
return v(5);
|
||||||
});
|
});
|
||||||
m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) {
|
m.def("get_elem_indirect", [](std::vector<Eigen::Ref<const Eigen::VectorXd>> v) {
|
||||||
py::module::import("numpy").attr("ones")(10);
|
py::module_::import("numpy").attr("ones")(10);
|
||||||
return v[0](5);
|
return v[0](5);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -51,17 +51,17 @@ PYBIND11_EMBEDDED_MODULE(throw_error_already_set, ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
|
TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
|
||||||
auto module = py::module::import("test_interpreter");
|
auto module_ = py::module_::import("test_interpreter");
|
||||||
REQUIRE(py::hasattr(module, "DerivedWidget"));
|
REQUIRE(py::hasattr(module_, "DerivedWidget"));
|
||||||
|
|
||||||
auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module.attr("__dict__"));
|
auto locals = py::dict("hello"_a="Hello, World!", "x"_a=5, **module_.attr("__dict__"));
|
||||||
py::exec(R"(
|
py::exec(R"(
|
||||||
widget = DerivedWidget("{} - {}".format(hello, x))
|
widget = DerivedWidget("{} - {}".format(hello, x))
|
||||||
message = widget.the_message
|
message = widget.the_message
|
||||||
)", py::globals(), locals);
|
)", py::globals(), locals);
|
||||||
REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5");
|
REQUIRE(locals["message"].cast<std::string>() == "Hello, World! - 5");
|
||||||
|
|
||||||
auto py_widget = module.attr("DerivedWidget")("The question");
|
auto py_widget = module_.attr("DerivedWidget")("The question");
|
||||||
auto message = py_widget.attr("the_message");
|
auto message = py_widget.attr("the_message");
|
||||||
REQUIRE(message.cast<std::string>() == "The question");
|
REQUIRE(message.cast<std::string>() == "The question");
|
||||||
|
|
||||||
@ -70,10 +70,10 @@ TEST_CASE("Pass classes and data between modules defined in C++ and Python") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Import error handling") {
|
TEST_CASE("Import error handling") {
|
||||||
REQUIRE_NOTHROW(py::module::import("widget_module"));
|
REQUIRE_NOTHROW(py::module_::import("widget_module"));
|
||||||
REQUIRE_THROWS_WITH(py::module::import("throw_exception"),
|
REQUIRE_THROWS_WITH(py::module_::import("throw_exception"),
|
||||||
"ImportError: C++ Error");
|
"ImportError: C++ Error");
|
||||||
REQUIRE_THROWS_WITH(py::module::import("throw_error_already_set"),
|
REQUIRE_THROWS_WITH(py::module_::import("throw_error_already_set"),
|
||||||
Catch::Contains("ImportError: KeyError"));
|
Catch::Contains("ImportError: KeyError"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,14 +107,14 @@ bool has_pybind11_internals_static() {
|
|||||||
|
|
||||||
TEST_CASE("Restart the interpreter") {
|
TEST_CASE("Restart the interpreter") {
|
||||||
// Verify pre-restart state.
|
// Verify pre-restart state.
|
||||||
REQUIRE(py::module::import("widget_module").attr("add")(1, 2).cast<int>() == 3);
|
REQUIRE(py::module_::import("widget_module").attr("add")(1, 2).cast<int>() == 3);
|
||||||
REQUIRE(has_pybind11_internals_builtin());
|
REQUIRE(has_pybind11_internals_builtin());
|
||||||
REQUIRE(has_pybind11_internals_static());
|
REQUIRE(has_pybind11_internals_static());
|
||||||
REQUIRE(py::module::import("external_module").attr("A")(123).attr("value").cast<int>() == 123);
|
REQUIRE(py::module_::import("external_module").attr("A")(123).attr("value").cast<int>() == 123);
|
||||||
|
|
||||||
// local and foreign module internals should point to the same internals:
|
// local and foreign module internals should point to the same internals:
|
||||||
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
|
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
|
||||||
py::module::import("external_module").attr("internals_at")().cast<uintptr_t>());
|
py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
|
||||||
|
|
||||||
// Restart the interpreter.
|
// Restart the interpreter.
|
||||||
py::finalize_interpreter();
|
py::finalize_interpreter();
|
||||||
@ -130,14 +130,14 @@ TEST_CASE("Restart the interpreter") {
|
|||||||
REQUIRE(has_pybind11_internals_builtin());
|
REQUIRE(has_pybind11_internals_builtin());
|
||||||
REQUIRE(has_pybind11_internals_static());
|
REQUIRE(has_pybind11_internals_static());
|
||||||
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
|
REQUIRE(reinterpret_cast<uintptr_t>(*py::detail::get_internals_pp()) ==
|
||||||
py::module::import("external_module").attr("internals_at")().cast<uintptr_t>());
|
py::module_::import("external_module").attr("internals_at")().cast<uintptr_t>());
|
||||||
|
|
||||||
// Make sure that an interpreter with no get_internals() created until finalize still gets the
|
// Make sure that an interpreter with no get_internals() created until finalize still gets the
|
||||||
// internals destroyed
|
// internals destroyed
|
||||||
py::finalize_interpreter();
|
py::finalize_interpreter();
|
||||||
py::initialize_interpreter();
|
py::initialize_interpreter();
|
||||||
bool ran = false;
|
bool ran = false;
|
||||||
py::module::import("__main__").attr("internals_destroy_test") =
|
py::module_::import("__main__").attr("internals_destroy_test") =
|
||||||
py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast<bool *>(ran) = true; });
|
py::capsule(&ran, [](void *ran) { py::detail::get_internals(); *static_cast<bool *>(ran) = true; });
|
||||||
REQUIRE_FALSE(has_pybind11_internals_builtin());
|
REQUIRE_FALSE(has_pybind11_internals_builtin());
|
||||||
REQUIRE_FALSE(has_pybind11_internals_static());
|
REQUIRE_FALSE(has_pybind11_internals_static());
|
||||||
@ -149,20 +149,20 @@ TEST_CASE("Restart the interpreter") {
|
|||||||
REQUIRE_FALSE(has_pybind11_internals_static());
|
REQUIRE_FALSE(has_pybind11_internals_static());
|
||||||
|
|
||||||
// C++ modules can be reloaded.
|
// C++ modules can be reloaded.
|
||||||
auto cpp_module = py::module::import("widget_module");
|
auto cpp_module = py::module_::import("widget_module");
|
||||||
REQUIRE(cpp_module.attr("add")(1, 2).cast<int>() == 3);
|
REQUIRE(cpp_module.attr("add")(1, 2).cast<int>() == 3);
|
||||||
|
|
||||||
// C++ type information is reloaded and can be used in python modules.
|
// C++ type information is reloaded and can be used in python modules.
|
||||||
auto py_module = py::module::import("test_interpreter");
|
auto py_module = py::module_::import("test_interpreter");
|
||||||
auto py_widget = py_module.attr("DerivedWidget")("Hello after restart");
|
auto py_widget = py_module.attr("DerivedWidget")("Hello after restart");
|
||||||
REQUIRE(py_widget.attr("the_message").cast<std::string>() == "Hello after restart");
|
REQUIRE(py_widget.attr("the_message").cast<std::string>() == "Hello after restart");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Subinterpreter") {
|
TEST_CASE("Subinterpreter") {
|
||||||
// Add tags to the modules in the main interpreter and test the basics.
|
// Add tags to the modules in the main interpreter and test the basics.
|
||||||
py::module::import("__main__").attr("main_tag") = "main interpreter";
|
py::module_::import("__main__").attr("main_tag") = "main interpreter";
|
||||||
{
|
{
|
||||||
auto m = py::module::import("widget_module");
|
auto m = py::module_::import("widget_module");
|
||||||
m.attr("extension_module_tag") = "added to module in main interpreter";
|
m.attr("extension_module_tag") = "added to module in main interpreter";
|
||||||
|
|
||||||
REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
|
REQUIRE(m.attr("add")(1, 2).cast<int>() == 3);
|
||||||
@ -181,9 +181,9 @@ TEST_CASE("Subinterpreter") {
|
|||||||
REQUIRE(has_pybind11_internals_static());
|
REQUIRE(has_pybind11_internals_static());
|
||||||
|
|
||||||
// Modules tags should be gone.
|
// Modules tags should be gone.
|
||||||
REQUIRE_FALSE(py::hasattr(py::module::import("__main__"), "tag"));
|
REQUIRE_FALSE(py::hasattr(py::module_::import("__main__"), "tag"));
|
||||||
{
|
{
|
||||||
auto m = py::module::import("widget_module");
|
auto m = py::module_::import("widget_module");
|
||||||
REQUIRE_FALSE(py::hasattr(m, "extension_module_tag"));
|
REQUIRE_FALSE(py::hasattr(m, "extension_module_tag"));
|
||||||
|
|
||||||
// Function bindings should still work.
|
// Function bindings should still work.
|
||||||
@ -194,8 +194,8 @@ TEST_CASE("Subinterpreter") {
|
|||||||
Py_EndInterpreter(sub_tstate);
|
Py_EndInterpreter(sub_tstate);
|
||||||
PyThreadState_Swap(main_tstate);
|
PyThreadState_Swap(main_tstate);
|
||||||
|
|
||||||
REQUIRE(py::hasattr(py::module::import("__main__"), "main_tag"));
|
REQUIRE(py::hasattr(py::module_::import("__main__"), "main_tag"));
|
||||||
REQUIRE(py::hasattr(py::module::import("widget_module"), "extension_module_tag"));
|
REQUIRE(py::hasattr(py::module_::import("widget_module"), "extension_module_tag"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Execution frame") {
|
TEST_CASE("Execution frame") {
|
||||||
@ -245,7 +245,7 @@ TEST_CASE("Reload module from file") {
|
|||||||
// Disable generation of cached bytecode (.pyc files) for this test, otherwise
|
// Disable generation of cached bytecode (.pyc files) for this test, otherwise
|
||||||
// Python might pick up an old version from the cache instead of the new versions
|
// Python might pick up an old version from the cache instead of the new versions
|
||||||
// of the .py files generated below
|
// of the .py files generated below
|
||||||
auto sys = py::module::import("sys");
|
auto sys = py::module_::import("sys");
|
||||||
bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>();
|
bool dont_write_bytecode = sys.attr("dont_write_bytecode").cast<bool>();
|
||||||
sys.attr("dont_write_bytecode") = true;
|
sys.attr("dont_write_bytecode") = true;
|
||||||
// Reset the value at scope exit
|
// Reset the value at scope exit
|
||||||
@ -267,8 +267,8 @@ TEST_CASE("Reload module from file") {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Import the module from file
|
// Import the module from file
|
||||||
auto module = py::module::import(module_name.c_str());
|
auto module_ = py::module_::import(module_name.c_str());
|
||||||
int result = module.attr("test")().cast<int>();
|
int result = module_.attr("test")().cast<int>();
|
||||||
REQUIRE(result == 1);
|
REQUIRE(result == 1);
|
||||||
|
|
||||||
// Update the module .py file with a small change
|
// Update the module .py file with a small change
|
||||||
@ -278,7 +278,7 @@ TEST_CASE("Reload module from file") {
|
|||||||
test_module.close();
|
test_module.close();
|
||||||
|
|
||||||
// Reload the module
|
// Reload the module
|
||||||
module.reload();
|
module_.reload();
|
||||||
result = module.attr("test")().cast<int>();
|
result = module_.attr("test")().cast<int>();
|
||||||
REQUIRE(result == 2);
|
REQUIRE(result == 2);
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
TEST_SUBMODULE(eval_, m) {
|
TEST_SUBMODULE(eval_, m) {
|
||||||
// test_evals
|
// test_evals
|
||||||
|
|
||||||
auto global = py::dict(py::module::import("__main__").attr("__dict__"));
|
auto global = py::dict(py::module_::import("__main__").attr("__dict__"));
|
||||||
|
|
||||||
m.def("test_eval_statements", [global]() {
|
m.def("test_eval_statements", [global]() {
|
||||||
auto local = py::dict();
|
auto local = py::dict();
|
||||||
|
@ -163,7 +163,7 @@ TEST_SUBMODULE(exceptions, m) {
|
|||||||
m.def("modulenotfound_exception_matches_base", []() {
|
m.def("modulenotfound_exception_matches_base", []() {
|
||||||
try {
|
try {
|
||||||
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
|
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
|
||||||
py::module::import("nonexistent");
|
py::module_::import("nonexistent");
|
||||||
}
|
}
|
||||||
catch (py::error_already_set &ex) {
|
catch (py::error_already_set &ex) {
|
||||||
if (!ex.matches(PyExc_ImportError)) throw;
|
if (!ex.matches(PyExc_ImportError)) throw;
|
||||||
|
@ -142,7 +142,7 @@ public:
|
|||||||
TEST_SUBMODULE(factory_constructors, m) {
|
TEST_SUBMODULE(factory_constructors, m) {
|
||||||
|
|
||||||
// Define various trivial types to allow simpler overload resolution:
|
// Define various trivial types to allow simpler overload resolution:
|
||||||
py::module m_tag = m.def_submodule("tag");
|
py::module_ m_tag = m.def_submodule("tag");
|
||||||
#define MAKE_TAG_TYPE(Name) \
|
#define MAKE_TAG_TYPE(Name) \
|
||||||
struct Name##_tag {}; \
|
struct Name##_tag {}; \
|
||||||
py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \
|
py::class_<Name##_tag>(m_tag, #Name "_tag").def(py::init<>()); \
|
||||||
|
@ -45,7 +45,7 @@ TEST_SUBMODULE(gil_scoped, m) {
|
|||||||
[](VirtClass &virt) { virt.pure_virtual_func(); });
|
[](VirtClass &virt) { virt.pure_virtual_func(); });
|
||||||
m.def("test_cross_module_gil",
|
m.def("test_cross_module_gil",
|
||||||
[]() {
|
[]() {
|
||||||
auto cm = py::module::import("cross_module_gil_utils");
|
auto cm = py::module_::import("cross_module_gil_utils");
|
||||||
auto gil_acquire = reinterpret_cast<void (*)()>(
|
auto gil_acquire = reinterpret_cast<void (*)()>(
|
||||||
PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
|
PyLong_AsVoidPtr(cm.attr("gil_acquire_funcaddr").ptr()));
|
||||||
py::gil_scoped_release gil_release;
|
py::gil_scoped_release gil_release;
|
||||||
|
@ -37,7 +37,7 @@ TEST_SUBMODULE(iostream, m) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
m.def("captured_output", [](std::string msg) {
|
m.def("captured_output", [](std::string msg) {
|
||||||
py::scoped_ostream_redirect redir(std::cout, py::module::import("sys").attr("stdout"));
|
py::scoped_ostream_redirect redir(std::cout, py::module_::import("sys").attr("stdout"));
|
||||||
std::cout << msg << std::flush;
|
std::cout << msg << std::flush;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,7 +46,7 @@ TEST_SUBMODULE(iostream, m) {
|
|||||||
py::arg("msg"), py::arg("flush")=true);
|
py::arg("msg"), py::arg("flush")=true);
|
||||||
|
|
||||||
m.def("captured_err", [](std::string msg) {
|
m.def("captured_err", [](std::string msg) {
|
||||||
py::scoped_ostream_redirect redir(std::cerr, py::module::import("sys").attr("stderr"));
|
py::scoped_ostream_redirect redir(std::cerr, py::module_::import("sys").attr("stderr"));
|
||||||
std::cerr << msg << std::flush;
|
std::cerr << msg << std::flush;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -65,8 +65,8 @@ TEST_SUBMODULE(iostream, m) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
m.def("captured_dual", [](std::string msg, std::string emsg) {
|
m.def("captured_dual", [](std::string msg, std::string emsg) {
|
||||||
py::scoped_ostream_redirect redirout(std::cout, py::module::import("sys").attr("stdout"));
|
py::scoped_ostream_redirect redirout(std::cout, py::module_::import("sys").attr("stdout"));
|
||||||
py::scoped_ostream_redirect redirerr(std::cerr, py::module::import("sys").attr("stderr"));
|
py::scoped_ostream_redirect redirerr(std::cerr, py::module_::import("sys").attr("stderr"));
|
||||||
std::cout << msg << std::flush;
|
std::cout << msg << std::flush;
|
||||||
std::cerr << emsg << std::flush;
|
std::cerr << emsg << std::flush;
|
||||||
});
|
});
|
||||||
|
@ -107,7 +107,7 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
|
|||||||
return py::make_tuple(i, j, k, kwargs); },
|
return py::make_tuple(i, j, k, kwargs); },
|
||||||
py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kw_only(), py::arg("k") /* kw-only */);
|
py::arg() /* positional */, py::arg("j") = -1 /* both */, py::kw_only(), py::arg("k") /* kw-only */);
|
||||||
|
|
||||||
m.def("register_invalid_kw_only", [](py::module m) {
|
m.def("register_invalid_kw_only", [](py::module_ m) {
|
||||||
m.def("bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); },
|
m.def("bad_kw_only", [](int i, int j) { return py::make_tuple(i, j); },
|
||||||
py::kw_only(), py::arg() /* invalid unnamed argument */, "j"_a);
|
py::kw_only(), py::arg() /* invalid unnamed argument */, "j"_a);
|
||||||
});
|
});
|
||||||
@ -138,5 +138,5 @@ TEST_SUBMODULE(kwargs_and_defaults, m) {
|
|||||||
// Make sure a class (not an instance) can be used as a default argument.
|
// Make sure a class (not an instance) can be used as a default argument.
|
||||||
// The return value doesn't matter, only that the module is importable.
|
// The return value doesn't matter, only that the module is importable.
|
||||||
m.def("class_default_argument", [](py::object a) { return py::repr(a); },
|
m.def("class_default_argument", [](py::object a) { return py::repr(a); },
|
||||||
"a"_a = py::module::import("decimal").attr("Decimal"));
|
"a"_a = py::module_::import("decimal").attr("Decimal"));
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ TEST_SUBMODULE(local_bindings, m) {
|
|||||||
// should raise a runtime error from the duplicate definition attempt. If test_class isn't
|
// should raise a runtime error from the duplicate definition attempt. If test_class isn't
|
||||||
// available it *also* throws a runtime error (with "test_class not enabled" as value).
|
// available it *also* throws a runtime error (with "test_class not enabled" as value).
|
||||||
m.def("register_local_external", [m]() {
|
m.def("register_local_external", [m]() {
|
||||||
auto main = py::module::import("pybind11_tests");
|
auto main = py::module_::import("pybind11_tests");
|
||||||
if (py::hasattr(main, "class_")) {
|
if (py::hasattr(main, "class_")) {
|
||||||
bind_local<LocalExternal, 7>(m, "LocalExternal", py::module_local());
|
bind_local<LocalExternal, 7>(m, "LocalExternal", py::module_local());
|
||||||
}
|
}
|
||||||
|
@ -207,12 +207,12 @@ TEST_SUBMODULE(methods_and_attributes, m) {
|
|||||||
// test_no_mixed_overloads
|
// test_no_mixed_overloads
|
||||||
// Raise error if trying to mix static/non-static overloads on the same name:
|
// Raise error if trying to mix static/non-static overloads on the same name:
|
||||||
.def_static("add_mixed_overloads1", []() {
|
.def_static("add_mixed_overloads1", []() {
|
||||||
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module_::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
||||||
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
emna.def ("overload_mixed1", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
|
||||||
.def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded));
|
.def_static("overload_mixed1", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded));
|
||||||
})
|
})
|
||||||
.def_static("add_mixed_overloads2", []() {
|
.def_static("add_mixed_overloads2", []() {
|
||||||
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
auto emna = py::reinterpret_borrow<py::class_<ExampleMandA>>(py::module_::import("pybind11_tests.methods_and_attributes").attr("ExampleMandA"));
|
||||||
emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded))
|
emna.def_static("overload_mixed2", static_cast<py::str ( *)(float )>(&ExampleMandA::overloaded))
|
||||||
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
|
.def ("overload_mixed2", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded));
|
||||||
})
|
})
|
||||||
@ -308,11 +308,11 @@ TEST_SUBMODULE(methods_and_attributes, m) {
|
|||||||
m.attr("debug_enabled") = false;
|
m.attr("debug_enabled") = false;
|
||||||
#endif
|
#endif
|
||||||
m.def("bad_arg_def_named", []{
|
m.def("bad_arg_def_named", []{
|
||||||
auto m = py::module::import("pybind11_tests");
|
auto m = py::module_::import("pybind11_tests");
|
||||||
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
|
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg("a") = UnregisteredType());
|
||||||
});
|
});
|
||||||
m.def("bad_arg_def_unnamed", []{
|
m.def("bad_arg_def_unnamed", []{
|
||||||
auto m = py::module::import("pybind11_tests");
|
auto m = py::module_::import("pybind11_tests");
|
||||||
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
|
m.def("should_fail", [](int, UnregisteredType) {}, py::arg(), py::arg() = UnregisteredType());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
TEST_SUBMODULE(modules, m) {
|
TEST_SUBMODULE(modules, m) {
|
||||||
// test_nested_modules
|
// test_nested_modules
|
||||||
|
// This is intentionally "py::module" to verify it still can be used in place of "py::module_"
|
||||||
py::module m_sub = m.def_submodule("subsubmodule");
|
py::module m_sub = m.def_submodule("subsubmodule");
|
||||||
m_sub.def("submodule_func", []() { return "submodule_func()"; });
|
m_sub.def("submodule_func", []() { return "submodule_func()"; });
|
||||||
|
|
||||||
@ -50,6 +51,7 @@ TEST_SUBMODULE(modules, m) {
|
|||||||
.def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default
|
.def_readwrite("a1", &B::a1) // def_readonly uses an internal reference return policy by default
|
||||||
.def_readwrite("a2", &B::a2);
|
.def_readwrite("a2", &B::a2);
|
||||||
|
|
||||||
|
// This is intentionally "py::module" to verify it still can be used in place of "py::module_"
|
||||||
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
|
m.attr("OD") = py::module::import("collections").attr("OrderedDict");
|
||||||
|
|
||||||
// test_duplicate_registration
|
// test_duplicate_registration
|
||||||
@ -60,7 +62,7 @@ TEST_SUBMODULE(modules, m) {
|
|||||||
class Dupe3 { };
|
class Dupe3 { };
|
||||||
class DupeException { };
|
class DupeException { };
|
||||||
|
|
||||||
auto dm = py::module("dummy");
|
auto dm = py::module_("dummy");
|
||||||
auto failures = py::list();
|
auto failures = py::list();
|
||||||
|
|
||||||
py::class_<Dupe1>(dm, "Dupe1");
|
py::class_<Dupe1>(dm, "Dupe1");
|
||||||
|
@ -22,7 +22,7 @@ struct DtypeCheck {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
DtypeCheck get_dtype_check(const char* name) {
|
DtypeCheck get_dtype_check(const char* name) {
|
||||||
py::module np = py::module::import("numpy");
|
py::module_ np = py::module_::import("numpy");
|
||||||
DtypeCheck check{};
|
DtypeCheck check{};
|
||||||
check.numpy = np.attr("dtype")(np.attr(name));
|
check.numpy = np.attr("dtype")(np.attr(name));
|
||||||
check.pybind11 = py::dtype::of<T>();
|
check.pybind11 = py::dtype::of<T>();
|
||||||
@ -133,7 +133,7 @@ template <typename T, typename T2> py::handle auxiliaries(T &&r, T2 &&r2) {
|
|||||||
static int data_i = 42;
|
static int data_i = 42;
|
||||||
|
|
||||||
TEST_SUBMODULE(numpy_array, sm) {
|
TEST_SUBMODULE(numpy_array, sm) {
|
||||||
try { py::module::import("numpy"); }
|
try { py::module_::import("numpy"); }
|
||||||
catch (...) { return; }
|
catch (...) { return; }
|
||||||
|
|
||||||
// test_dtypes
|
// test_dtypes
|
||||||
|
@ -255,7 +255,7 @@ struct A {};
|
|||||||
struct B {};
|
struct B {};
|
||||||
|
|
||||||
TEST_SUBMODULE(numpy_dtypes, m) {
|
TEST_SUBMODULE(numpy_dtypes, m) {
|
||||||
try { py::module::import("numpy"); }
|
try { py::module_::import("numpy"); }
|
||||||
catch (...) { return; }
|
catch (...) { return; }
|
||||||
|
|
||||||
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
|
// typeinfo may be registered before the dtype descriptor for scalar casts to work...
|
||||||
|
@ -17,7 +17,7 @@ double my_func(int x, float y, double z) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_SUBMODULE(numpy_vectorize, m) {
|
TEST_SUBMODULE(numpy_vectorize, m) {
|
||||||
try { py::module::import("numpy"); }
|
try { py::module_::import("numpy"); }
|
||||||
catch (...) { return; }
|
catch (...) { return; }
|
||||||
|
|
||||||
// test_vectorize, test_docs, test_array_collapse
|
// test_vectorize, test_docs, test_array_collapse
|
||||||
|
@ -289,7 +289,7 @@ TEST_SUBMODULE(pytypes, m) {
|
|||||||
py::print("no new line here", "end"_a=" -- ");
|
py::print("no new line here", "end"_a=" -- ");
|
||||||
py::print("next print");
|
py::print("next print");
|
||||||
|
|
||||||
auto py_stderr = py::module::import("sys").attr("stderr");
|
auto py_stderr = py::module_::import("sys").attr("stderr");
|
||||||
py::print("this goes to stderr", "file"_a=py_stderr);
|
py::print("this goes to stderr", "file"_a=py_stderr);
|
||||||
|
|
||||||
py::print("flush", "flush"_a=true);
|
py::print("flush", "flush"_a=true);
|
||||||
|
@ -117,7 +117,7 @@ TEST_SUBMODULE(stl_binders, m) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// The rest depends on numpy:
|
// The rest depends on numpy:
|
||||||
try { py::module::import("numpy"); }
|
try { py::module_::import("numpy"); }
|
||||||
catch (...) { return; }
|
catch (...) { return; }
|
||||||
|
|
||||||
// test_vector_buffer_numpy
|
// test_vector_buffer_numpy
|
||||||
|
@ -187,7 +187,7 @@ static void test_gil_from_thread() {
|
|||||||
|
|
||||||
// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
|
// Forward declaration (so that we can put the main tests here; the inherited virtual approaches are
|
||||||
// rather long).
|
// rather long).
|
||||||
void initialize_inherited_virtuals(py::module &m);
|
void initialize_inherited_virtuals(py::module_ &m);
|
||||||
|
|
||||||
TEST_SUBMODULE(virtual_functions, m) {
|
TEST_SUBMODULE(virtual_functions, m) {
|
||||||
// test_override
|
// test_override
|
||||||
@ -459,7 +459,7 @@ public:
|
|||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void initialize_inherited_virtuals(py::module &m) {
|
void initialize_inherited_virtuals(py::module_ &m) {
|
||||||
// test_inherited_virtuals
|
// test_inherited_virtuals
|
||||||
|
|
||||||
// Method 1: repeat
|
// Method 1: repeat
|
||||||
|
Loading…
Reference in New Issue
Block a user