diff --git a/include/pybind11/detail/common.h b/include/pybind11/detail/common.h index 7e06287d1c9..ae37eb4babb 100644 --- a/include/pybind11/detail/common.h +++ b/include/pybind11/detail/common.h @@ -311,18 +311,19 @@ extern "C" { #define PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \ static PyModuleDef PYBIND11_CONCAT(pybind11_module_def_, name); #define PYBIND11_DETAIL_MODULE_CREATE(name) \ - auto m = pybind11::detail::create_top_level_module( \ + auto m = ::pybind11::detail::create_top_level_module( \ PYBIND11_TOSTRING(name), nullptr, \ &PYBIND11_CONCAT(pybind11_module_def_, name)); #else #define PYBIND11_DETAIL_MODULE_STATIC_DEF(name) #define PYBIND11_DETAIL_MODULE_CREATE(name) \ - auto m = pybind11::module_(PYBIND11_TOSTRING(name)); + auto m = ::pybind11::detail::create_top_level_module( \ + PYBIND11_TOSTRING(name), nullptr) #endif #define PYBIND11_MODULE(name, variable) \ PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \ 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_CHECK_PYTHON_VERSION \ PYBIND11_ENSURE_INTERNALS_READY \ @@ -332,7 +333,7 @@ extern "C" { return m.ptr(); \ } 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) diff --git a/include/pybind11/embed.h b/include/pybind11/embed.h index 2d94e170067..2085c820fe6 100644 --- a/include/pybind11/embed.h +++ b/include/pybind11/embed.h @@ -45,26 +45,27 @@ }); } \endrst */ -#define PYBIND11_EMBEDDED_MODULE(name, variable) \ - static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module_ &); \ - static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ - auto m = pybind11::module_(PYBIND11_TOSTRING(name)); \ - try { \ - PYBIND11_CONCAT(pybind11_init_, name)(m); \ - return m.ptr(); \ - } catch (pybind11::error_already_set &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } catch (const std::exception &e) { \ - PyErr_SetString(PyExc_ImportError, e.what()); \ - return nullptr; \ - } \ - } \ - PYBIND11_EMBEDDED_MODULE_IMPL(name) \ - pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \ - (PYBIND11_TOSTRING(name), \ - PYBIND11_CONCAT(pybind11_init_impl_, name)); \ - void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module_ &variable) +#define PYBIND11_EMBEDDED_MODULE(name, variable) \ + PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \ + static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \ + static PyObject PYBIND11_CONCAT(*pybind11_init_wrapper_, name)() { \ + PYBIND11_DETAIL_MODULE_CREATE(name) \ + try { \ + PYBIND11_CONCAT(pybind11_init_, name)(m); \ + return m.ptr(); \ + } catch (::pybind11::error_already_set &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } catch (const std::exception &e) { \ + PyErr_SetString(PyExc_ImportError, e.what()); \ + return nullptr; \ + } \ + } \ + PYBIND11_EMBEDDED_MODULE_IMPL(name) \ + ::pybind11::detail::embedded_module PYBIND11_CONCAT(pybind11_module_, name) \ + (PYBIND11_TOSTRING(name), \ + PYBIND11_CONCAT(pybind11_init_impl_, name)); \ + void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &variable) PYBIND11_NAMESPACE_BEGIN(PYBIND11_NAMESPACE) diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index db0efd445e3..68bc7325e35 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -856,14 +856,15 @@ class cpp_function : public function { } }; - -#if PY_MAJOR_VERSION >= 3 class module_; PYBIND11_NAMESPACE_BEGIN(detail) +#if PY_MAJOR_VERSION >= 3 inline module_ create_top_level_module(const char *name, const char *doc, PyModuleDef *def); -PYBIND11_NAMESPACE_END(detail) +#else +inline module_ create_top_level_module(const char *name, const char *doc); #endif +PYBIND11_NAMESPACE_END(detail) /// Wrapper for Python extension modules class module_ : public object { @@ -871,17 +872,14 @@ class module_ : public object { PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check) /// Create a new top-level Python module with the given name and docstring - explicit module_(const char *name, const char *doc = nullptr) + PYBIND11_DEPRECATED("Use PYBIND11_MODULE, module_::def_submodule, or module_::import instead") + explicit module_(const char *name, const char *doc = nullptr) { #if PY_MAJOR_VERSION >= 3 - : module_(name, doc, new PyModuleDef()) {} + *this = detail::create_top_level_module(name, doc, new PyModuleDef()); #else - { - m_ptr = Py_InitModule3(name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr); - if (m_ptr == nullptr) - pybind11_fail("Internal error in module_::module_()"); - inc_ref(); - } + *this = detail::create_top_level_module(name, doc); #endif + } /** \rst Create Python binding for a new function within the module scope. ``Func`` @@ -946,29 +944,6 @@ class module_ : public object { PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); } - -private: -#if PY_MAJOR_VERSION >= 3 - friend module_ detail::create_top_level_module(const char *, const char *, PyModuleDef *); - - explicit module_(const char *name, const char *doc, PyModuleDef *def) { - def = new (def) PyModuleDef { // Placement new (not an allocation). - /* m_base */ PyModuleDef_HEAD_INIT, - /* m_name */ name, - /* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr, - /* m_size */ -1, - /* m_methods */ nullptr, - /* m_slots */ nullptr, - /* m_traverse */ nullptr, - /* m_clear */ nullptr, - /* m_free */ nullptr - }; - m_ptr = PyModule_Create(def); - if (m_ptr == nullptr) - pybind11_fail("Internal error in module_::module_()"); - inc_ref(); - } -#endif }; // When inside a namespace (or anywhere as long as it's not the first item on a line), @@ -976,13 +951,35 @@ class module_ : public object { // simplicity, if someone wants to use py::module for example, that is perfectly safe. using module = module_; -#if PY_MAJOR_VERSION >= 3 PYBIND11_NAMESPACE_BEGIN(detail) +#if PY_MAJOR_VERSION >= 3 inline module_ create_top_level_module(const char *name, const char *doc, PyModuleDef *def) { - return module_(name, doc, def); + def = new (def) PyModuleDef { // Placement new (not an allocation). + /* m_base */ PyModuleDef_HEAD_INIT, + /* m_name */ name, + /* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr, + /* m_size */ -1, + /* m_methods */ nullptr, + /* m_slots */ nullptr, + /* m_traverse */ nullptr, + /* m_clear */ nullptr, + /* m_free */ nullptr + }; + auto m = PyModule_Create(def); + if (m == nullptr) + pybind11_fail("Internal error in detail::create_top_level_module()"); + // TODO: Should be reinterpret_steal, but Python also steals it again when returned from PyInit_... + return reinterpret_borrow(m); +} +#else +inline module_ create_top_level_module(const char *name, const char *doc) { + auto m = Py_InitModule3(name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr); + if (m == nullptr) + pybind11_fail("Internal error in detail::create_top_level_module()"); + return reinterpret_borrow(m); } -PYBIND11_NAMESPACE_END(detail) #endif +PYBIND11_NAMESPACE_END(detail) /// \ingroup python_builtins /// Return a dictionary representing the global variables in the current execution frame, diff --git a/tests/test_modules.cpp b/tests/test_modules.cpp index 897cf89c468..23373d91a0e 100644 --- a/tests/test_modules.cpp +++ b/tests/test_modules.cpp @@ -62,7 +62,11 @@ TEST_SUBMODULE(modules, m) { class Dupe3 { }; class DupeException { }; - auto dm = py::module_("dummy"); +#if PY_MAJOR_VERSION >= 3 + auto dm = py::detail::create_top_level_module("dummy", nullptr, new PyModuleDef); +#else + auto dm = py::detail::create_top_level_module("dummy", nullptr); +#endif auto failures = py::list(); py::class_(dm, "Dupe1");