Emit reStructuredText from sphinx autodoc?

2020-02-26 04:04发布

问题:

CPython doesn't use autodoc for its documentation - we use hand-written prose.

For PEP 3144 (the ipaddress module), I'd like to use sphinx-apidoc to generate the initial reference documentation. That means I want to run a two-pass operation:

  1. Use sphinx-apidoc to emit a Sphinx project for the module that depends on autodoc

  2. Run a sphinx builder that creates new reStructuredText source files, with all the autodoc directives replaced by inline reStructuredText content and markup that produces the same output

The first step is straightforward, but I have no idea how to do the second step and can't even think of good ways to search for any existing projects along these lines.

回答1:

I had same problem and for one time generating of docs I've used quite ugly solution to patch Sphinx, see Make Sphinx generate RST class documentation from pydoc.



回答2:

Not a full answer, more or less a starting point:

autodoc translates auto directives to python directives. So one can use autodoc events to get the translated python directives.

For example if you have the following mymodule.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
This is my module.
"""

def my_test_func(a, b=1):
    """This is my test function"""
    return a + b 

class MyClass(object):
    """This is my class"""

    def __init__(x, y='test'):
        """The init of my class"""
        self.x = float(x)
        self.y = y 

    def my_method(self, z): 
        """This is my method.

        :param z: a number
        :type z: float, int
        :returns: the sum of self.x and z
        :rtype: float
        """
        return self.x + z 

sphinx-apidoc will create

mymodule Module
===============

.. automodule:: mymodule
    :members:
    :undoc-members:
    :show-inheritance:

The following extension (or addition to conf.py):

NAMES = []
DIRECTIVES = {}

def get_rst(app, what, name, obj, options, signature,
            return_annotation):
    doc_indent = '    '
    directive_indent = ''
    if what in ['method', 'attribute']:
        doc_indent += '    '
        directive_indent += '    '
    directive = '%s.. py:%s:: %s' % (directive_indent, what, name)
    if signature:  # modules, attributes, ... don't have a signature
        directive += signature
    NAMES.append(name)
    rst = directive + '\n\n' + doc_indent + obj.__doc__ + '\n'
    DIRECTIVES[name] = rst 

def write_new_docs(app, exception):
    txt = ['My module documentation']
    txt.append('-----------------------\n')
    for name in NAMES:
        txt.append(DIRECTIVES[name])
    print '\n'.join(txt)
    with open('../doc_new/generated.rst', 'w') as outfile:
        outfile.write('\n'.join(txt))

def setup(app):
    app.connect('autodoc-process-signature', get_rst)
    app.connect('build-finished', write_new_docs)

will give you:

My module documentation
-----------------------

.. py:module:: mymodule


This is my module.


.. py:class:: mymodule.MyClass(x, y='test')

    This is my class

    .. py:method:: mymodule.MyClass.my_method(z)

        This is my method.

        :param z: a number
        :type z: float, int
        :returns: the sum of self.x and z
        :rtype: float


.. py:function:: mymodule.my_test_func(a, b=1)

    This is my test function

However as autodoc emits no event, when the translation is completed, So further processing done by autodoc has to be adapted to the docstrings here.