Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

autodoc: Allow overloaded functions to have different docstrings #7787

Open
eric-wieser opened this issue Jun 4, 2020 · 12 comments
Open

autodoc: Allow overloaded functions to have different docstrings #7787

eric-wieser opened this issue Jun 4, 2020 · 12 comments
Labels
extensions:autodoc type:enhancement enhance or introduce a new feature

Comments

@eric-wieser
Copy link
Contributor

eric-wieser commented Jun 4, 2020

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
@eric-wieser eric-wieser added the type:enhancement enhance or introduce a new feature label Jun 4, 2020
@tk0miya
Copy link
Member

tk0miya commented Jun 4, 2020

It sounds good. But it is very difficult to support inheritance, f-string and other features. And I think this is not commonly used.

@tk0miya tk0miya added this to the some future version milestone Jun 4, 2020
@eric-wieser
Copy link
Contributor Author

eric-wieser commented Jun 4, 2020

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?

@jakobandersen
Copy link
Contributor

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 :-).

@eric-wieser
Copy link
Contributor Author

eric-wieser commented Jun 4, 2020

@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)

@jakobandersen
Copy link
Contributor

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++ :-))

@eric-wieser
Copy link
Contributor Author

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.

@tk0miya
Copy link
Member

tk0miya commented Jun 7, 2020

Oh, I don't know that. It means we can get docstrings via AST, great!

f-strings cannot be used as docstrings anyway

@jakobandersen
Copy link
Contributor

@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).

@Blendify
Copy link
Contributor

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.

@kuraga
Copy link

kuraga commented Mar 4, 2024

@eric-wieser , is it here?

https://pytorch.org/docs/stable/generated/torch.optim.Optimizer.step.html#torch.optim.Optimizer.step

image

@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).

@ax3l
Copy link

ax3l commented Apr 3, 2024

No, I don't think the original request works yet.
sizmailov/pybind11-stubgen#221

The last example posted has a single doc string per overload, instead of a unique doc string for each overload.

@devesnosy
Copy link

yes please

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extensions:autodoc type:enhancement enhance or introduce a new feature
Projects
None yet
Development

No branches or pull requests

7 participants