Issues

Issue #564 resolved

autodoc: extract function signature from docstring

Nikolaus Rath
created an issue

When autodoc is used for documenting C extensions, it does not include the function signature (presumably because the Python signature cannot be extracted from a .so module).

Tools for generating C extensions (like Sphinx or Cython) do know the Python signature and should be able to make this information available to sphinx as well.

Cython already suppports embedding the signature in the first line of the docstring. It would be great if autodoc could try to read the function signature from there if it cannot be determined from the function itself.

Comments (16)

  1. Nikolaus Rath reporter

    Attached is the monkeypatch that I'm using at the moment. It changes autodoc to try to find a function signature in the first field of the docstring and additionally removes Cython specific type declarations from the parameter list.

    It should be easy enough to integrate, but it may need some generalization (at the moment it's very Cython specific).

  2. Nikolaus Rath reporter

    This is a new version that is more concise and also gets rid of the final newline after the signature. I'm hereby relicensing it under the same license as Sphinx (in case that's necessary).

  3. Georg Brandl repo owner

    Thanks for the inspiration! I added a similar feature (but implemented it differently) in de340a6098c7 . Note that I do not strip anything from the signature; that can be done in a custom autodoc-process-signature event handler.

  4. Nikolaus Rath reporter
    • removed component
    • removed version

    Thanks for implementing it :-).

    I think you forgot something in doc/ext/autodoc.rst though. The docstring looks incomplete in the middle ("However, it is a well- convention"..?).

  5. Nikolaus Rath reporter
    • changed status to new

    There is also a problem with stripping the docstring indentation. In the output, everything except for the first line (the second after the signature) appears indented in the output. You should be able to test this with

    class DocstringSig(object):
        def meth(self):
            """meth(FOO, BAR=1) -> BAZ
    One line description        
    
            rest of docstring
            """
    

    such a docstring is generated from a Cython function

    class DocstringSig(object):
        cdef meth(self, FOO, BAR=1):
            """One line description        
    
            rest of docstring
            """
    
  6. Nikolaus Rath reporter

    Could you elaborate on how I can strip type declarations from the signature? How do I register an event handler? Do I need to write my own extension?

  7. Nikolaus Rath reporter

    Nevermind, I figured it out. Here is my solution, in case someone else is interested. It needs to be loaded as an extension module.

    import re
    
    TYPE_RE = re.compile(r'(?:int|char)(?:\s+\*?\s*|\s*\*?\s+)([a-zA-Z_].*)')
    
    def setup(app):
        app.connect('autodoc-process-signature', process_signature)
    
    def process_signature(app, what, name, obj, options, signature, return_annotation):
        # Some unused arguments
        #pylint: disable=W0613
        
        if what not in ('function', 'method'):
            return
        
        new_params = list()
        for param in (x.strip() for x in signature[1:-1].split(',')):
            hit = TYPE_RE.match(param)
            if hit:
                new_params.append(hit.group(1))
            else:
                new_params.append(param)
                
        return ('(%s)' % ', '.join(new_params), return_annotation)
    
  8. Anonymous

    Just paste it their literally and remove the module from the extensions list? Or do I need to move the code from setup() into the top level? Is conf.py called with an app object in the namespace?

  9. Georg Brandl repo owner

    conf.py is treated like an extension if it contains a setup(app) function. So if your conf.py has no setup() currently, you can just paste it literally.

  10. Anonymous

    This seems to work with automethod, but not autoclass.

    .. autoclass:: Foo :members: keys

    does not render a function signature, but

    .. autoclass:: Foo

    .. automethod:: keys

    does.

  11. Log in to comment