Merge pull request #5449 from tk0miya/5436_attributes_for_enum_subclasses

Fix #5436: Autodoc does not work with enum subclasses with properties/methods
This commit is contained in:
Takeshi KOMIYA 2018-09-18 17:42:45 +09:00 committed by GitHub
commit f79caff858
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 29 deletions

View File

@ -21,6 +21,7 @@ Bugs fixed
* #5422: lambda object causes PicklingError on storing environment * #5422: lambda object causes PicklingError on storing environment
* #5417: Sphinx fails to build with syntax error in Python 2.7.5 * #5417: Sphinx fails to build with syntax error in Python 2.7.5
* #4911: add latexpdf to make.bat for non make-mode * #4911: add latexpdf to make.bat for non make-mode
* #5436: Autodoc does not work with enum subclasses with properties/methods
Testing Testing
-------- --------

View File

@ -16,7 +16,7 @@ import warnings
from collections import namedtuple from collections import namedtuple
from types import FunctionType, MethodType, ModuleType from types import FunctionType, MethodType, ModuleType
from six import PY2 from six import PY2, iteritems
from sphinx.util import logging from sphinx.util import logging
from sphinx.util.inspect import isenumclass, safe_getattr from sphinx.util.inspect import isenumclass, safe_getattr
@ -248,6 +248,11 @@ def get_object_members(subject, objpath, attrgetter, analyzer=None):
if name not in members: if name not in members:
members[name] = Attribute(name, True, value) members[name] = Attribute(name, True, value)
superclass = subject.__mro__[1]
for name, value in iteritems(obj_dict):
if name not in superclass.__dict__:
members[name] = Attribute(name, True, value)
# other members # other members
for name in dir(subject): for name in dir(subject):
try: try:

View File

@ -223,19 +223,6 @@ class InstAttCls(object):
"""Docstring for instance attribute InstAttCls.ia2.""" """Docstring for instance attribute InstAttCls.ia2."""
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""
val4 = 34
class CustomIter(object): class CustomIter(object):
def __init__(self): def __init__(self):
"""Create a new `CustomIter`.""" """Create a new `CustomIter`."""

View File

@ -0,0 +1,19 @@
from __future__ import absolute_import
import enum
class EnumCls(enum.Enum):
"""
this is enum class
"""
#: doc for val1
val1 = 12
val2 = 23 #: doc for val2
val3 = 34
"""doc for val3"""
val4 = 34
def say_hello(self):
"""a method says hello to you."""
pass

View File

