Skip to content

Commit

Permalink
Can disable the section headings in docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
AWhetter committed Apr 4, 2021
1 parent ee182af commit 659a12f
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 19 deletions.
2 changes: 1 addition & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ The valid options are:
* `-DPYBIND11_NOPYTHON=ON`: Disable all Python searching (disables tests)
* `-DBUILD_TESTING=ON`: Enable the tests
* `-DDOWNLOAD_CATCH=ON`: Download catch to build the C++ tests
* `-DOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests
* `-DDOWNLOAD_EIGEN=ON`: Download Eigen for the NumPy tests
* `-DPYBIND11_INSTALL=ON/OFF`: Enable the install target (on by default for the
master project)
* `-DUSE_PYTHON_INSTALL_DIR=ON`: Try to install into the python dir
Expand Down
36 changes: 35 additions & 1 deletion docs/advanced/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,43 @@ For example:
|
| Add two floating points numbers together.
Calling ``options.disable_function_signatures()``, as shown previously,
Calling ``options.disable_function_signatures()`` as shown previously,
will cause docstrings to be generated without the prepended function signatures
and without the section headings.
To disable only the sections headings, use ``options.disable_section_headings()``:

.. code-block:: cpp
PYBIND11_MODULE(example, m) {
py::options options;
options.disable_section_headings();
m.def("add", [](int a, int b)->int { return a + b; },
"A function which adds two numbers.\n"); // Note the additional newline here.
m.def("add", [](float a, float b)->float { return a + b; },
"Internally, a simple addition is performed.");
m.def("add", [](py::none a, py::none b)->py::none { return py::none(); },
"Both numbers can be None, and None will be returned.");
}
The above example would produce the following docstring:

.. code-block:: pycon
>>> help(example.add)
add(...)
| add(arg0: int, arg1: int) -> int
| add(arg0: float, arg1: float) -> float
| add(arg0: None, arg1: None) -> None
| A function which adds two numbers.
|
| Internally, a simple addition is performed.
| Both numbers can be None, and None will be returned.
Not every overload must supply a docstring.
You may find it easier for a single overload to supply the entire docstring.

.. [#f4] http://www.sphinx-doc.org
.. [#f5] http://github.com/pybind/python_example
Expand Down
7 changes: 7 additions & 0 deletions include/pybind11/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,18 @@ class options {

options& enable_function_signatures() & { global_state().show_function_signatures = true; return *this; }

options& disable_section_headings() & { global_state().show_section_headings = false; return *this; }

options& enable_section_headings() & { global_state().show_section_headings = true; return *this; }

// Getter methods (return the global state):

static bool show_user_defined_docstrings() { return global_state().show_user_defined_docstrings; }

static bool show_function_signatures() { return global_state().show_function_signatures; }

static bool show_section_headings() { return global_state().show_section_headings; }

// This type is not meant to be allocated on the heap.
void* operator new(size_t) = delete;

Expand All @@ -52,6 +58,7 @@ class options {
struct state {
bool show_user_defined_docstrings = true; //< Include user-supplied texts in docstrings.
bool show_function_signatures = true; //< Include auto-generated function signatures in docstrings.
bool show_section_headings = true; //< Include section headings in docstrings.
};

static state &global_state() {
Expand Down
26 changes: 15 additions & 11 deletions include/pybind11/pybind11.h
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ class cpp_function : public function {

std::string signatures;
int index = 0;
bool first_user_def = true;
/* Create a nice pydoc rec including all signatures and
docstrings of the functions in the overload chain */
if (chain && options::show_function_signatures()) {
Expand All @@ -458,12 +459,16 @@ class cpp_function : public function {
signatures += it->signature;
signatures += "\n";
}
signatures += "\nOverloaded function.\n\n";
if (options::show_section_headings())
signatures += "\nOverloaded function.\n\n";
else
first_user_def = false;
}
// Then specific overload signatures
bool first_user_def = true;
const bool show_signature_headings = options::show_function_signatures()
&& options::show_section_headings();
for (auto it = chain_start; it != nullptr; it = it->next) {
if (options::show_function_signatures()) {
if (show_signature_headings) {
if (index > 0) signatures += "\n";
if (chain)
signatures += std::to_string(++index) + ". ";
Expand All @@ -472,15 +477,14 @@ class cpp_function : public function {
signatures += "\n";
}
if (it->doc && strlen(it->doc) > 0 && options::show_user_defined_docstrings()) {
// If we're appending another docstring, and aren't printing function signatures, we
// need to append a newline first:
if (!options::show_function_signatures()) {
if (first_user_def) first_user_def = false;
else signatures += "\n";
}
if (options::show_function_signatures()) signatures += "\n";
// If we're appending another docstring, and aren't printing signature headings,
// we need to append a newline first:
if (!show_signature_headings && first_user_def)
first_user_def = false;
else
signatures += "\n";
signatures += it->doc;
if (options::show_function_signatures()) signatures += "\n";
if (show_signature_headings) signatures += "\n";
}
}

Expand Down
23 changes: 17 additions & 6 deletions tests/test_factory_constructors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,23 @@ TEST_SUBMODULE(factory_constructors, m) {
.def(py::init([](py::handle, int v, py::handle) { return TestFactoryHelper::construct1(v); }))
.def_readwrite("value", &TestFactory1::value)
;
py::class_<TestFactory2>(m, "TestFactory2")
.def(py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }))
.def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); }))
.def(py::init([](move_tag) { return TestFactoryHelper::construct2(); }))
.def_readwrite("value", &TestFactory2::value)
;
{
py::options options;
options.disable_section_headings();

py::class_<TestFactory2>(m, "TestFactory2")
.def(
py::init([](pointer_tag, int v) { return TestFactoryHelper::construct2(v); }),
"This is one part of the docstring."
)
.def(py::init([](unique_ptr_tag, std::string v) { return TestFactoryHelper::construct2(v); }))
.def(
py::init([](move_tag) { return TestFactoryHelper::construct2(); }),
"This is the other part of the docstring."
)
.def_readwrite("value", &TestFactory2::value)
;
}

// Stateful & reused:
int c = 1;
Expand Down
12 changes: 12 additions & 0 deletions tests/test_factory_constructors.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ def test_init_factory_signature(msg):
""" # noqa: E501 line too long
)

assert (
msg(m.TestFactory2.__init__.__doc__)
== """
__init__(self: m.factory_constructors.TestFactory2, arg0: m.factory_constructors.tag.pointer_tag, arg1: int) -> None
__init__(self: m.factory_constructors.TestFactory2, arg0: m.factory_constructors.tag.unique_ptr_tag, arg1: str) -> None
__init__(self: m.factory_constructors.TestFactory2, arg0: m.factory_constructors.tag.move_tag) -> None
This is one part of the docstring.
This is the other part of the docstring.
""" # noqa: E501 line too long
)


def test_init_factory_casting():
"""Tests py::init_factory() wrapper with various upcasting and downcasting returns"""
Expand Down

0 comments on commit 659a12f

Please sign in to comment.