pybind / pybind11

Seamless operability between C++11 and Python
https://pybind11.readthedocs.io/
Other
15.65k stars 2.1k forks source link

[BUG] Overloaded functions - indentation in string literal docstrings unexpectedly breaks sphinx parsing #3037

Open ka-bo opened 3 years ago

ka-bo commented 3 years ago

TLDR

Docstings of overloading functions may break "consistent indentation", which is required for the docstring to be parsed by sphinx (or help()) correctly if the docstring contains indentation.

In my opinion this qualifies as unexpected behaviour, especially since the documentation explicitly mentions "consistent indentation" in string literals to be dealt with correctly by sphinx.

Description

I have possible encountered a problem with docstrings of overloaded functions. In C++ you will want to indent your docstrings (within string literals) to make the code more readable. The documentation mentions that sphinx will ignore consistent indentations, which works for method definitions in general. However, with overloaded functions indentation poses a problem and sphinx was not able to parse my docstrings correctly.

Probably this becomes more clear with a code example. These two dummy functions

m.def("dummy_int", [](int a){std::cout << "int " << a;}, R"pbdoc(
    Dummy function, print and int

    Args:
        a: an integer
    )pbdoc");

and

m.def("dummy_int_unindet", [](int a){std::cout << "int " << a;}, R"pbdoc(
Dummy function, print and int

Args:
    a: an integer
)pbdoc");

only differ by the indentation within their docstrings.

Calling print(m.dummy_int.__doc__) yields

dummy_int(self: int) -> None

    Dummy function, print and int

    Args:
        a: an integer

and print(m.dummy_int_unindent.__doc__)

dummy_int_unindent(self: int) -> None

Dummy function, print and int

Args:
  a: an integer

In this case the indentation within the docstrings is consistent, hence, help() and also sphinx are able to deal with this, the resulting outputs are equal.

However, when defining the overloaded functions

m.def("dummy", [](int a){std::cout << "int " << a;}, R"pbdoc(
    Dummy overloaded function, print a INT

    Args:
        a: an integer
    )pbdoc");

m.def("dummy", [](float a){std::cout << "float " << a;}, R"pbdoc(
    Dummy overloaded function, print a FLOAT

    Args:
        a: a float
    )pbdoc");

and

m.def("dummy_unindent", [](int a){std::cout << "int " << a;}, R"pbdoc(
Dummy overloaded function, print a INT

Args:
    a: an integer
)pbdoc");

m.def("dummy_unindent", [](float a){std::cout << "float " << a;}, R"pbdoc(
Dummy overloaded function, print a FLOAT

Args:
    a: a float
)pbdoc");

calling print(m.dummy.__doc__) now yields

dummy(*args, **kwargs)
Overloaded function.

1. dummy(self: int) -> None

    Dummy overloaded function, print a INT

    Args:
        a: an integer

2. dummy(self: float) -> None

    Dummy overloaded function, print a FLOAT

    Args:
        a: a float

and print(m.dummy_unindent.__doc__) gives

dummy_unindent(*args, **kwargs)
Overloaded function.

1. dummy_unindent(self: int) -> None

Dummy overloaded function, print a INT

Args:
    a: an integer

2. dummy_unindent(self: float) -> None

Dummy overloaded function, print a FLOAT

Args:
    a: a float

As far as I have tested it, sphinx is not able to deal with the first, indented variant correctly. Also help() displays differently indented result for the two overloaded functions. I suppose, the parsing fails because the indentation is not consistent since the Overloaded function sets the level of indentation.

Maybe there is an easy fix possible with the composing of the overloaded function docstring?

finnBsch commented 1 year ago

Any news on this?

lkiem commented 12 months ago

Are there any news on this?