Skip to content

Commit

Permalink
Do not document members inherited from stdlib classes
Browse files Browse the repository at this point in the history
Closes #467
  • Loading branch information
AWhetter committed Jul 24, 2024
1 parent 2a90c6d commit 570a594
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 5 deletions.
14 changes: 14 additions & 0 deletions autoapi/_astroid_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -663,3 +663,17 @@ def get_class_docstring(node):
return base.doc_node.value

return doc


def is_abstract_class(node: astroid.ClassDef) -> bool:
metaclass = node.metaclass()
if metaclass and metaclass.name == "ABCMeta":
return True

if "abc.ABC" in node.basenames:
return True

if any(method.is_abstract(pass_is_abstract=False) for method in node.methods()):
return True

return False
20 changes: 15 additions & 5 deletions autoapi/_parser.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import collections
import itertools
import os
import sys

import astroid
import astroid.builder
Expand All @@ -9,6 +10,14 @@
from . import _astroid_utils


if sys.version_info < (3, 10): # PY310
from stdlib_list import in_stdlib
else:

def in_stdlib(module_name: str) -> bool:
return module_name in sys.stdlib_module_names


def _prepare_docstring(doc):
return "\n".join(sphinx.util.docstrings.prepare_docstring(doc))

Expand Down Expand Up @@ -135,12 +144,13 @@ def parse_classdef(self, node, data=None):
for base in itertools.chain(iter((node,)), node.ancestors()):
seen = set()
base_children = []
if base.qname() in (
"__builtins__.object",
"builtins.object",
"builtins.type",
):

# Don't document members inherited from standard library classes
# unless that class is abstract.
base_module = base.qname().split(".", 1)[0]
if in_stdlib(base_module) and not _astroid_utils.is_abstract_class(base):
continue

for child in base.get_children():
name = getattr(child, "name", None)
if isinstance(child, (astroid.Assign, astroid.AnnAssign)):
Expand Down
1 change: 1 addition & 0 deletions docs/changes/467.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Do not document members inherited from standard library classes.
2 changes: 2 additions & 0 deletions docs/reference/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Customisation Options
* ``members``: Display children of an object
* ``inherited-members``: Display children of an object
that have been inherited from a base class.
Members from standard library base classes are not included,
unless the base class is abstract.
* ``undoc-members``: Display objects that have no docstring
* ``private-members``: Display private objects (eg. ``_foo`` in Python)
* ``special-members``: Display special objects (eg. ``__foo__`` in Python)
Expand Down
1 change: 1 addition & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ install_requires =
Jinja2
PyYAML
sphinx>=6.1.0
stdlib_list;python_version<"3.10"

[options.extras_require]
docs =
Expand Down
16 changes: 16 additions & 0 deletions tests/python/py3example/example/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"""

import asyncio
import collections.abc
import typing
from typing import ClassVar, Dict, Iterable, Generic, List, TypeVar, Union, overload

Expand Down Expand Up @@ -169,3 +170,18 @@ async def async_function(wait: bool) -> int:


class SomeMetaclass(type): ...


class MyException(Exception):
pass


class My123(collections.abc.Sequence):
def __getitem__(self, i):
if i < len(self):
return i

raise IndexError(i)

def __len__(self):
return 3
8 changes: 8 additions & 0 deletions tests/python/test_pyintegration.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,14 @@ def test_integration(self, parse):
assert "Initialize self" not in example_file
assert "a new type" not in example_file

# Test that members are not inherited from standard library classes.
assert example_file.find(id="example.MyException")
assert not example_file.find(id="example.MyException.args")
# With the exception of abstract base classes.
assert example_file.find(id="example.My123")
assert example_file.find(id="example.My123.__contains__")
assert example_file.find(id="example.My123.index")

def test_annotations(self, parse):
example_file = parse("_build/html/autoapi/example/index.html")

Expand Down

0 comments on commit 570a594

Please sign in to comment.