使用Sphinx autodoc记录Python协程

4
我开始用Sphinx记录我的第一个基于asyncio的项目。我注意到有些项目在某些方法之前有“协程”前缀,我想在我的项目文档中也这样做,但是我不知道如何实现。
例如,aiohttp的HTTP客户端参考显示如下:
class aiohttp.ClientSession(...): coroutine request(...)
该项目似乎使用了一个"coroutinemethod"指令来实现这一点,但是我使用docstrings内联记录所有函数和类,而且只有在reStructuredText文档中编写文档时才能使用此指令。
有人知道如何使用autodoc实现此结果吗?
编辑:如果Sphinx不支持,我也会接受解释如何制作Sphinx扩展来实现此功能的答案。如果有人能指出一种自动检测方法是否为协程的方式,使用"inspect.iscoroutinefunction()"将获得额外的奖励分数。

编辑:我正在查看CPython项目中的"pyspecific" Sphinx扩展程序以获取灵感。但是,我需要更改autodoc的行为,而不是添加新的指令。经过一番研究,看起来autodoc有一个autodoc-process-signature事件可以用于自定义函数签名,但它似乎没有被“pyspecific”扩展使用的对象。

1个回答

3
这个功能在Sphinx中没有现成的支持。但是,pull request #1826 添加了生成器、协程函数、带有内建协程检测的autodoc的autofunctionautomethod指令的协程方法的支持。
这里是一个补丁,在Sphinx 1.4中应用(需要禁用的-W“将警告转化为错误”选项):
# Recipe stolen from open PR (https://github.com/sphinx-doc/sphinx/pull/1826).


from inspect import iscoroutinefunction

from sphinx import addnodes
from sphinx.domains.python import (
    PyClassmember,
    PyModulelevel,
)
from sphinx.ext.autodoc import FunctionDocumenter as _FunctionDocumenter
from sphinx.ext.autodoc import MethodDocumenter as _MethodDocumenter


class PyCoroutineMixin(object):
    """Helper for coroutine-related Sphinx custom directives."""

    def handle_signature(self, sig, signode):
        ret = super(PyCoroutineMixin, self).handle_signature(sig, signode)
        signode.insert(0, addnodes.desc_annotation('coroutine ', 'coroutine '))
        return ret


class PyCoroutineFunction(PyCoroutineMixin, PyModulelevel):
    """Sphinx directive for coroutine functions."""

    def run(self):
        self.name = 'py:function'
        return PyModulelevel.run(self)


class PyCoroutineMethod(PyCoroutineMixin, PyClassmember):
    """Sphinx directive for coroutine methods."""

    def run(self):
        self.name = 'py:method'
        return PyClassmember.run(self)


class FunctionDocumenter(_FunctionDocumenter):
    """Automatically detect coroutine functions."""

    def import_object(self):
        ret = _FunctionDocumenter.import_object(self)
        if not ret:
            return ret

        obj = self.parent.__dict__.get(self.object_name)
        if iscoroutinefunction(obj):
            self.directivetype = 'coroutine'
            self.member_order = _FunctionDocumenter.member_order + 2
        return ret


class MethodDocumenter(_MethodDocumenter):
    """Automatically detect coroutine methods."""

    def import_object(self):
        ret = _MethodDocumenter.import_object(self)
        if not ret:
            return ret

        obj = self.parent.__dict__.get(self.object_name)
        if iscoroutinefunction(obj):
            self.directivetype = 'coroutinemethod'
            self.member_order = _MethodDocumenter.member_order + 2
        return ret


def setup(app):
    """Sphinx extension entry point."""

    # Add new directives.
    app.add_directive_to_domain('py', 'coroutine', PyCoroutineFunction)
    app.add_directive_to_domain('py', 'coroutinemethod', PyCoroutineMethod)

    # Customize annotations for anything that looks like a coroutine.
    app.add_autodocumenter(FunctionDocumenter)
    app.add_autodocumenter(MethodDocumenter)

    # Return extension meta data.
    return {
        'version': '1.0',
        'parallel_read_safe': True,
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接