mirror of
https://github.com/sphinx-doc/sphinx.git
synced 2025-02-25 18:55:22 -06:00
Add general docstring processing support with a new event in autodoc.
This commit is contained in:
parent
abddd96093
commit
c1bedfc105
4
CHANGES
4
CHANGES
@ -68,6 +68,10 @@ New features added
|
||||
|
||||
* Extensions:
|
||||
|
||||
- The autodoc extension now offers a much more flexible way to
|
||||
manipulate docstrings before including them into the output, via
|
||||
the new `autodoc-process-docstring` event.
|
||||
|
||||
- The `autodoc` extension accepts signatures for functions, methods
|
||||
and classes now that override the signature got via introspection
|
||||
from Python code.
|
||||
|
@ -131,8 +131,6 @@ latex_logo = '_static/sphinx.png'
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
automodule_skip_lines = 4
|
||||
|
||||
|
||||
# Extension interface
|
||||
# -------------------
|
||||
@ -180,6 +178,8 @@ def parse_event(env, sig, signode):
|
||||
|
||||
|
||||
def setup(app):
|
||||
from sphinx.ext.autodoc import cut_lines
|
||||
app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
|
||||
app.add_description_unit('directive', 'dir', 'pair: %s; directive', parse_directive)
|
||||
app.add_description_unit('role', 'role', 'pair: %s; role', parse_role)
|
||||
app.add_description_unit('confval', 'confval', 'pair: %s; configuration value')
|
||||
|
@ -162,24 +162,24 @@ package.
|
||||
Sphinx core events
|
||||
------------------
|
||||
|
||||
These events are known to the core. The arguments showed are given to the
|
||||
These events are known to the core. The arguments shown are given to the
|
||||
registered event handlers.
|
||||
|
||||
.. event:: builder-inited ()
|
||||
.. event:: builder-inited (app)
|
||||
|
||||
Emitted the builder object has been created.
|
||||
|
||||
.. event:: doctree-read (doctree)
|
||||
.. event:: doctree-read (app, doctree)
|
||||
|
||||
Emitted when a doctree has been parsed and read by the environment, and is
|
||||
about to be pickled.
|
||||
|
||||
.. event:: doctree-resolved (doctree, docname)
|
||||
.. event:: doctree-resolved (app, doctree, docname)
|
||||
|
||||
Emitted when a doctree has been "resolved" by the environment, that is, all
|
||||
references and TOCs have been inserted.
|
||||
|
||||
.. event:: page-context (pagename, templatename, context, doctree)
|
||||
.. event:: page-context (app, pagename, templatename, context, doctree)
|
||||
|
||||
Emitted when the HTML builder has created a context dictionary to render a
|
||||
template with -- this can be used to add custom elements to the context.
|
||||
|
@ -148,6 +148,10 @@ There are also new config values that you can set:
|
||||
fields with version control tags, that you don't want to put in the generated
|
||||
documentation.
|
||||
|
||||
.. deprecated:: 0.4
|
||||
Use the more versatile docstring processing provided by
|
||||
:event:`autodoc-process-docstring`.
|
||||
|
||||
.. confval:: autoclass_content
|
||||
|
||||
This value selects what content will be inserted into the main body of an
|
||||
@ -164,3 +168,36 @@ There are also new config values that you can set:
|
||||
Only the ``__init__`` method's docstring is inserted.
|
||||
|
||||
.. versionadded:: 0.3
|
||||
|
||||
|
||||
Docstring preprocessing
|
||||
-----------------------
|
||||
|
||||
.. versionadded:: 0.4
|
||||
|
||||
autodoc provides the following additional event:
|
||||
|
||||
.. event:: autodoc-process-docstring (app, what, name, obj, options, lines)
|
||||
|
||||
Emitted when autodoc has read and processed a docstring. *lines* is a list
|
||||
of strings -- the lines of the processed docstring -- that the event handler
|
||||
can modify **in place** to change what Sphinx puts into the output.
|
||||
|
||||
:param app: the Sphinx application object
|
||||
:param what: the type of the object which the docstring belongs to (one of
|
||||
``"module"``, ``"class"``, ``"exception"``, ``"function"``, ``"method"``,
|
||||
``"attribute"``)
|
||||
:param name: the fully qualified name of the object
|
||||
:param obj: the object itself
|
||||
:param options: the options given to the directive: an object with attributes
|
||||
``inherited_members``, ``undoc_members``, ``show_inheritance`` and
|
||||
``noindex`` that are true if the flag option of same name was given to the
|
||||
auto directive
|
||||
:param lines: the lines of the docstring, see above
|
||||
|
||||
|
||||
The :mod:`sphinx.ext.autodoc` module provides factory functions for commonly
|
||||
needed docstring processing:
|
||||
|
||||
.. autofunction:: cut_lines
|
||||
.. autofunction:: between
|
||||
|
@ -209,6 +209,9 @@ class BuildEnvironment:
|
||||
self.srcdir = srcdir
|
||||
self.config = config
|
||||
|
||||
# the application object; only set while update() runs
|
||||
self.app = None
|
||||
|
||||
# the docutils settings for building
|
||||
self.settings = default_settings.copy()
|
||||
self.settings['env'] = self
|
||||
@ -420,6 +423,7 @@ class BuildEnvironment:
|
||||
yield msg
|
||||
|
||||
self.config = config
|
||||
self.app = app
|
||||
|
||||
# clear all files no longer present
|
||||
for docname in removed:
|
||||
@ -434,6 +438,8 @@ class BuildEnvironment:
|
||||
self.warn(None, 'master file %s not found' %
|
||||
self.doc2path(config.master_doc))
|
||||
|
||||
self.app = None
|
||||
|
||||
# remove all non-existing images from inventory
|
||||
for imgsrc in self.images.keys():
|
||||
if not os.access(path.join(self.srcdir, imgsrc), os.R_OK):
|
||||
|
@ -78,6 +78,51 @@ class AutodocReporter(object):
|
||||
return self.system_message(4, *args, **kwargs)
|
||||
|
||||
|
||||
# Some useful event listener factories for autodoc-process-docstring.
|
||||
|
||||
def cut_lines(pre, post=0, what=None):
|
||||
"""
|
||||
Return a listener that removes the first *pre* and last *post*
|
||||
lines of every docstring. If *what* is a sequence of strings,
|
||||
only docstrings of a type in *what* will be processed.
|
||||
|
||||
Use like this (e.g. in the ``setup()`` function of :file:`conf.py`)::
|
||||
|
||||
from sphinx.ext.autodoc import cut_lines
|
||||
app.connect('autodoc-process-docstring', cut_lines(4, what=['module']))
|
||||
|
||||
This can (and should) be used in place of :confval:`automodule_skip_lines`.
|
||||
"""
|
||||
def process(app, what_, name, obj, options, lines):
|
||||
if what and what_ not in what:
|
||||
return
|
||||
del lines[:pre]
|
||||
if post:
|
||||
del lines[-post:]
|
||||
return process
|
||||
|
||||
def between(marker, what=None):
|
||||
"""
|
||||
Return a listener that only keeps lines between the first two lines that
|
||||
match the *marker* regular expression. If *what* is a sequence of strings,
|
||||
only docstrings of a type in *what* will be processed.
|
||||
"""
|
||||
marker_re = re.compile(marker)
|
||||
def process(app, what_, name, obj, options, lines):
|
||||
if what and what_ not in what:
|
||||
return
|
||||
seen = 0
|
||||
for i, line in enumerate(lines[:]):
|
||||
if marker_re.match(line):
|
||||
if not seen:
|
||||
del lines[:i+1]
|
||||
seen = i+1
|
||||
else:
|
||||
del lines[i-seen:]
|
||||
break
|
||||
return process
|
||||
|
||||
|
||||
def isdescriptor(x):
|
||||
"""Check if the object is some kind of descriptor."""
|
||||
for item in '__get__', '__set__', '__delete__':
|
||||
@ -127,7 +172,7 @@ def get_module_charset(module):
|
||||
return charset
|
||||
|
||||
|
||||
def get_doc(what, obj, env):
|
||||
def get_doc(what, name, obj, options, env):
|
||||
"""Format and yield lines of the docstring(s) for the object."""
|
||||
docstrings = []
|
||||
if getattr(obj, '__doc__', None):
|
||||
@ -168,7 +213,12 @@ def get_doc(what, obj, env):
|
||||
except UnicodeError:
|
||||
# last resort -- can't fail
|
||||
docstring = docstring.decode('latin1')
|
||||
for line in prepare_docstring(docstring):
|
||||
docstringlines = prepare_docstring(docstring)
|
||||
if env.app:
|
||||
# let extensions preprocess docstrings
|
||||
env.app.emit('autodoc-process-docstring',
|
||||
what, name, obj, options, docstringlines)
|
||||
for line in docstringlines:
|
||||
yield line
|
||||
|
||||
|
||||
@ -336,7 +386,7 @@ def generate_rst(what, name, members, options, add_content, document, lineno,
|
||||
sourcename = 'docstring of %s' % fullname
|
||||
|
||||
# add content from docstrings
|
||||
for i, line in enumerate(get_doc(what, todoc, env)):
|
||||
for i, line in enumerate(get_doc(what, fullname, todoc, options, env)):
|
||||
result.append(indent + line, sourcename, i)
|
||||
|
||||
# add source content, if present
|
||||
@ -364,7 +414,7 @@ def generate_rst(what, name, members, options, add_content, document, lineno,
|
||||
members_check_module = True
|
||||
all_members = inspect.getmembers(todoc)
|
||||
else:
|
||||
if options.inherited:
|
||||
if options.inherited_members:
|
||||
# getmembers() uses dir() which pulls in members from all base classes
|
||||
all_members = inspect.getmembers(todoc)
|
||||
else:
|
||||
@ -378,7 +428,7 @@ def generate_rst(what, name, members, options, add_content, document, lineno,
|
||||
continue
|
||||
# ignore undocumented members if :undoc-members: is not given
|
||||
doc = getattr(member, '__doc__', None)
|
||||
if not options.undoc and not doc:
|
||||
if not options.undoc_members and not doc:
|
||||
continue
|
||||
if what == 'module':
|
||||
if isinstance(member, types.FunctionType):
|
||||
@ -420,11 +470,11 @@ def _auto_directive(dirname, arguments, options, content, lineno,
|
||||
name = arguments[0]
|
||||
genopt = Options()
|
||||
members = options.get('members', [])
|
||||
genopt.inherited = 'inherited-members' in options
|
||||
if genopt.inherited and not members:
|
||||
genopt.inherited_members = 'inherited-members' in options
|
||||
if genopt.inherited_members and not members:
|
||||
# :inherited-members: implies :members:
|
||||
members = ['__all__']
|
||||
genopt.undoc = 'undoc-members' in options
|
||||
genopt.undoc_members = 'undoc-members' in options
|
||||
genopt.show_inheritance = 'show-inheritance' in options
|
||||
genopt.noindex = 'noindex' in options
|
||||
|
||||
@ -465,16 +515,16 @@ def auto_directive_withmembers(*args, **kwds):
|
||||
return _auto_directive(*args, **kwds)
|
||||
|
||||
|
||||
def members_directive(arg):
|
||||
def members_option(arg):
|
||||
if arg is None:
|
||||
return ['__all__']
|
||||
return [x.strip() for x in arg.split(',')]
|
||||
|
||||
|
||||
def setup(app):
|
||||
mod_options = {'members': members_directive, 'undoc-members': directives.flag,
|
||||
mod_options = {'members': members_option, 'undoc-members': directives.flag,
|
||||
'noindex': directives.flag}
|
||||
cls_options = {'members': members_directive, 'undoc-members': directives.flag,
|
||||
cls_options = {'members': members_option, 'undoc-members': directives.flag,
|
||||
'noindex': directives.flag, 'inherited-members': directives.flag,
|
||||
'show-inheritance': directives.flag}
|
||||
app.add_directive('automodule', auto_directive_withmembers,
|
||||
@ -489,5 +539,7 @@ def setup(app):
|
||||
noindex=directives.flag)
|
||||
app.add_directive('autoattribute', auto_directive, 1, (1, 0, 1),
|
||||
noindex=directives.flag)
|
||||
# deprecated: remove in some future version.
|
||||
app.add_config_value('automodule_skip_lines', 0, True)
|
||||
app.add_config_value('autoclass_content', 'class', True)
|
||||
app.add_event('autodoc-process-docstring')
|
||||
|
@ -239,4 +239,3 @@ def setup(app):
|
||||
app.add_config_value('coverage_c_path', [], False)
|
||||
app.add_config_value('coverage_c_regexes', {}, False)
|
||||
app.add_config_value('coverage_ignore_c_items', {}, False)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user