Skip to content
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
45 changes: 45 additions & 0 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,14 @@ class module_ : public object {
return *this;
}

/** \rst
Overload of `def` taking the function name as a ``std::string``.
\endrst */
template <typename Func, typename... Extra>
module_ &def(const std::string &name_, Func &&f, const Extra &...extra) {
return def(name_.c_str(), f, std::forward<Extra>(extra)...);
}

/** \rst
Create and return a new Python submodule with the given name and docstring.
This also works recursively, i.e.
Expand Down Expand Up @@ -1587,6 +1595,18 @@ class module_ : public object {
return result;
}

/** \rst
Overload of `def_submodule` taking the function name and documentation as ``std::string``.
\endrst */
module_ def_submodule(const std::string &name, const std::string &doc) {
return def_submodule(name.c_str(), doc.c_str());
}

/** \rst
Overload of `def_submodule` taking the function name as a ``std::string``.
\endrst */
module_ def_submodule(const std::string &name) { return def_submodule(name.c_str(), nullptr); }

/// Import and return a module or throws `error_already_set`.
static module_ import(const char *name) {
PyObject *obj = PyImport_ImportModule(name);
Expand All @@ -1596,6 +1616,11 @@ class module_ : public object {
return reinterpret_steal<module_>(obj);
}

/** \rst
Overload of `import` taking the function name as a ``std::string``.
\endrst */
static module_ import(const std::string &name) { return import(name.c_str()); }

/// Reload the module or throws `error_already_set`.
void reload() {
PyObject *obj = PyImport_ReloadModule(ptr());
Expand All @@ -1622,6 +1647,14 @@ class module_ : public object {
PyModule_AddObject(ptr(), name, obj.inc_ref().ptr() /* steals a reference */);
}

/** \rst
Overload of `add_object` taking the function name as a ``std::string``.
\endrst */
PYBIND11_NOINLINE void
add_object(const std::string &name, handle obj, bool overwrite = false) {
return add_object(name.c_str(), obj, overwrite);
}

// DEPRECATED (since PR #5688): Use PyModuleDef directly instead.
using module_def = PyModuleDef;

Expand Down Expand Up @@ -1662,6 +1695,18 @@ class module_ : public object {
// For Python 2, reinterpret_borrow was correct.
return reinterpret_borrow<module_>(m);
}

/** \rst
Overload of `create_extension_module` taking the module name and documentation as
``std::string``.
\endrst */
static module_ create_extension_module(const std::string &name,
const std::string &doc,
PyModuleDef *def,
mod_gil_not_used gil_not_used
= mod_gil_not_used(false)) {
return create_extension_module(name.c_str(), doc.c_str(), def, gil_not_used);
}
};

PYBIND11_NAMESPACE_BEGIN(detail)
Expand Down
13 changes: 13 additions & 0 deletions tests/test_exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,19 @@ TEST_SUBMODULE(exceptions, m) {
return false;
});

m.def("modulenotfound_exception_matches_base_string", []() {
try {
// On Python >= 3.6, this raises a ModuleNotFoundError, a subclass of ImportError
py::module_::import(std::string("nonexistent"));
} catch (py::error_already_set &ex) {
if (!ex.matches(PyExc_ImportError)) {
throw;
}
return true;
}
return false;
});

m.def("throw_already_set", [](bool err) {
if (err) {
py::set_error(PyExc_ValueError, "foo");
Expand Down
1 change: 1 addition & 0 deletions tests/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ def test_exception_matches():
assert m.exception_matches()
assert m.exception_matches_base()
assert m.modulenotfound_exception_matches_base()
assert m.modulenotfound_exception_matches_base_string()


def test_custom(msg):
Expand Down
7 changes: 7 additions & 0 deletions tests/test_modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,11 @@ TEST_SUBMODULE(modules, m) {
});

m.def("def_submodule", [](py::module_ m, const char *name) { return m.def_submodule(name); });

// Test std::string versions of def_submodule and def
py::module m_sub_string = m.def_submodule(std::string("submodule_string"));
m_sub_string.def(std::string("submodule_string_func"),
[]() { return "submodule_string_func()"; });
m_sub_string.def(
std::string("submodule_string_func_with_arg"), [](int x) { return x + 1; }, py::arg("x"));
}
9 changes: 9 additions & 0 deletions tests/test_modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import env
from pybind11_tests import ConstructorStats
from pybind11_tests import modules as m
from pybind11_tests.modules import submodule_string as mstr
from pybind11_tests.modules import subsubmodule as ms


Expand All @@ -25,6 +26,14 @@ def test_nested_modules():

assert ms.submodule_func() == "submodule_func()"

assert (
pybind11_tests.modules.submodule_string.__name__
== "pybind11_tests.modules.submodule_string"
)

assert mstr.submodule_string_func() == "submodule_string_func()"
assert mstr.submodule_string_func_with_arg(x=2) == 3


def test_reference_internal():
b = ms.B()
Expand Down
Loading