Skip to content

Commit e0ab897

Browse files
authored
Merge pull request #29 from Chilipp/autodocsummdirective
Add Autodocsummdirective
2 parents 0a1b651 + 7375fb6 commit e0ab897

15 files changed

+397
-32
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ python:
88
- "3.6"
99
env:
1010
- SPHINX_VERSION=""
11+
- SPHINX_VERSION=3.2.*
1112
- SPHINX_VERSION=3.1.*
1213
- SPHINX_VERSION=3.0.*
1314
- SPHINX_VERSION=2.4.*

autodocsumm/__init__.py

Lines changed: 117 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,24 @@
1-
"""Sphinx extension that defines a new automodule directive with autosummary
1+
"""Sphinx extension that defines new auto documenters with autosummary.
22
3-
The :class:`AutoSummDirective` defined in this extension module allows the
4-
same functionality as the automodule and autoclass directives of the
5-
:mod:`sphinx.ext.autodoc` module but with an additional `autosummary` option.
6-
This option puts a autosummary in the style of the
7-
:mod:`sphinx.ext.autosummary` module at the beginning of the class or module.
8-
The content of this autosummary is automatically determined by the results of
9-
the automodule (or autoclass) directive.
3+
The :class:`AutoSummModuleDocumenter` and :class:`AutoSummClassDocumenter`
4+
classes defined here enable an autosummary-style listing of the corresponding
5+
members.
106
117
This extension gives also the possibility to choose which data shall be shown
128
and to include the docstring of the ``'__call__'`` attribute.
139
"""
14-
import logging
10+
from itertools import chain
11+
12+
from sphinx.util import logging
1513
import re
1614
import six
15+
16+
from docutils import nodes
17+
1718
import sphinx
19+
20+
from sphinx.util.docutils import SphinxDirective
21+
1822
from sphinx.ext.autodoc import (
1923
ClassDocumenter, ModuleDocumenter, ALL, PycodeError,
2024
ModuleAnalyzer, bool_option, AttributeDocumenter, DataDocumenter, Options,
@@ -23,7 +27,10 @@
2327

2428
signature = Signature = None
2529

26-
from sphinx.ext.autodoc.directive import AUTODOC_DEFAULT_OPTIONS
30+
from sphinx.ext.autodoc.directive import (
31+
AutodocDirective, AUTODOC_DEFAULT_OPTIONS, process_documenter_options,
32+
DocumenterBridge
33+
)
2734

2835
from sphinx.ext.autodoc import get_documenters
2936

@@ -48,7 +55,7 @@
4855
if six.PY2:
4956
from itertools import imap as map
5057

51-
__version__ = '0.1.14'
58+
__version__ = '0.2.0'
5259

5360
__author__ = "Philipp S. Sommer"
5461

@@ -77,11 +84,16 @@ def process_signature(obj):
7784
return args
7885

7986

87+
def list_option(option):
88+
"""Transform a string to a list by splitting at ;;."""
89+
return [s.strip() for s in option.split(";;")]
90+
91+
8092
class AutosummaryDocumenter(object):
8193
"""Abstract class for for extending Documenter methods
8294
8395
This classed is used as a base class for Documenters in order to provide
84-
the necessary methods for the :class:`AutoSummDirective`."""
96+
the necessary methods for generating the autosummary."""
8597

