Unify Python 2 & 3 py::module constructor, and make contructor with pre-allocated PyModuleDef private (#2534)

This commit is contained in:
Yannick Jadoul 2020-10-02 16:01:24 +02:00 committed by GitHub
parent 6d2d08db00
commit 07b069a55b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 17 deletions

View File

@ -311,7 +311,7 @@ extern "C" {
#define PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \ #define PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \
static PyModuleDef PYBIND11_CONCAT(pybind11_module_def_, name); static PyModuleDef PYBIND11_CONCAT(pybind11_module_def_, name);
#define PYBIND11_DETAIL_MODULE_CREATE(name) \ #define PYBIND11_DETAIL_MODULE_CREATE(name) \
auto m = pybind11::module( \ auto m = pybind11::detail::create_top_level_module( \
PYBIND11_TOSTRING(name), nullptr, \ PYBIND11_TOSTRING(name), nullptr, \
&PYBIND11_CONCAT(pybind11_module_def_, name)); &PYBIND11_CONCAT(pybind11_module_def_, name));
#else #else

View File

@ -856,35 +856,32 @@ protected:
} }
}; };
#if PY_MAJOR_VERSION >= 3
class module_;
PYBIND11_NAMESPACE_BEGIN(detail)
inline module_ create_top_level_module(const char *name, const char *doc, PyModuleDef *def);
PYBIND11_NAMESPACE_END(detail)
#endif
/// Wrapper for Python extension modules /// Wrapper for Python extension modules
class module_ : public object { class module_ : public object {
public: public:
PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check) PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)
/// Create a new top-level Python module with the given name and docstring /// Create a new top-level Python module with the given name and docstring
explicit module_(const char *name, const char *doc = nullptr)
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
explicit module_(const char *name, const char *doc = nullptr, PyModuleDef *def = nullptr) { : module_(name, doc, new PyModuleDef()) {}
if (!def) def = new PyModuleDef();
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);
#else #else
explicit module_(const char *name, const char *doc = nullptr) { {
m_ptr = Py_InitModule3(name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr); m_ptr = Py_InitModule3(name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr);
#endif
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
/** \rst /** \rst
Create Python binding for a new function within the module scope. ``Func`` Create Python binding for a new function within the module scope. ``Func``
@ -949,10 +946,41 @@ public:
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */); 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
}; };
using module = module_; using module = module_;
#if PY_MAJOR_VERSION >= 3
PYBIND11_NAMESPACE_BEGIN(detail)
inline module_ create_top_level_module(const char *name, const char *doc, PyModuleDef *def) {
return module_(name, doc, def);
}
PYBIND11_NAMESPACE_END(detail)
#endif
/// \ingroup python_builtins /// \ingroup python_builtins
/// Return a dictionary representing the global variables in the current execution frame, /// Return a dictionary representing the global variables in the current execution frame,
/// 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).