sphinx
sphinx copied to clipboard
Docs from dataclass descriptor fields
Is your feature request related to a problem? Please describe.
If you define a dataclass descriptor field then it doesn't return self, so sphinx doesn't know to look for the descriptor's __doc__ attribute, which could be settable.
class Attribute:
def __init__(self, default, doc):
self.default = default
self.__doc_ = doc
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
if isinstance(instance, None):
return self.default
return getattr(instance, self.name)
def __set__(self, instance, value):
setattr(instance, self.name, value)
@dataclass
class Class:
attr = Attribute(1, doc="this is a docstring")
Describe the solution you'd like
I know that one can add a docstring after defining the attribute, but that's not always desired. It would be great if
sphinx, when looking at attributes on a class, also used vars to check if that attribute is actually a descriptor with a __doc__ attribute.
A hierarchy of docs preference will be required. I imagine this might be:
- Explicit docstring added to attribute
@dataclass
class Class:
attr = Attribute(1, doc="this is a docstring")
"""This overrides the doc argument"""
- docstring on descriptor
@dataclass
class Class:
attr = Attribute(1, doc="this is a docstring")
Describe alternatives you've considered
Developing a plugin to do this. However, this is a pretty common code pattern, e.g. doc in @property and dataclases are likewise property.
Related to data descriptors for dataclasses: #11588
Upon my return I can have a look at both of them at the same time (for dataclasses, that would help a lot).
I won't be able to do anything until mid October though so if anyone wants to take on the task, feel free to do it (I'll still be able to review).
I investigated a bit but I'm not really sure how to properly fix this issue. It's quite easy to make it recognize descriptors and then extract the __doc__ from it but it's actually really difficult to ensure that we are not using a "bad" docstring, e.g., one that is due to Python.
One thing I can do is specialize the descriptor detection for dataclasses but I'm not really happy with this approach. Instead, a more careful analysis should be done but I don't really have the time today. I tried to implement something but observed that I would likely touch too many parts of autodoc which I don't want to (for now).
So, sorry but this feature needs to wait (again) :(
I've found this function useful for resolving attributes on classes.
def all_cls_vars(obj: object | type, /) -> dict[str, Any]:
"""Return all variables in the whole class hierarchy."""
cls = obj if isinstance(obj, type) else obj.__class__
return functools.reduce(operator.__or__, map(vars, cls.mro()[::-1]))
Then
def is_descriptor(obj: Any) -> TypeGuard[SupportsGet]:
return hasattr(obj, "__get__")
is_descriptor(all_cls_vars(Class)["attribute"])