sphinx
sphinx copied to clipboard
autodoc: Allow overloaded functions to have different docstrings
If would be great if sphinx could emit all of the docstrings for something like:
from typing import overload
@overload
def my_bytes(n: int):
""" construct an empty array of n bytes """
@overload
def my_bytes(s: bytes):
""" copy an existing bytes-like object """
def my_bytes(b):
""" Some common docstring """
return bytes(b)
As of the fix to #3610, autodoc emits:
.. function:: my_bytes(n: int)
my_bytes(s: bytes)
Some common docstring
but does not extract the first two docstrings.
Perhaps one reasonable option would be to emit
.. function:: my_bytes(n: int)
construct an empty array of n bytes
Some common docstring
.. function:: my_bytes(s: bytes)
copy an existing bytes-like object
Some common docstring
although this doesn't scale to .. class particularly well.
Another choice would be to render numbers next to the overloads (in the style of cppreference), and then refer to them in the text. In its most minimal form, that would be:
.. function:: my_bytes(n: int)
my_bytes(s: bytes)
:number-overloads:
1. construct an empty array of n bytes
2. copy an existing bytes-like object
Some common docstring
but perhaps new directives or roles could be introduced to render that better:
.. function:: my_bytes(n: int)
my_bytes(s: bytes)
.. overloadref::1 # presence of these makes the numbers appear as needed.
construct an empty array of n bytes
.. overloadref::2
copy an existing bytes-like object
Some common docstring
It sounds good. But it is very difficult to support inheritance, f-string and other features. And I think this is not commonly used.
I don't see how f-string or inheritance would come into play here: f-strings cannot be used as docstrings anyway, and inheritance seems already handled by the existing patch?
It is great to get overload support! Perhaps I missed it in one of the other issues/PRs but is it correctly understood that only
.. function:: my_bytes(n: int)
my_bytes(s: bytes)
is supposed to work right now, while
.. function:: my_bytes(n: int)
.. function:: my_bytes(s: bytes)
yields a duplication error? It would be great if both styles are supported :-).
@jakobandersen: I think that
.. function:: my_bytes(n: int)
my_bytes(s: bytes)
has worked for quite a long time. What changed recently is that @typing.overload causes it to be emitted automatically.
I think your problem can be solved with:
.. function:: my_bytes(n: int)
:no-index:
.. function:: my_bytes(s: bytes)
Ah, I see. I suggest to add a note in the Python domain documentation (not sure what the best way to write it is currently).
Indeed the :no-index: makes the error disappear, but I wouldn't say it solves the problem.
The grouped version indicates to me that the functions are sort of closely related, while the non-grouped indicates a more distant relationship.
In your example, without too much thinking, I would have them separate: one is a simple copy-constructor the other is (slightly) more interesting.
(I may be somewhat biased by usually documenting Python bindings for C++ :-))
Ah, I see. I suggest to add a note in the Python domain documentation
Agreed, I didn't even know no-index was allowed outside autofunction, it doesn't seem to be documented.
In your example, without too much thinking,
If you're willing to put in a bit more thinking, how do you think the constructors for my class here should be documented? Right now, I'm just using .. class with :no-index: inside the docstring for __init__, which feels rather hacky.
Oh, I don't know that. It means we can get docstrings via AST, great!
f-strings cannot be used as docstrings anyway
@eric-wieser, I'm not too familiar with the domain so it's tricky to judge, but to me it looks like 2 or possibly 3 different groups: default and copy constructor, and then the rest, or the rest partitioned in some way.
But it should be possible to change the hax classes to simply __init__ functions (with the same :no-index: annotation).
Having a better way to handle overloaded functions would be great. Currently trying to make something work.
.. class:: StrokeAttribute
Class to define a set of attributes associated with a :class:`StrokeVertex`.
The attribute set stores the color, alpha and thickness values for a Stroke
Vertex.
.. method:: __init__()
__init__(brother)
__init__(red, green, blue, alpha, thickness_right, thickness_left)
__init__(attribute1, attribute2, t)
__init__()
Default constructor.
__init__(brother)
Copy constructor.
__init__(red, green, blue, alpha, thickness_right, thickness_left)
Build a stroke vertex attribute from a set of parameters.
__init__(attribute1, attribute2, t)
Interpolation constructor. Build a StrokeAttribute from two
StrokeAttribute objects and an interpolation parameter.
:arg brother: A StrokeAttribute object to be used as a copy constructor.
:type brother: :class:`StrokeAttribute`
:arg red: Red component of a stroke color.
:type red: float
:arg green: Green component of a stroke color.
:type green: float
:arg blue: Blue component of a stroke color.
:type blue: float
:arg alpha: Alpha component of a stroke color.
:type alpha: float
:arg thickness_right: Stroke thickness on the right.
:type thickness_right: float
:arg thickness_left: Stroke thickness on the left.
:type thickness_left: float
:arg attribute1: The first StrokeAttribute object.
:type attribute1: :class:`StrokeAttribute`
:arg attribute2: The second StrokeAttribute object.
:type attribute2: :class:`StrokeAttribute`
:arg t: The interpolation parameter (0 <= t <= 1).
:type t: float
It would be nice if we could have a description for each overloaded function without duplicating text.
@eric-wieser , is it here?
https://pytorch.org/docs/stable/generated/torch.optim.Optimizer.step.html#torch.optim.Optimizer.step
@overload
def step(self, closure: None = ...) -> None:
...
@overload
def step(self, closure: Callable[[], float]) -> float:
...
def step(self, closure: Optional[Callable[[], float]] = None) -> Optional[float]:
r"""Performs a single optimization step (parameter update).
No, I don't think the original request works yet. https://github.com/sizmailov/pybind11-stubgen/issues/221
The last example posted has a single doc string per overload, instead of a unique doc string for each overload.
yes please