From 676b91180285937e16ab31e91aa94039fad0f67a Mon Sep 17 00:00:00 2001 From: Pieter Holtzhausen Date: Fri, 15 Jul 2011 11:43:43 +0200 Subject: [PATCH] Update the numpy sphinx extensions from http://projects.scipy.org/numpy/browser/trunk/doc/sphinxext/ --- doc/ext/docscrape.py | 61 ++++++++-------- doc/ext/docscrape_sphinx.py | 25 ++++--- doc/ext/numpydoc.py | 141 ++++++++++++++---------------------- 3 files changed, 100 insertions(+), 127 deletions(-) diff --git a/doc/ext/docscrape.py b/doc/ext/docscrape.py index 0e073da9..ad5998cc 100644 --- a/doc/ext/docscrape.py +++ b/doc/ext/docscrape.py @@ -84,7 +84,7 @@ class Reader(object): class NumpyDocString(object): - def __init__(self,docstring): + def __init__(self, docstring, config={}): docstring = textwrap.dedent(docstring).split('\n') self._doc = Reader(docstring) @@ -183,7 +183,7 @@ class NumpyDocString(object): return params - + _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) def _parse_see_also(self, content): @@ -216,7 +216,7 @@ class NumpyDocString(object): current_func = None rest = [] - + for line in content: if not line.strip(): continue @@ -258,7 +258,7 @@ class NumpyDocString(object): if len(line) > 2: out[line[1]] = strip_each_in(line[2].split(',')) return out - + def _parse_summary(self): """Grab signature (if given) and summary""" if self._is_at_section(): @@ -275,7 +275,7 @@ class NumpyDocString(object): if not self._is_at_section(): self['Extended Summary'] = self._read_to_next_section() - + def _parse(self): self._doc.reset() self._parse_summary() @@ -408,22 +408,17 @@ def header(text, style='-'): class FunctionDoc(NumpyDocString): - def __init__(self, func, role='func', doc=None): + def __init__(self, func, role='func', doc=None, config={}): self._f = func self._role = role # e.g. "func" or "meth" - if doc is None: - doc = inspect.getdoc(func) or '' - try: - NumpyDocString.__init__(self, doc) - except ValueError, e: - print '*'*78 - print "ERROR: '%s' while parsing `%s`" % (e, self._f) - print '*'*78 - #print "Docstring follows:" - #print doclines - #print '='*78 - if not self['Signature']: + if doc is None: + if func is None: + raise ValueError("No function or docstring given") + doc = inspect.getdoc(func) or '' + NumpyDocString.__init__(self, doc) + + if not self['Signature'] and func is not None: func, func_name = self.get_func() try: # try to read signature @@ -442,7 +437,7 @@ class FunctionDoc(NumpyDocString): else: func = self._f return func, func_name - + def __str__(self): out = '' @@ -463,35 +458,41 @@ class FunctionDoc(NumpyDocString): class ClassDoc(NumpyDocString): - def __init__(self,cls,modulename='',func_doc=FunctionDoc,doc=None): - if not inspect.isclass(cls): - raise ValueError("Initialise using a class. Got %r" % cls) + def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc, + config={}): + if not inspect.isclass(cls) and cls is not None: + raise ValueError("Expected a class or None, but got %r" % cls) self._cls = cls if modulename and not modulename.endswith('.'): modulename += '.' self._mod = modulename - self._name = cls.__name__ - self._func_doc = func_doc if doc is None: + if cls is None: + raise ValueError("No class or documentation string given") doc = pydoc.getdoc(cls) NumpyDocString.__init__(self, doc) - if not self['Methods']: - self['Methods'] = [(name, '', '') for name in sorted(self.methods)] - - if not self['Attributes']: - self['Attributes'] = [(name, '', '') - for name in sorted(self.properties)] + if config.get('show_class_members', True): + if not self['Methods']: + self['Methods'] = [(name, '', '') + for name in sorted(self.methods)] + if not self['Attributes']: + self['Attributes'] = [(name, '', '') + for name in sorted(self.properties)] @property def methods(self): + if self._cls is None: + return [] return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and callable(func)] @property def properties(self): + if self._cls is None: + return [] return [name for name,func in inspect.getmembers(self._cls) if not name.startswith('_') and func is None] diff --git a/doc/ext/docscrape_sphinx.py b/doc/ext/docscrape_sphinx.py index 12907731..9f4350d4 100644 --- a/doc/ext/docscrape_sphinx.py +++ b/doc/ext/docscrape_sphinx.py @@ -3,7 +3,9 @@ import sphinx from docscrape import NumpyDocString, FunctionDoc, ClassDoc class SphinxDocString(NumpyDocString): - use_plots = False + def __init__(self, docstring, config={}): + self.use_plots = config.get('use_plots', False) + NumpyDocString.__init__(self, docstring, config=config) # string conversion routines def _str_header(self, name, symbol='`'): @@ -189,17 +191,21 @@ class SphinxDocString(NumpyDocString): return '\n'.join(out) class SphinxFunctionDoc(SphinxDocString, FunctionDoc): - pass + def __init__(self, obj, doc=None, config={}): + self.use_plots = config.get('use_plots', False) + FunctionDoc.__init__(self, obj, doc=doc, config=config) class SphinxClassDoc(SphinxDocString, ClassDoc): - pass + def __init__(self, obj, doc=None, func_doc=None, config={}): + self.use_plots = config.get('use_plots', False) + ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) class SphinxObjDoc(SphinxDocString): - def __init__(self, obj, doc): + def __init__(self, obj, doc=None, config={}): self._f = obj - SphinxDocString.__init__(self, doc) + SphinxDocString.__init__(self, doc, config=config) -def get_doc_object(obj, what=None, doc=None): +def get_doc_object(obj, what=None, doc=None, config={}): if what is None: if inspect.isclass(obj): what = 'class' @@ -210,10 +216,11 @@ def get_doc_object(obj, what=None, doc=None): else: what = 'object' if what == 'class': - return SphinxClassDoc(obj, '', func_doc=SphinxFunctionDoc, doc=doc) + return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, + config=config) elif what in ('function', 'method'): - return SphinxFunctionDoc(obj, '', doc=doc) + return SphinxFunctionDoc(obj, doc=doc, config=config) else: if doc is None: doc = pydoc.getdoc(obj) - return SphinxObjDoc(obj, doc) + return SphinxObjDoc(obj, doc, config=config) diff --git a/doc/ext/numpydoc.py b/doc/ext/numpydoc.py index 6667c429..aa390056 100644 --- a/doc/ext/numpydoc.py +++ b/doc/ext/numpydoc.py @@ -24,14 +24,16 @@ 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)) - doc.use_plots = app.config.numpydoc_use_plots + 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 \ @@ -71,7 +73,8 @@ def mangle_docstrings(app, what, name, obj, options, lines, 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 - 'initializes x; see ' in pydoc.getdoc(obj.__init__)): + (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 @@ -82,80 +85,63 @@ def mangle_signature(app, what, name, obj, options, sig, retann): 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, True) - app.add_config_value('numpydoc_use_plots', None, False) - # Extra mangling directives - name_type = { - 'cfunction': 'function', - 'cmember': 'attribute', - 'cmacro': 'function', - 'ctype': 'class', - 'cvar': 'object', - 'class': 'class', + 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 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', - 'attribute': 'attribute', + 'class': 'class', + 'exception': 'class', 'method': 'function', - 'staticmethod': 'function', 'classmethod': 'function', + 'staticmethod': 'function', + 'attribute': 'attribute', } - 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: - if "method" in name: - name = "automethod" - else: - name = "auto"+name - 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 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 @@ -176,24 +162,3 @@ def wrap_mangling_directive(base_directive_name, objtype): 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)