This commit is contained in:
Pieter Holtzhausen
2011-07-15 20:15:44 +02:00
parent aef8d50f5b
commit 676b911802
3 changed files with 100 additions and 127 deletions
+31 -30
View File
@@ -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<role>\w+):`(?P<name>[a-zA-Z0-9_.-]+)`|"
r" (?P<name2>[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]
+16 -9
View File
@@ -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)
+53 -88
View File
@@ -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)