8698
#: List of functions that may filter the members
8799
filter_funcs = []
@@ -108,15 +120,15 @@ def get_grouped_documenters(self, all_members=False):
108120
dictionary whose keys are determined by the :attr:`member_sections`
109121
dictionary and whose values are lists of tuples. Each tuple
110122
consists of a documenter and a boolean to identify whether a module
111-
check should be made describes an attribute or not. The dictionary
112-
can be used in the
113-
:meth:`AutoSummDirective.get_items_from_documenters` method
123+
check should be made describes an attribute or not.
114124
115125
Notes
116126
-----
117127
If a :class:`sphinx.ext.autodoc.Documenter.member_order` value is not
118128
in the :attr:`member_sections` dictionary, it will be put into an
119129
additional `Miscellaneous` section."""
130+
use_sections = self.options.autosummary_sections
131+
120132
self.parse_name()
121133
self.import_object()
122134
# If there is no real module defined, figure out which to use.
@@ -146,6 +158,13 @@ def get_grouped_documenters(self, all_members=False):
146158
if self.objpath:
147159
self.env.temp_data['autodoc:class'] = self.objpath[0]
148160

161+
if not self.options.autosummary_force_inline:
162+
docstring = self.get_doc()
163+
autodocsumm_directive = '.. auto%ssumm::' % self.objtype
164+
for s in chain.from_iterable(docstring):
165+
if autodocsumm_directive in s:
166+
return {}
167+
149168
# set the members from the autosummary member options
150169
options_save = {}
151170
for option in member_options.intersection(self.option_spec):
@@ -195,7 +214,8 @@ def get_grouped_documenters(self, all_members=False):
195214
'autodocsumm-grouper', self.objtype, e[0].object_name,
196215
e[0].object, section, self.object)
197216
section = user_section or section
198-
documenters.setdefault(section, []).append(e)
217+
if not use_sections or section in use_sections:
218+
documenters.setdefault(section, []).append(e)
199219
self.options.update(options_save)
200220
return documenters
201221

@@ -208,7 +228,8 @@ def add_autosummary(self):
208228
sourcename = self.get_sourcename()
209229

210230
for section, documenters in grouped_documenters.items():
211-
self.add_line('**%s:**' % section, sourcename)
231+
if not self.options.autosummary_no_titles:
232+
self.add_line('**%s:**' % section, sourcename)
212233

213234
self.add_line('', sourcename)
214235

@@ -223,12 +244,13 @@ def add_autosummary(self):
223244

224245

225246
class AutoSummModuleDocumenter(ModuleDocumenter, AutosummaryDocumenter):
226-
"""Module documentor suitable for the :class:`AutoSummDirective`
247+
"""Module documentor with autosummary tables of its members.
227248
228249
This class has the same functionality as the base
229250
:class:`sphinx.ext.autodoc.ModuleDocumenter` class but with an additional
230-
`autosummary` and the :meth:`get_grouped_documenters` method.
231-
It's priority is slightly higher than the one of the ModuleDocumenter."""
251+
`autosummary`.
252+
It's priority is slightly higher than the one of the ModuleDocumenter.
253+
"""
232254

233255
#: slightly higher priority than
234256
#: :class:`sphinx.ext.autodoc.ModuleDocumenter`
@@ -239,6 +261,9 @@ class AutoSummModuleDocumenter(ModuleDocumenter, AutosummaryDocumenter):
239261
option_spec = ModuleDocumenter.option_spec.copy()
240262
option_spec['autosummary'] = bool_option
241263
option_spec['autosummary-no-nesting'] = bool_option
264+
option_spec['autosummary-sections'] = list_option
265+
option_spec['autosummary-no-titles'] = bool_option
266+
option_spec['autosummary-force-inline'] = bool_option
242267

243268
#: Add options for members for the autosummary
244269
for _option in member_options.intersection(option_spec):
@@ -267,13 +292,14 @@ def add_content(self, *args, **kwargs):
267292

268293

269294
class AutoSummClassDocumenter(ClassDocumenter, AutosummaryDocumenter):
270-
"""Class documentor suitable for the :class:`AutoSummDirective`
295+
"""Class documentor with autosummary tables for its members.
271296
272297
This class has the same functionality as the base
273298
:class:`sphinx.ext.autodoc.ClassDocumenter` class but with an additional
274299
`autosummary` option to provide the ability to provide a summary of all
275-
methods and attributes at the beginning.
276-
It's priority is slightly higher than the one of the ClassDocumenter"""
300+
methods and attributes.
301+
It's priority is slightly higher than the one of the ClassDocumenter
302+
"""
277303

278304
#: slightly higher priority than
279305
#: :class:`sphinx.ext.autodoc.ClassDocumenter`
@@ -284,6 +310,9 @@ class AutoSummClassDocumenter(ClassDocumenter, AutosummaryDocumenter):
284310
option_spec = ClassDocumenter.option_spec.copy()
285311
option_spec['autosummary'] = bool_option
286312
option_spec['autosummary-no-nesting'] = bool_option
313+
option_spec['autosummary-sections'] = list_option
314+
option_spec['autosummary-no-titles'] = bool_option
315+
option_spec['autosummary-force-inline'] = bool_option
287316

288317
#: Add options for members for the autosummary
289318
for _option in member_options.intersection(option_spec):
@@ -453,10 +482,75 @@ def __init__(self, *args, **kwargs):
453482
self.options.annotation = ' '
454483

455484

485+
class AutoDocSummDirective(SphinxDirective):
486+
"""A directive to generate an autosummary.
487+
488+
Usage::
489+
490+
.. autoclasssum:: <Class>
491+
492+
.. automodsum:: <module>
493+
494+
The directive additionally supports all options of the ``autoclass`` or
495+
``automod`` directive respectively. Sections can be a list of section titles
496+
to be included. If ommitted, all sections are used.
497+
"""
498+
499+
has_content = False
500+
501+
option_spec = AutodocDirective.option_spec
502+
503+
required_arguments = 1
504+
optional_arguments = 0
505+
506+
def run(self):
507+
reporter = self.state.document.reporter
508+
509+
try:
510+
source, lineno = reporter.get_source_and_line(self.lineno)
511+
except AttributeError:
512+
source, lineno = (None, None)
513+
514+
# look up target Documenter
515+
objtype = self.name[4:-4] # strip prefix (auto-) and suffix (-summ).
516+
doccls = self.env.app.registry.documenters[objtype]
517+
518+
self.options['autosummary-force-inline'] = True
519+
self.options['autosummary'] = True
520+
if 'no-members' not in self.options:
521+
self.options['members'] = True
522+
523+
# process the options with the selected documenter's option_spec
524+
try:
525+
documenter_options = process_documenter_options(doccls, self.config,
526+
self.options)
527+
except (KeyError, ValueError, TypeError) as exc:
528+
# an option is either unknown or has a wrong type
529+
logger.error(
530+
f'An option to {self.name} is either unknown or has an invalid '
531+
f'value: {exc}',
532+
location=(self.env.docname, lineno))
533+
return []
534+
535+
# generate the output
536+
params = DocumenterBridge(self.env, reporter, documenter_options,
537+
lineno, self.state)
538+
documenter = doccls(params, self.arguments[0])
539+
documenter.add_autosummary()
540+
541+
node = nodes.paragraph()
542+
node.document = self.state.document
543+
self.state.nested_parse(params.result, 0, node)
544+
545+
return node.children
546+
547+
456548
def setup(app):
457549
"""setup function for using this module as a sphinx extension"""
458550
app.setup_extension('sphinx.ext.autosummary')
459551
app.setup_extension('sphinx.ext.autodoc')
552+
app.add_directive('autoclasssumm', AutoDocSummDirective)
553+
app.add_directive('automodulesumm', AutoDocSummDirective)
460554

461555
AUTODOC_DEFAULT_OPTIONS.extend(
462556
[option for option in AutoSummModuleDocumenter.option_spec

docs/conf_settings.rst

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,47 @@ table: these are
3838
- ``autosummary-imported-members``
3939
- ``autosummary-ignore-module-all``
4040
- ``autosummary-members``
41-
- ``autosummary-no-nesting``
4241

4342
They are essentially the same as the options for :mod:`~sphinx.ext.autodoc`
4443
(i.e. ``private-members`` or ``members``), but they only affect the
4544
autosummary table (see the example in :ref:`summary-table-example`).
4645

47-
The new additional flag ``autosummary-no-nesting`` only generates
48-
autosummary tables for a module, but not for members within. See
49-
:ref:`no-nesting-example`.
46+
``autosummary-no-nesting``
47+
The new additional flag ``autosummary-no-nesting`` only generates
48+
autosummary tables for a module, but not for members within. See
49+
example about :ref:`no-nesting-example`.
50+
``autosummary-sections``
51+
Select which sections to generate the autosummary for. Usage is like
52+
``:autosummary-sections: Methods ;; Attributes``. When omitted, all sections
53+
are generated. See the example about :ref:`select-sections-example`
54+
``autosummary-no-titles``
55+
Do not add section titles above each autosummary table
56+
``autosummary-force-inline``
57+
Force adding the autosummary, even it is already contained in the class
58+
or module docstring. See the example about :ref:`autosummary-position-example`
59+
60+
61+
.. _directives:
62+
63+
Directives
64+
----------
65+
66+
.. rst:directive:: autoclasssumm
67+
68+
This class generates the autosummary tables for the given class. You can
69+
use the same options as for the ``autoclass`` directive. You can select a
70+
specific section and omit the title via::
71+
72+
.. autoclasssumm:: MyClass
73+
:autosummary-sections: Methods
74+
:autosummary-no-titles:
75+
76+
By default, this directives also sets the `:members:` option unless you
77+
specify `:no-members`.
78+
79+
.. rst:directive:: automodulesumm
80+
81+
The same as the ``autoclasssumm`` directive, just for a module.
5082

5183

5284
.. _confvals:

docs/examples.rst

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,68 @@ which gives us
138138
:members:
139139
:autosummary:
140140
:autosummary-no-nesting:
141+
142+
143+
.. _select-sections-example:
144+
145+
Select the sections to document
146+
-------------------------------
147+
You can select, which sections to document. If you only want the *Methods*
148+
section of a class, you can specify::
149+
150+
.. autoclass:: dummy.MyClass
151+
:members:
152+
:autosummary:
153+
:autosummary-sections: Methods
154+
155+
Multiple sections might be separated by `;;`, e.g.
156+
``:autosummary-sections: Methods ;; Attributes``.
157+
158+
This also works for the ``autoclasssumm`` and ``automodulesumm`` directives,
159+
e.g.::
160+
161+
.. autoclasssumm:: dummy.SomeClass
162+
:autosummary-sections: Methods
163+
164+
.. autoclasssumm:: dummy.MyClass
165+
:autosummary-sections: Methods
166+
167+
168+
.. _autosummary-position-example:
169+
170+
Positioning of the autosummary table
171+
------------------------------------
172+
By default, the autosummary tables are put at the end of the docstring sections
173+
for classes and methods, i.e. something like::
174+
175+
class-name
176+
class-docstring
177+
autosummary-tables
178+
class-members
179+
180+
You can customize this positioning by calling the ``.. autoclasssumm::``
181+
directive inside the class docstring, e.g.
182+
183+
.. literalinclude:: inline_autoclasssumm.py
184+
185+
Documenting this, with ``.. autoclass:: MyClass`` creates
186+
187+
.. autoclass:: inline_autoclasssumm.MyClass
188+
:noindex:
189+
:members:
190+
191+
Note that this omits the `Attributes` section as we specified the
192+
``:autosummary-sections:`` options here. If you want to list this section
193+
anyway at the end of the docstring, you can use the ``autosummary-force-inline``
194+
option, e.g.::
195+
196+
.. autoclass:: inline_autoclasssumm.MyClass
197+
:members:
198+
:autosummary-force-inline:
199+
:autosummary-sections: Attributes
200+
201+
.. autoclass:: inline_autoclasssumm.MyClass
202+
:members:
203+
:noindex:
204+
:autosummary-force-inline:
205+
:autosummary-sections: Attributes

0 commit comments

Comments
 (0)