diff --git a/CHANGES b/CHANGES index faaf4ad67..a2e93b298 100644 --- a/CHANGES +++ b/CHANGES @@ -20,6 +20,8 @@ Bugs fixed * #5421: autodoc emits deprecation warning for :confval:`autodoc_default_flags` * #5422: lambda object causes PicklingError on storing environment * #5417: Sphinx fails to build with syntax error in Python 2.7.5 +* #4911: add latexpdf to make.bat for non make-mode +* #5436: Autodoc does not work with enum subclasses with properties/methods * #5437: autodoc: crashed on modules importing eggs Testing @@ -37,6 +39,7 @@ Dependencies ``xelatex/lualatex``), instructs ``make latexpdf`` to use :program:`xindy` for general index. Make sure your LaTeX distribution includes it. (refs: #5134) +* LaTeX: ``latexmk`` is required for ``make latexpdf`` on Windows Incompatible changes -------------------- diff --git a/sphinx/ext/autodoc/importer.py b/sphinx/ext/autodoc/importer.py index 041589b58..a2280e82b 100644 --- a/sphinx/ext/autodoc/importer.py +++ b/sphinx/ext/autodoc/importer.py @@ -16,7 +16,7 @@ import warnings from collections import namedtuple from types import FunctionType, MethodType, ModuleType -from six import PY2 +from six import PY2, iteritems from sphinx.util import logging 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: 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 for name in dir(subject): try: diff --git a/sphinx/templates/quickstart/make.bat_t b/sphinx/templates/quickstart/make.bat_t index cd96c0736..c162da36d 100644 --- a/sphinx/templates/quickstart/make.bat_t +++ b/sphinx/templates/quickstart/make.bat_t @@ -31,6 +31,7 @@ if "%1" == "help" ( echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter + echo. latexpdf to make LaTeX files and run them through platex/dvipdfmx echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files diff --git a/tests/roots/test-ext-autodoc/target/__init__.py b/tests/roots/test-ext-autodoc/target/__init__.py index 201e84efd..9bb50bca9 100644 --- a/tests/roots/test-ext-autodoc/target/__init__.py +++ b/tests/roots/test-ext-autodoc/target/__init__.py @@ -223,19 +223,6 @@ class InstAttCls(object): """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): def __init__(self): """Create a new `CustomIter`.""" diff --git a/tests/roots/test-ext-autodoc/target/enum.py b/tests/roots/test-ext-autodoc/target/enum.py new file mode 100644 index 000000000..31e7c6ccd --- /dev/null +++ b/tests/roots/test-ext-autodoc/target/enum.py @@ -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 diff --git a/tests/test_autodoc.py b/tests/test_autodoc.py index e2dc37c56..554ad180f 100644 --- a/tests/test_autodoc.py +++ b/tests/test_autodoc.py @@ -829,7 +829,6 @@ def test_autodoc_ignore_module_all(app): '.. py:class:: CustomDataDescriptor2(doc)', '.. py:class:: CustomDataDescriptorMeta', '.. py:class:: CustomDict', - '.. py:class:: EnumCls', '.. py:class:: InstAttCls()', '.. py:class:: Outer', ' .. py:class:: Outer.Inner', @@ -1263,48 +1262,54 @@ def test_instance_attributes(app): def test_enum_class(app): options = {"members": None, "undoc-members": True} - actual = do_autodoc(app, 'class', 'target.EnumCls', options) + actual = do_autodoc(app, 'class', 'target.enum.EnumCls', options) assert list(actual) == [ '', '.. py:class:: EnumCls', - ' :module: target', + ' :module: target.enum', '', ' this is enum class', ' ', ' ', + ' .. py:method:: EnumCls.say_hello()', + ' :module: target.enum', + ' ', + ' a method says hello to you.', + ' ', + ' ', ' .. py:attribute:: EnumCls.val1', - ' :module: target', + ' :module: target.enum', ' :annotation: = 12', ' ', ' doc for val1', ' ', ' ', ' .. py:attribute:: EnumCls.val2', - ' :module: target', + ' :module: target.enum', ' :annotation: = 23', ' ', ' doc for val2', ' ', ' ', ' .. py:attribute:: EnumCls.val3', - ' :module: target', + ' :module: target.enum', ' :annotation: = 34', ' ', ' doc for val3', ' ', ' ', ' .. py:attribute:: EnumCls.val4', - ' :module: target', + ' :module: target.enum', ' :annotation: = 34', ' ' ] # 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) == [ '', '.. py:attribute:: EnumCls.val1', - ' :module: target', + ' :module: target.enum', ' :annotation: = 12', '', ' doc for val1', @@ -1473,7 +1478,7 @@ def test_merge_autodoc_default_flags2(app): @pytest.mark.sphinx('html', testroot='ext-autodoc') def test_autodoc_default_options(app): # 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.val4' not in actual actual = do_autodoc(app, 'class', 'target.CustomIter') @@ -1481,7 +1486,7 @@ def test_autodoc_default_options(app): # with :members: 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.val4' not in actual @@ -1490,7 +1495,7 @@ def test_autodoc_default_options(app): '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.val4' in actual @@ -1516,7 +1521,7 @@ def test_autodoc_default_options(app): '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.val4' not in actual app.config.autodoc_default_options = { @@ -1540,7 +1545,7 @@ def test_autodoc_default_options(app): def test_autodoc_default_options_with_values(app): # with :members: 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.val2' in actual assert ' .. py:attribute:: EnumCls.val3' not in actual @@ -1564,7 +1569,7 @@ def test_autodoc_default_options_with_values(app): 'members': None, '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.val2' in actual assert ' .. py:attribute:: EnumCls.val3' in actual