diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 104f32206..70ba635eb 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -439,9 +439,9 @@ protected: /* Install docstring */ auto *func = (PyCFunctionObject *) m_ptr; - if (func->m_ml->ml_doc) - std::free(const_cast(func->m_ml->ml_doc)); - func->m_ml->ml_doc = strdup(signatures.c_str()); + std::free(const_cast(func->m_ml->ml_doc)); + // Install docstring if it's non-empty (when at least one option is enabled) + func->m_ml->ml_doc = signatures.empty() ? nullptr : strdup(signatures.c_str()); if (rec->is_method) { m_ptr = PYBIND11_INSTANCE_METHOD_NEW(m_ptr, rec->scope.ptr()); diff --git a/tests/test_docstring_options.cpp b/tests/test_docstring_options.cpp index 8c8f79fd5..8a97af55f 100644 --- a/tests/test_docstring_options.cpp +++ b/tests/test_docstring_options.cpp @@ -45,6 +45,14 @@ TEST_SUBMODULE(docstring_options, m) { m.def("test_function7", [](int, int) {}, py::arg("a"), py::arg("b"), "A custom docstring"); + { + py::options options; + options.disable_user_defined_docstrings(); + options.disable_function_signatures(); + + m.def("test_function8", []() {}); + } + { py::options options; options.disable_user_defined_docstrings(); diff --git a/tests/test_docstring_options.py b/tests/test_docstring_options.py index 87d80d2df..8ee661388 100644 --- a/tests/test_docstring_options.py +++ b/tests/test_docstring_options.py @@ -34,6 +34,9 @@ def test_docstring_options(): assert m.test_function7.__doc__.startswith("test_function7(a: int, b: int) -> None") assert m.test_function7.__doc__.endswith("A custom docstring\n") + # when all options are disabled, no docstring (instead of an empty one) should be generated + assert m.test_function8.__doc__ is None + # Suppression of user-defined docstrings for non-function objects assert not m.DocstringTestFoo.__doc__ assert not m.DocstringTestFoo.value_prop.__doc__