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

feat: Option to generate headings (+ ToC entries) for items in summary tables (attributes, functions/methods, classes, modules) #133

Open
EvieePy opened this issue Feb 17, 2024 · 4 comments
Assignees
Labels
feature New feature or request

Comments

@EvieePy
Copy link

EvieePy commented Feb 17, 2024

Description of the bug

When using the Attributes section in a class docstring, E.g.

class Hello:
    """Hello World!
    
    Attributes
    ----------
    thing: int
        The thing for Hello.
    """

Also applies to Google style docstrings.

No ToC of those attributes are generated.
Properties (@property) in the class are properly added to the ToC.

This is also an issue on the insiders build where the use of summaries doesn't include these attributes in it's summary. And without the show_docstring_attributes: false option, the Attributes section is actually generated twice; One with all the properties already included in the ToC and another with all the attributes in the docstring (but they can't be referenced).

Adding doctstring below the attribute works, but this is not ideal, especially when dealing with large documentation or classes with a large amount of attributes or when any ordering of these attributes or logic is needed to be done in __init__.

Full traceback

No traceback.

Expected behavior

The Attributes section from the class docstring displays and add attributes to the toc appropriately and doesn't generate a secondary summary on insiders builds.

Environment information

  • System: Windows-11-10.0.22621-SP0
  • Python: cpython 3.12.0
  • Environment variables:
  • Installed packages:
    • mkdocs v1.5.3
    • mkdocstrings v0.24.0
    • mkdocstrings-python v1.8.0.1.6.1.dev4+g157224d
    • griffe v0.40.1.1.0.0
@pawamoy
Copy link
Member

pawamoy commented Feb 17, 2024

Hello, thanks for the report 🙂

No ToC of those attributes are generated.

The logic here is that docstring sections never generate entries in the Table of Contents, except for the Parameters section (recent feature), because it is special and there is no other way to create permalinks to parameters.

Contrary to parameters, attributes can be documented individually thanks to a docstring below their assignment. This lets users write a long documentation string for the attributes, more easily than in a docstring section item. Attributes sections, just like Functions, Methods, Classes and Modules sections, then act as manual summary tables. These tables can be generated automatically thanks to the auto-summary feature.

The recommended way to document code with mkdocstrings-python is therefore to document objects individually rather than in docstring sections, since these sections can be automatically generated. Some might consider it best-practice because the docstring lives right next to the attribute itself, and makes it easier to update it / remove it when the attribute changes.

If we were to make Attributes, Functions, Methods, Classes and Modules sections generate headings, and therefore ToC entries, this would clash with their "summary" behavior. To prevent that, it could be made configurable. I'm not strongly opposed to do that, but it needs careful design to make it interoperable with all the other existing options and ways to document objects. And since we already have a lot of rendering options, I'm not enthusiastic at the idea of adding more, which can greatly increase the number of rendering combinations that must be made interoperable!

About the use-case your describe: specific ordering is an interesting point 🤔 Aren't the existing ordering option working for you (members and members order)? Users tend to prefer maintaining source order, so maybe it makes sense to order attribute assignments in __init__ methods too?

Note that you can document an attribute without assigning:

def __init__(self) -> None:
    """Initialize the object."""
    self.a: int
    """Docs for `a`."""

    self.a = 0

Happy to hear your thoughts @EvieePy 🙂

@EvieePy
Copy link
Author

EvieePy commented Feb 17, 2024

Hi, thanks for the reply!

This is all valid, though a bit unexpected as having used sphinx for a very long time now I am used to the attributes sections being referenced and summarized. I guess a potential work around is to create a markdown link with a custom header point to the class itself, though this won't be ideal when dealing with properties.

Alternatively, we can use the docstrings under the attributes.

As for my point on ordering and logic in __init__, what I meant was, when ordering of attributes is somehow important E.g. (An attribute must be defined after something else or some other call, as an example), or simply when you are dealing with a large class, mixing these attributes might become quite hard to manage and read, especially when documenting attributes that explain something in depth.

Consider the following:

class Hello:
    """This is the Hello class!

    Attributes
    ----------
    world
        The world is a very big place to us, 
        but small in the eyes of the universe.
    
        When we say Hello to the world, 
        we are letting everyone know how 
        excited we are to be here!

        Sorry for the long boring text, 
        but this is a common use case for
        attributes. We might need more in depth
        explanations here to let the user know
        how the attribute affects the program in
        certain ways, or how it can be used and managed.
    
        We might even like to include additional information like version added, 
        changed, etc and it's default, etc etc etc...
    thing
        Some small documentation.
    """
    def __init__(self) -> None:
        self.thing: int = ...
        world = do_call()
        self.world: Earth = world
        self.etc = ...
       

class Bye:
    """This class shows the inverse scenario of Hello."""
    def __init__(self) -> None:
        self.thing: int = ...
        """Some small documentation."""
        world = do_call()
        self.world: Earth = world
        """
        The world is a very big place to us, 
        but small in the eyes of the universe.
    
        When we say Hello to the world, 
        we are letting everyone know how 
        excited we are to be here!

        Sorry for the long boring text, 
        but this is a common use case for
        attributes. We might need more in depth
        explanations here to let the user know
        how the attribute affects the program in
        certain ways, or how it can be used and managed.
    
        We might even like to include additional information like version added, 
        changed, etc and it's default, etc etc etc...
        """
        self.etc = ...

As you can see managing the logic within init now becomes harder because we have to read through documentation, which could be separated at the top on one known and predefined space.

Thanks again, and thanks for all the work put into this!

P.S I wrote this on my phone, sorry for any mistakes

@pawamoy
Copy link
Member

pawamoy commented Feb 18, 2024

Thanks for explaining your use-case.

I can see how this becomes a matter of preference: I prefer Bye rather than Hello. It reminds me of the PEP 727 discussion 😅

I myself never extensively used Sphinx, so I wasn't aware it worked that way. Is there a Sphinx example deployed somewhere, so I can see its output?

Anyway. I've thought about it and here's what I conclude: mkdocstrings is not an opinionated tool. It gives different ways of doing things to users. So I'll add a "headings" option for all "summary" sections (attributes, function/methods, classes, modules). I'll still recommend documenting each object individually in the docs though 🙂

@pawamoy pawamoy changed the title bug: Attributes included in class docstrings sections don't generate ToC and duplicate summaries(Insiders) feat: Option to generate headings (+ ToC entries) for items in summary tables (attributes, functions/methods, classes, modules) Feb 18, 2024
@pawamoy
Copy link
Member

pawamoy commented Feb 18, 2024

I'll open a new issue for a feature/fix allowing to de-duplicate summary tables when the auto-summary option is activated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants