From b4f91a5ce58c7accb2d580e84771e5d563e873d6 Mon Sep 17 00:00:00 2001 From: Georg Brandl Date: Tue, 29 Jul 2008 18:30:23 +0000 Subject: [PATCH] #3422: allow changing the signature of functions via a new hook. --- CHANGES | 3 +++ doc/ext/autodoc.rst | 31 +++++++++++++++++++++---- setup.py | 2 +- sphinx/ext/autodoc.py | 53 +++++++++++++++++++++++++++++++------------ 4 files changed, 69 insertions(+), 20 deletions(-) diff --git a/CHANGES b/CHANGES index 99e8fc2aa..a44481713 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,9 @@ New features added to disable the anchor-link creation after headlines and definition links. EXPERIMENTAL +* sphinx.doc.autodoc has a new event ``autodoc-process-signature`` that + allows tuning function signature introspection. + Release 0.4.2 (Jul 29, 2008) ============================ diff --git a/doc/ext/autodoc.rst b/doc/ext/autodoc.rst index 683dad71f..e1229521c 100644 --- a/doc/ext/autodoc.rst +++ b/doc/ext/autodoc.rst @@ -189,12 +189,12 @@ There are also new config values that you can set: Docstring preprocessing ----------------------- -.. versionadded:: 0.4 - -autodoc provides the following additional event: +autodoc provides the following additional events: .. event:: autodoc-process-docstring (app, what, name, obj, options, lines) + .. versionadded:: 0.4 + Emitted when autodoc has read and processed a docstring. *lines* is a list of strings -- the lines of the processed docstring -- that the event handler can modify **in place** to change what Sphinx puts into the output. @@ -211,9 +211,32 @@ autodoc provides the following additional event: auto directive :param lines: the lines of the docstring, see above +.. event:: autodoc-process-signature (app, what, name, obj, options, signature, return_annotation) + + .. versionadded:: 0.5 + + Emitted when autodoc has formatted a signature for an object. The event + handler can return a new tuple ``(signature, return_annotation)`` to change + what Sphinx puts into the output. + + :param app: the Sphinx application object + :param what: the type of the object which the docstring belongs to (one of + ``"module"``, ``"class"``, ``"exception"``, ``"function"``, ``"method"``, + ``"attribute"``) + :param name: the fully qualified name of the object + :param obj: the object itself + :param options: the options given to the directive: an object with attributes + ``inherited_members``, ``undoc_members``, ``show_inheritance`` and + ``noindex`` that are true if the flag option of same name was given to the + auto directive + :param signature: function signature, as a string of the form + ``"(parameter_1, parameter_2)"``, or ``None`` if introspection didn't succeed + and signature wasn't specified in the directive. + :param return_annotation: function return annotation as a string of the form + ``" -> annotation"``, or ``None`` if there is no return annotation The :mod:`sphinx.ext.autodoc` module provides factory functions for commonly -needed docstring processing: +needed docstring processing in event :event:`autodoc-process-docstring`: .. autofunction:: cut_lines .. autofunction:: between diff --git a/setup.py b/setup.py index b9f3f4e61..454e098cf 100644 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import ez_setup ez_setup.use_setuptools() import sys -from setuptools import setup, Feature +from setuptools import setup import sphinx diff --git a/sphinx/ext/autodoc.py b/sphinx/ext/autodoc.py index 315003046..5210087b6 100644 --- a/sphinx/ext/autodoc.py +++ b/sphinx/ext/autodoc.py @@ -320,27 +320,49 @@ class RstGenerator(object): mod = self.env.currmodule return fullname, mod, [cls, base], args, retann - def format_signature(self, what, obj, args, retann): + def format_signature(self, what, name, obj, args, retann): """ Return the signature of the object, formatted for display. """ if what not in ('class', 'method', 'function'): return '' + + err = None if args is not None: # signature given explicitly - return '(%s)%s' % (args, retann or '') - if what == 'class': - # for classes, the relevant signature is the __init__ method's - obj = getattr(obj, '__init__', None) - # classes without __init__ method? - if obj is None or obj is object.__init__ or not \ - (inspect.ismethod(obj) or inspect.isfunction(obj)): - return '' - argspec = inspect.getargspec(obj) - if what in ('class', 'method') and argspec[0] and \ - argspec[0][0] in ('cls', 'self'): - del argspec[0][0] - return inspect.formatargspec(*argspec) + args = "(%s)" % args + else: + # try to introspect the signature + try: + if what == 'class': + # for classes, the relevant signature is the __init__ method's + obj = getattr(obj, '__init__', None) + # classes without __init__ method? + if obj is None or obj is object.__init__ or not \ + (inspect.ismethod(obj) or inspect.isfunction(obj)): + return '' + argspec = inspect.getargspec(obj) + if what in ('class', 'method') and argspec[0] and \ + argspec[0][0] in ('cls', 'self'): + del argspec[0][0] + args = inspect.formatargspec(*argspec) + except Exception, e: + args = None + err = e + + results = self.env.app.emit('autodoc-process-signature', + what, name, obj, self.options, args, retann) + for result in results: + if result: + args, retann = result + + if args is not None: + return '%s%s' % (args, retann or '') + elif err: + # re-raise the error for perusal of the handler in generate() + raise RuntimeError(err) + else: + return '' def generate(self, what, name, members, add_content, indent=u'', check_module=False): """ @@ -383,7 +405,7 @@ class RstGenerator(object): # format the object's signature, if any try: - sig = self.format_signature(what, todoc, args, retann) + sig = self.format_signature(what, name, todoc, args, retann) except Exception, err: self.warn('error while formatting signature for %s: %s' % (fullname, err)) @@ -596,3 +618,4 @@ def setup(app): app.add_config_value('automodule_skip_lines', 0, True) app.add_config_value('autoclass_content', 'class', True) app.add_event('autodoc-process-docstring') + app.add_event('autodoc-process-signature')