Former-commit-id:133dc97f67
[formerlya02aeb236c
] [formerly9f19e3f712
] [formerly06a8b51d6d
[formerly9f19e3f712
[formerly 64fa9254b946eae7e61bbc3f513b7c3696c4f54f]]] Former-commit-id:06a8b51d6d
Former-commit-id:377dcd10b9
[formerly3360eb6c5f
] Former-commit-id:8e80217e59
196 lines
6.8 KiB
Python
Executable file
196 lines
6.8 KiB
Python
Executable file
"""
|
|
========
|
|
numpydoc
|
|
========
|
|
|
|
Sphinx extension that handles docstrings in the Numpy standard format. [1]
|
|
|
|
It will:
|
|
|
|
- Convert Parameters etc. sections to field lists.
|
|
- Convert See Also section to a See also entry.
|
|
- Renumber references.
|
|
- Extract the signature from the docstring, if it can't be determined otherwise.
|
|
|
|
.. [1] http://projects.scipy.org/numpy/wiki/CodingStyleGuidelines#docstring-standard
|
|
|
|
"""
|
|
|
|
import os, re, pydoc
|
|
from docscrape_sphinx import get_doc_object, SphinxDocString
|
|
from sphinx.util.compat import Directive
|
|
import inspect
|
|
|
|
def mangle_docstrings(app, what, name, obj, options, lines,
|
|
reference_offset=[0]):
|
|
|
|
cfg = dict(use_plots=app.config.numpydoc_use_plots,
|
|
show_class_members=app.config.numpydoc_show_class_members)
|
|
|
|
if what == 'module':
|
|
# Strip top title
|
|
title_re = re.compile(ur'^\s*[#*=]{4,}\n[a-z0-9 -]+\n[#*=]{4,}\s*',
|
|
re.I|re.S)
|
|
lines[:] = title_re.sub(u'', u"\n".join(lines)).split(u"\n")
|
|
else:
|
|
doc = get_doc_object(obj, what, u"\n".join(lines), config=cfg)
|
|
lines[:] = unicode(doc).split(u"\n")
|
|
|
|
if app.config.numpydoc_edit_link and hasattr(obj, '__name__') and \
|
|
obj.__name__:
|
|
if hasattr(obj, '__module__'):
|
|
v = dict(full_name=u"%s.%s" % (obj.__module__, obj.__name__))
|
|
else:
|
|
v = dict(full_name=obj.__name__)
|
|
lines += [u'', u'.. htmlonly::', '']
|
|
lines += [u' %s' % x for x in
|
|
(app.config.numpydoc_edit_link % v).split("\n")]
|
|
|
|
# replace reference numbers so that there are no duplicates
|
|
references = []
|
|
for line in lines:
|
|
line = line.strip()
|
|
m = re.match(ur'^.. \[([a-z0-9_.-])\]', line, re.I)
|
|
if m:
|
|
references.append(m.group(1))
|
|
|
|
# start renaming from the longest string, to avoid overwriting parts
|
|
references.sort(key=lambda x: -len(x))
|
|
if references:
|
|
for i, line in enumerate(lines):
|
|
for r in references:
|
|
if re.match(ur'^\d+$', r):
|
|
new_r = u"R%d" % (reference_offset[0] + int(r))
|
|
else:
|
|
new_r = u"%s%d" % (r, reference_offset[0])
|
|
lines[i] = lines[i].replace(u'[%s]_' % r,
|
|
u'[%s]_' % new_r)
|
|
lines[i] = lines[i].replace(u'.. [%s]' % r,
|
|
u'.. [%s]' % new_r)
|
|
|
|
reference_offset[0] += len(references)
|
|
|
|
def mangle_signature(app, what, name, obj, options, sig, retann):
|
|
# Do not try to inspect classes that don't define `__init__`
|
|
if (inspect.isclass(obj) and
|
|
(not hasattr(obj, '__init__') or
|
|
'initializes x; see ' in pydoc.getdoc(obj.__init__))):
|
|
return '', ''
|
|
|
|
if not (callable(obj) or hasattr(obj, '__argspec_is_invalid_')): return
|
|
if not hasattr(obj, '__doc__'): return
|
|
|
|
doc = SphinxDocString(pydoc.getdoc(obj))
|
|
if doc['Signature']:
|
|
sig = re.sub(u"^[^(]*", u"", doc['Signature'])
|
|
return sig, u''
|
|
|
|
def initialize(app):
|
|
try:
|
|
app.connect('autodoc-process-signature', mangle_signature)
|
|
except:
|
|
monkeypatch_sphinx_ext_autodoc()
|
|
|
|
def setup(app, get_doc_object_=get_doc_object):
|
|
global get_doc_object
|
|
get_doc_object = get_doc_object_
|
|
|
|
app.connect('autodoc-process-docstring', mangle_docstrings)
|
|
app.connect('builder-inited', initialize)
|
|
app.add_config_value('numpydoc_edit_link', None, False)
|
|
app.add_config_value('numpydoc_use_plots', None, False)
|
|
app.add_config_value('numpydoc_show_class_members', True, True)
|
|
|
|
# Extra mangling directives
|
|
name_type = {
|
|
'cfunction': 'function',
|
|
'cmember': 'attribute',
|
|
'cmacro': 'function',
|
|
'ctype': 'class',
|
|
'cvar': 'object',
|
|
'class': 'class',
|
|
'function': 'function',
|
|
'attribute': 'attribute',
|
|
'method': 'function',
|
|
'staticmethod': 'function',
|
|
'classmethod': 'function',
|
|
}
|
|
|
|
for name, objtype in name_type.items():
|
|
app.add_directive('np-' + name, wrap_mangling_directive(name, objtype))
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Input-mangling directives
|
|
#------------------------------------------------------------------------------
|
|
from docutils.statemachine import ViewList
|
|
|
|
def get_directive(name):
|
|
from docutils.parsers.rst import directives
|
|
try:
|
|
return directives.directive(name, None, None)[0]
|
|
except AttributeError:
|
|
pass
|
|
try:
|
|
# docutils 0.4
|
|
return directives._directives[name]
|
|
except (AttributeError, KeyError):
|
|
raise RuntimeError("No directive named '%s' found" % name)
|
|
|
|
def wrap_mangling_directive(base_directive_name, objtype):
|
|
base_directive = get_directive(base_directive_name)
|
|
|
|
if inspect.isfunction(base_directive):
|
|
base_func = base_directive
|
|
class base_directive(Directive):
|
|
required_arguments = base_func.arguments[0]
|
|
optional_arguments = base_func.arguments[1]
|
|
final_argument_whitespace = base_func.arguments[2]
|
|
option_spec = base_func.options
|
|
has_content = base_func.content
|
|
def run(self):
|
|
return base_func(self.name, self.arguments, self.options,
|
|
self.content, self.lineno,
|
|
self.content_offset, self.block_text,
|
|
self.state, self.state_machine)
|
|
|
|
class directive(base_directive):
|
|
def run(self):
|
|
env = self.state.document.settings.env
|
|
|
|
name = None
|
|
if self.arguments:
|
|
m = re.match(r'^(.*\s+)?(.*?)(\(.*)?', self.arguments[0])
|
|
name = m.group(2).strip()
|
|
|
|
if not name:
|
|
name = self.arguments[0]
|
|
|
|
lines = list(self.content)
|
|
mangle_docstrings(env.app, objtype, name, None, None, lines)
|
|
self.content = ViewList(lines, self.content.parent)
|
|
|
|
return base_directive.run(self)
|
|
|
|
return directive
|
|
|
|
#------------------------------------------------------------------------------
|
|
# Monkeypatch sphinx.ext.autodoc to accept argspecless autodocs (Sphinx < 0.5)
|
|
#------------------------------------------------------------------------------
|
|
|
|
def monkeypatch_sphinx_ext_autodoc():
|
|
global _original_format_signature
|
|
import sphinx.ext.autodoc
|
|
|
|
if sphinx.ext.autodoc.format_signature is our_format_signature:
|
|
return
|
|
|
|
print "[numpydoc] Monkeypatching sphinx.ext.autodoc ..."
|
|
_original_format_signature = sphinx.ext.autodoc.format_signature
|
|
sphinx.ext.autodoc.format_signature = our_format_signature
|
|
|
|
def our_format_signature(what, obj):
|
|
r = mangle_signature(None, what, None, obj, None, None, None)
|
|
if r is not None:
|
|
return r[0]
|
|
else:
|
|
return _original_format_signature(what, obj)
|