Skip to content

Docstring metadata ignored for attributesΒ #8180

@dfremont

Description

@dfremont

Describe the bug
Metadata in the docstrings (or doc-comments) of attributes is ignored; for example, :meta public: does not make an attribute whose name starts with an underscore public.

To Reproduce
Apply autodoc to a class such as the following:

class Foo:
    #: A class attribute whose name starts with an underscore.
    #:
    #: :meta public:
    _bar = 12

There will be no entry generated for _bar.

Expected behavior
The attribute _bar above should be listed in the generated documentation.

Your project
Here is a tiny project using the example above: example.zip

Environment info

  • OS: macOS 10.14.6
  • Python version: 3.8.0
  • Sphinx version: 3.3.0 (I tried my patch below on the 3.x branch)
  • Sphinx extensions: sphinx.ext.autodoc

Additional context
The cause of the bug is that autodoc.Documenter.filter_members does not properly look up the docstring/doc-comments for attributes when searching for metadata. The following patch seems to fix the problem (I haven't made a PR since I'm not at all sure that this is the right way to do it):

diff --git a/sphinx/ext/autodoc/__init__.py b/sphinx/ext/autodoc/__init__.py
index ed02c2c90..0d9dc5f5f 100644
--- a/sphinx/ext/autodoc/__init__.py
+++ b/sphinx/ext/autodoc/__init__.py
@@ -647,20 +647,24 @@ class Documenter:
             else:
                 isattr = False
 
-            doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings,
-                         self.parent, self.object_name)
-            if not isinstance(doc, str):
-                # Ignore non-string __doc__
-                doc = None
-
-            # if the member __doc__ is the same as self's __doc__, it's just
-            # inherited and therefore not the member's doc
-            cls = self.get_attr(member, '__class__', None)
-            if cls:
-                cls_doc = self.get_attr(cls, '__doc__', None)
-                if cls_doc == doc:
+            if (namespace, membername) in attr_docs:
+                doc = '\n'.join(attr_docs[(namespace, membername)])
+                has_doc = True
+            else:
+                doc = getdoc(member, self.get_attr, self.env.config.autodoc_inherit_docstrings,
+                             self.parent, self.object_name)
+                if not isinstance(doc, str):
+                    # Ignore non-string __doc__
                     doc = None
-            has_doc = bool(doc)
+
+                # if the member __doc__ is the same as self's __doc__, it's just
+                # inherited and therefore not the member's doc
+                cls = self.get_attr(member, '__class__', None)
+                if cls:
+                    cls_doc = self.get_attr(cls, '__doc__', None)
+                    if cls_doc == doc:
+                        doc = None
+                has_doc = bool(doc)
 
             metadata = extract_metadata(doc)
             if 'private' in metadata:

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions