summaryrefslogtreecommitdiff
path: root/doc/sphinxext/numpydoc/numpydoc.py
diff options
context:
space:
mode:
authorPauli Virtanen <pav@iki.fi>2013-02-16 15:44:01 +0200
committerPauli Virtanen <pav@iki.fi>2013-02-16 17:28:28 +0200
commit7f2da39dea8f869ea4d5256786f55eacbd5722e6 (patch)
treeda7d400a2d0684135a272ef1cb41b50e174ffb67 /doc/sphinxext/numpydoc/numpydoc.py
parenta4cd4ffd52b4b60df4e8752ea202862e2c386589 (diff)
downloadnumpy-7f2da39dea8f869ea4d5256786f55eacbd5722e6.tar.gz
ENH: numpydoc: Python 2 & 3 in single codebase, restructure as a package
Diffstat (limited to 'doc/sphinxext/numpydoc/numpydoc.py')
-rw-r--r--doc/sphinxext/numpydoc/numpydoc.py176
1 files changed, 176 insertions, 0 deletions
diff --git a/doc/sphinxext/numpydoc/numpydoc.py b/doc/sphinxext/numpydoc/numpydoc.py
new file mode 100644
index 000000000..ec4884db7
--- /dev/null
+++ b/doc/sphinxext/numpydoc/numpydoc.py
@@ -0,0 +1,176 @@
+"""
+========
+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] https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt
+
+"""
+
+import sphinx
+
+if sphinx.__version__ < '1.0.1':
+ raise RuntimeError("Sphinx 1.0.1 or newer is required")
+
+import os, sys, 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(u'^\\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)
+ if sys.version_info[0] >= 3:
+ doc = str(doc)
+ else:
+ doc = str(doc).decode('utf-8')
+ lines[:] = 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::', u'']
+ 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(u'^.. \\[([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(u'^\\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 setup(app, get_doc_object_=get_doc_object):
+ if not hasattr(app, 'add_config_value'):
+ return # probably called by nose, better bail out
+
+ global get_doc_object
+ get_doc_object = get_doc_object_
+
+ app.connect('autodoc-process-docstring', mangle_docstrings)
+ app.connect('autodoc-process-signature', mangle_signature)
+ 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 domains
+ app.add_domain(NumpyPythonDomain)
+ app.add_domain(NumpyCDomain)
+
+#------------------------------------------------------------------------------
+# Docstring-mangling domains
+#------------------------------------------------------------------------------
+
+from docutils.statemachine import ViewList
+from sphinx.domains.c import CDomain
+from sphinx.domains.python import PythonDomain
+
+class ManglingDomainBase(object):
+ directive_mangling_map = {}
+
+ def __init__(self, *a, **kw):
+ super(ManglingDomainBase, self).__init__(*a, **kw)
+ self.wrap_mangling_directives()
+
+ def wrap_mangling_directives(self):
+ for name, objtype in list(self.directive_mangling_map.items()):
+ self.directives[name] = wrap_mangling_directive(
+ self.directives[name], objtype)
+
+class NumpyPythonDomain(ManglingDomainBase, PythonDomain):
+ name = 'np'
+ directive_mangling_map = {
+ 'function': 'function',
+ 'class': 'class',
+ 'exception': 'class',
+ 'method': 'function',
+ 'classmethod': 'function',
+ 'staticmethod': 'function',
+ 'attribute': 'attribute',
+ }
+
+class NumpyCDomain(ManglingDomainBase, CDomain):
+ name = 'np-c'
+ directive_mangling_map = {
+ 'function': 'function',
+ 'member': 'attribute',
+ 'macro': 'function',
+ 'type': 'class',
+ 'var': 'object',
+ }
+
+def wrap_mangling_directive(base_directive, objtype):
+ 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
+