Skip to content

Commit

Permalink
Fix issue with ABC-derived classes having their members ignored in Py…
Browse files Browse the repository at this point in the history
…thon 3

ABC-derived classes (i.e. those deriving from the `abc` and `collections.abc` modules) now include their members (as defined in `__dict__`) in generated `autosummary` RST. `__slots__` may still be used to override `__dict__`, but if an ABC-derived class has empty slots, its `__dict__` will be used instead.

This was only an issue in Python 3 when ``:inherited-members:`` was not in effect.

Fixes #52
  • Loading branch information
jairideout committed Nov 1, 2018
1 parent d46a0c1 commit 1f4d426
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 3 deletions.
2 changes: 1 addition & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Changes in sphinx-automodapi
0.9 (unreleased)
----------------

- No changes yet.
- Fix issue with ABC-derived classes (``abc`` and ``collections.abc`` modules) having their members ignored in Python 3. This was only an issue when ``:inherited-members:`` was not in effect. [#53]

0.8 (2018-10-18)
----------------
Expand Down
14 changes: 13 additions & 1 deletion sphinx_automodapi/automodsumm.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class members that are inherited from a base class. This value can be
.. _sphinx.ext.inheritance_diagram: http://sphinx-doc.org/latest/ext/inheritance.html
"""

import abc
import inspect
import os
import re
Expand Down Expand Up @@ -551,7 +552,18 @@ def get_members_class(obj, typ, include_public=[],
if include_base:
names = dir(obj)
else:
if hasattr(obj, '__slots__'):
# Classes deriving from an ABC using the `abc` module will
# have an empty `__slots__` attribute in Python 3, unless
# other slots were declared along the inheritance chain. If
# the ABC-derived class has empty slots, we'll use the
# class `__dict__` instead.
declares_slots = (
hasattr(obj, '__slots__') and
not (type(obj) is abc.ABCMeta and
len(obj.__slots__) == 0)
)

if declares_slots:
names = tuple(getattr(obj, '__slots__'))
else:
names = getattr(obj, '__dict__').keys()
Expand Down
3 changes: 3 additions & 0 deletions sphinx_automodapi/tests/cases/abstract_classes/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
This example is to make sure that classes derived from the `abc` module will
have their members listed when ``:inherited-members:`` is not in effect
(https://github.com/astropy/sphinx-automodapi/issues/52).
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.. automodapi:: sphinx_automodapi.tests.example_module.abstract_classes
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
SequenceSubclass
================

.. currentmodule:: sphinx_automodapi.tests.example_module.abstract_classes

.. autoclass:: SequenceSubclass
:show-inheritance:

.. rubric:: Attributes Summary

.. autosummary::

~SequenceSubclass.my_property

.. rubric:: Methods Summary

.. autosummary::

~SequenceSubclass.my_method

.. rubric:: Attributes Documentation

.. autoattribute:: my_property

.. rubric:: Methods Documentation

.. automethod:: my_method
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

sphinx_automodapi.tests.example_module.abstract_classes Module
--------------------------------------------------------------

.. automodule:: sphinx_automodapi.tests.example_module.abstract_classes

Classes
^^^^^^^

.. automodsumm:: sphinx_automodapi.tests.example_module.abstract_classes
:classes-only:
:toctree: api

Class Inheritance Diagram
^^^^^^^^^^^^^^^^^^^^^^^^^

.. automod-diagram:: sphinx_automodapi.tests.example_module.abstract_classes
:private-bases:
:parts: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.. currentmodule:: sphinx_automodapi.tests.example_module.abstract_classes

.. autosummary::
:toctree: api

SequenceSubclass
43 changes: 43 additions & 0 deletions sphinx_automodapi/tests/example_module/abstract_classes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
try:
# Python 3
from collections.abc import Sequence
except ImportError:
# Python 2 (this import also works in Python <= 3.7, but will be removed in
# Python 3.8)
from collections import Sequence

__all__ = ['SequenceSubclass']


class SequenceSubclass(Sequence):
"""
Inherits from an ABC.
"""

def __init__(self):
self._items = []

def __len__(self):
"""
Must be defined for the collections.abc.Sequence base class.
"""
return len(self._items)

def __getitem__(self, key):
"""
Must be defined for the collections.abc.Sequence base class.
"""
return self._items[key]

def my_method(self, parameter):
"""
An example method.
"""
pass

@property
def my_property(self):
"""
An example property.
"""
return 42
11 changes: 10 additions & 1 deletion sphinx_automodapi/tests/test_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,16 @@ def write_conf(filename, conf):
'suppress_warnings': ['app.add_directive', 'app.add_node'],
'intersphinx_mapping': intersphinx_mapping,
'nitpick_ignore': [('py:class', 'sphinx_automodapi.tests.example_module.classes.BaseSpam'),
('py:class', 'sphinx_automodapi.tests.example_module.other_classes.BaseFoo')]}
('py:class', 'sphinx_automodapi.tests.example_module.other_classes.BaseFoo'),
# See the following links for why these classes need to be ignored.
# This only seems to be necessary for Python 2.7.
#
# https://trac.sagemath.org/ticket/19211
# https://stackoverflow.com/q/11417221/3776794
('py:class', '_abcoll.Sequence'),
('py:class', '_abcoll.Iterable'),
('py:class', '_abcoll.Container'),
('py:class', '_abcoll.Sized')]}


def setup_function(func):
Expand Down

0 comments on commit 1f4d426

Please sign in to comment.