Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use PyModule_New in module_ public constructor #2551

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions docs/upgrade.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,47 @@ to a new version. But it goes into more detail. This includes things like
deprecated APIs and their replacements, build system changes, general code
modernization and other useful information.

.. _upgrade-guide-2.7:

v2.7
====

The previously-deprecated constructor of ``py::module_`` now creates a Python
module object that is *not* used as the top-level module of a C extension.
Previous usage of the deprecated ``PYBIND11_PLUGIN`` macro using the constructor
instead of ``py::module_::create_extension_module`` will result in the following error
on import: ``SystemError: initialization of example did not return an extension module``.

In this case, change the following doubly-deprecated, memory-leaking pattern:

.. code-block:: cpp

PYBIND11_PLUGIN(example) {
auto m = pybind11::module_("example", "pybind11 example plugin");
/// Set up bindings here
return m.ptr();
}

into this:

.. code-block:: cpp

static pybind11::module_::module_def example_module_def;
PYBIND11_PLUGIN(example) {
auto m = pybind11::module_::create_extension_module(
"example", "pybind11 example plugin", &example_module_def);
/// Set up bindings here
return m.ptr();
}

or, preferably, avoid the deprecated ``PYBIND11_PLUGIN`` completely:

.. code-block:: cpp

PYBIND11_MODULE(example, m) {
/// Set up bindings here
}

.. _upgrade-guide-2.6:

v2.6
Expand Down
4 changes: 3 additions & 1 deletion include/pybind11/detail/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,8 +272,10 @@ extern "C" {

.. code-block:: cpp

static pybind11::module_::module_def example_module_def;
PYBIND11_PLUGIN(example) {
pybind11::module_ m("example", "pybind11 example plugin");
auto m = pybind11::module_::create_extension_module(
"example", "pybind11 example plugin", &example_module_def);
/// Set up bindings here
return m.ptr();
}
Expand Down
31 changes: 25 additions & 6 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -887,19 +887,38 @@ class cpp_function : public function {
}
};

/// Wrapper for Python extension modules
/// Wrapper for Python modules
class module_ : public object {
public:
PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)

/// Create a new top-level Python module with the given name and docstring
PYBIND11_DEPRECATED("Use PYBIND11_MODULE or module_::create_extension_module instead")
YannickJadoul marked this conversation as resolved.
Show resolved Hide resolved
/** \rst
Create a new top-level Python module with the given name and docstring.

Note that this cannot be used as the top-level module for a C extension.
Use `module_::create_extension_module` to create a module object that is
accepted by Python as top-level C extension module, returned from the
extension's ``PyInit_foo`` entry point (``initfoo`` in Python 2).
If you do *not* need a top-level C extension module, this constructor has
the advantage of not needing a ``PyModuleDef`` and thus being easier to use
w.r.t. memory management.
\endrst */
explicit module_(const char *name, const char *doc = nullptr) {
#if PY_MAJOR_VERSION >= 3
*this = create_extension_module(name, doc, new PyModuleDef());
#if defined(PYPY_VERSION) && (PYPY_VERSION_NUM < 0x07030400)
m_ptr = PyModule_New(const_cast<char *>(name));
#else
*this = create_extension_module(name, doc, nullptr);
m_ptr = PyModule_New(name);
#endif
if (!m_ptr)
pybind11_fail("Could not allocate module object!");
if (doc && options::show_user_defined_docstrings()) {
#if PY_MAJOR_VERSION >= 3 && !defined(PYPY_VERSION)
if (PyModule_SetDocString(m_ptr, doc) != 0)
throw error_already_set();
#else
setattr(m_ptr, "__doc__", PYBIND11_STR_TYPE(doc));
#endif
}
}

/** \rst
Expand Down
3 changes: 1 addition & 2 deletions tests/test_modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,7 @@ TEST_SUBMODULE(modules, m) {
class Dupe3 { };
class DupeException { };

// Go ahead and leak, until we have a non-leaking py::module_ constructor
auto dm = py::module_::create_extension_module("dummy", nullptr, new py::module_::module_def);
auto dm = py::module_("dummy");
auto failures = py::list();

py::class_<Dupe1>(dm, "Dupe1");
Expand Down