@ -829,7 +829,6 @@ def test_autodoc_ignore_module_all(app):
'.. py:class:: CustomDataDescriptor2(doc)', '.. py:class:: CustomDataDescriptor2(doc)',
'.. py:class:: CustomDataDescriptorMeta', '.. py:class:: CustomDataDescriptorMeta',
'.. py:class:: CustomDict', '.. py:class:: CustomDict',
'.. py:class:: EnumCls',
'.. py:class:: InstAttCls()', '.. py:class:: InstAttCls()',
'.. py:class:: Outer', '.. py:class:: Outer',
' .. py:class:: Outer.Inner', ' .. py:class:: Outer.Inner',
@ -1263,48 +1262,54 @@ def test_instance_attributes(app):
def test_enum_class(app): def test_enum_class(app):
options = {"members": None, options = {"members": None,
"undoc-members": True} "undoc-members": True}
actual = do_autodoc(app, 'class', 'target.EnumCls', options) actual = do_autodoc(app, 'class', 'target.enum.EnumCls', options)
assert list(actual) == [ assert list(actual) == [
'', '',
'.. py:class:: EnumCls', '.. py:class:: EnumCls',
' :module: target', ' :module: target.enum',
'', '',
' this is enum class', ' this is enum class',
' ', ' ',
' ', ' ',
' .. py:method:: EnumCls.say_hello()',
' :module: target.enum',
' ',
' a method says hello to you.',
' ',
' ',
' .. py:attribute:: EnumCls.val1', ' .. py:attribute:: EnumCls.val1',
' :module: target', ' :module: target.enum',
' :annotation: = 12', ' :annotation: = 12',
' ', ' ',
' doc for val1', ' doc for val1',
' ', ' ',
' ', ' ',
' .. py:attribute:: EnumCls.val2', ' .. py:attribute:: EnumCls.val2',
' :module: target', ' :module: target.enum',
' :annotation: = 23', ' :annotation: = 23',
' ', ' ',
' doc for val2', ' doc for val2',
' ', ' ',
' ', ' ',
' .. py:attribute:: EnumCls.val3', ' .. py:attribute:: EnumCls.val3',
' :module: target', ' :module: target.enum',
' :annotation: = 34', ' :annotation: = 34',
' ', ' ',
' doc for val3', ' doc for val3',
' ', ' ',
' ', ' ',
' .. py:attribute:: EnumCls.val4', ' .. py:attribute:: EnumCls.val4',
' :module: target', ' :module: target.enum',
' :annotation: = 34', ' :annotation: = 34',
' ' ' '
] ]
# checks for an attribute of EnumClass # checks for an attribute of EnumClass
actual = do_autodoc(app, 'attribute', 'target.EnumCls.val1') actual = do_autodoc(app, 'attribute', 'target.enum.EnumCls.val1')
assert list(actual) == [ assert list(actual) == [
'', '',
'.. py:attribute:: EnumCls.val1', '.. py:attribute:: EnumCls.val1',
' :module: target', ' :module: target.enum',
' :annotation: = 12', ' :annotation: = 12',
'', '',
' doc for val1', ' doc for val1',
@ -1473,7 +1478,7 @@ def test_merge_autodoc_default_flags2(app):
@pytest.mark.sphinx('html', testroot='ext-autodoc') @pytest.mark.sphinx('html', testroot='ext-autodoc')
def test_autodoc_default_options(app): def test_autodoc_default_options(app):
# no settings # no settings
actual = do_autodoc(app, 'class', 'target.EnumCls') actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' not in actual assert ' .. py:attribute:: EnumCls.val1' not in actual
assert ' .. py:attribute:: EnumCls.val4' not in actual assert ' .. py:attribute:: EnumCls.val4' not in actual
actual = do_autodoc(app, 'class', 'target.CustomIter') actual = do_autodoc(app, 'class', 'target.CustomIter')
@ -1481,7 +1486,7 @@ def test_autodoc_default_options(app):
# with :members: # with :members:
app.config.autodoc_default_options = {'members': None} app.config.autodoc_default_options = {'members': None}
actual = do_autodoc(app, 'class', 'target.EnumCls') actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val4' not in actual assert ' .. py:attribute:: EnumCls.val4' not in actual
@ -1490,7 +1495,7 @@ def test_autodoc_default_options(app):
'members': None, 'members': None,
'undoc-members': None, 'undoc-members': None,
} }
actual = do_autodoc(app, 'class', 'target.EnumCls') actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val4' in actual assert ' .. py:attribute:: EnumCls.val4' in actual
@ -1516,7 +1521,7 @@ def test_autodoc_default_options(app):
'members': None, 'members': None,
'exclude-members': None, 'exclude-members': None,
} }
actual = do_autodoc(app, 'class', 'target.EnumCls') actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val4' not in actual assert ' .. py:attribute:: EnumCls.val4' not in actual
app.config.autodoc_default_options = { app.config.autodoc_default_options = {
@ -1540,7 +1545,7 @@ def test_autodoc_default_options(app):
def test_autodoc_default_options_with_values(app): def test_autodoc_default_options_with_values(app):
# with :members: # with :members:
app.config.autodoc_default_options = {'members': 'val1,val2'} app.config.autodoc_default_options = {'members': 'val1,val2'}
actual = do_autodoc(app, 'class', 'target.EnumCls') actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' in actual assert ' .. py:attribute:: EnumCls.val1' in actual
assert ' .. py:attribute:: EnumCls.val2' in actual assert ' .. py:attribute:: EnumCls.val2' in actual
assert ' .. py:attribute:: EnumCls.val3' not in actual assert ' .. py:attribute:: EnumCls.val3' not in actual
@ -1564,7 +1569,7 @@ def test_autodoc_default_options_with_values(app):
'members': None, 'members': None,
'exclude-members': 'val1' 'exclude-members': 'val1'
} }
actual = do_autodoc(app, 'class', 'target.EnumCls') actual = do_autodoc(app, 'class', 'target.enum.EnumCls')
assert ' .. py:attribute:: EnumCls.val1' not in actual assert ' .. py:attribute:: EnumCls.val1' not in actual
assert ' .. py:attribute:: EnumCls.val2' in actual assert ' .. py:attribute:: EnumCls.val2' in actual
assert ' .. py:attribute:: EnumCls.val3' in actual assert ' .. py:attribute:: EnumCls.val3' in actual