mkdocstrings / griffe

Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API.
https://mkdocstrings.github.io/griffe
ISC License
281 stars 40 forks source link

feature: A way to get docstrings, ... of InitVar parameters of a dataclass #286

Closed has2k1 closed 2 months ago

has2k1 commented 3 months ago

History

PR #252 removed InitVar parameters from the list of dataclass members (and attributes). This was correct.

New Problem

There is no way to get access to the docstrings of the InitVar parameters. Class parameters (dc.Parameter) do not have docstrings, only the core objects (dc.Object) do and now classes only keep track of those objects that are members (dc.Class.members).

from griffe.tests import temporary_visited_package

code = '''
from dataclasses import InitVar, dataclass

@dataclass
class ClassWithInitVar:
    """
    Class with an InitVar Parameter
    """

    a: InitVar[int] = 1
    "Parameter a"

    b: float = 2
    "Parameter b"

    def __post_init__(self, a: int): ...
'''

with temporary_visited_package("package", {"__init__.py": code}) as m:
    obj = m["ClassWithInitVar"]

print(obj.members) # does not include object a  [correct]
print(obj.all_members) # does not include object a [correct]
# print(obj.*) # Nothing includes object a [missing]

Brainstorming a solution

To be useful, the type of InitVar parameters should be derived from dc.Object. Then they have .docstring, .lines, .lineno, e.t.c.

But none of the current subclasses [Alias, Attribute, Class, Function, Module] is suitable.

Possible options are:

With this kind of solution, the new class category would have to be used for one of:

  1. Only dataclass parameters that are InitVar
  2. All dataclass parameters

Option 2. seems like the better choice, but some (most) dataclass parameters are also attributes and that would complicate the solution.

That leaves option 1.

Then where should these "InitVar" objects be stored?

Maybe have them back in dc.Class.members. This shouldn't be the problem if they are not of type dc.Attribute and therefore do not show up in dc.Class.attributes. This would effectively make dc.Class.members a lookup for all objects statically defined in the class namespace.

pawamoy commented 3 months ago

Hi @has2k1, thanks for the report :slightly_smiling_face:

I'd be more to open to a fundamental change that adds docstrings to parameters and returned/received/yielded values. This would play well with PEP 727 and our griffe-typingdoc extension supporting it, or with potential successors of this PEP.

Adding a new kind of objects would be a bad design choice IMO. This would open the door to many more different kinds of objects, complicating the API a lot. That's a no-go to me :blush:

has2k1 commented 3 months ago

I'd be more to open to a fundamental change that adds docstrings to parameters

I think for parameters it would not be a fundamental change. Ignoring PEP 727 (but knowing that it could bring proper runtime docstrings to all parameters), this could be as small as giving dc.Parameter a few more attributes. Then deal with PEP 727 later.