''' sphinx_cython.py This module monkeypatches sphinx autodoc to support Cython generated function signatures in the first line of the docstring of functions implemented as C extensions. Copyright (C) Nikolaus Rath This file is part of LLFUSE (http://python-llfuse.googlecode.com). LLFUSE can be distributed under the terms of the GNU LGPL. It has been slightly modified by MinRK. ''' import sphinx.ext.autodoc as SphinxAutodoc from sphinx.util.docstrings import prepare_docstring import inspect import re from sphinx.util import force_decode TYPE_RE = re.compile(r'(?:int|char)(?:\s+\*?\s*|\s*\*?\s+)([a-zA-Z_].*)') ClassDocumenter = SphinxAutodoc.ClassDocumenter MethodDocumenter = SphinxAutodoc.MethodDocumenter FunctionDocumenter = SphinxAutodoc.FunctionDocumenter class MyDocumenter(SphinxAutodoc.Documenter): ''' Overwrites `get_doc()` to remove function and method signatures and `format_args` to parse and give precedence to function signatures in the first line of the docstring. ''' def get_doc(self, encoding=None): docstr = self.get_attr(self.object, '__doc__', None) if docstr: docstr = force_decode(docstr, encoding) myname = self.fullname[len(self.modname)+1:] if myname.endswith('()'): myname = myname[:-2] if (docstr and (myname + '(') in docstr and '\n' in docstr and docstr[docstr.index('\n')-1] == ')'): docstr = docstr[docstr.index('\n')+1:] if docstr: # make sure we have Unicode docstrings, then sanitize and split # into lines return [prepare_docstring(force_decode(docstr, encoding))] return [] def format_args(self): myname = self.fullname[len(self.modname)+1:] if myname.endswith('()'): myname = myname[:-2] # Try to parse docstring docstr = self.get_attr(self.object, '__doc__', None) if docstr: docstr = force_decode(docstr, 'utf-8') if (docstr and (myname + '(') in docstr and '\n' in docstr and docstr[docstr.index('\n')-1] == ')'): args = docstr[len(myname)+1:docstr.index('\n')-1] # Get rid of Cython style types declarations argl = [] for arg in [ x.strip() for x in args.split(',') ]: if (arg in ('cls', 'self') and isinstance(self, SphinxAutodoc.MethodDocumenter)): continue hit = TYPE_RE.match(arg) if hit: argl.append(hit.group(1)) else: argl.append(arg) args = '(%s)' % ', '.join(argl) else: # super seems to get this wrong: for cls in (MethodDocumenter, FunctionDocumenter, ClassDocumenter): if isinstance(self, cls): return cls.format_args(self) # return super(self.__class__, self).format_args() # escape backslashes for reST args = args.replace('\\', '\\\\') return args class MyFunctionDocumenter(MyDocumenter, SphinxAutodoc.FunctionDocumenter): pass class MyMethodDocumenter(MyDocumenter, SphinxAutodoc.MethodDocumenter): pass class MyClassDocumenter(MyDocumenter, SphinxAutodoc.ClassDocumenter): def format_signature(self): return self.format_args() or "()" SphinxAutodoc.ClassDocumenter = MyClassDocumenter SphinxAutodoc.MethodDocumenter = MyMethodDocumenter SphinxAutodoc.FunctionDocumenter = MyFunctionDocumenter # don't use AttributeDocumenter on 'method_descriptor' members: AD = SphinxAutodoc.AttributeDocumenter AD.method_types = tuple(list(AD.method_types) + [type(str.count)])