如何在Cython中使用Sphinx?

时间:2012-04-07 19:08:54

标签: cython python-sphinx

我最近通过将所有模块(顶级__init__.py除外)重命名为*.pyx,并将ext_modules = [Extension('foo', ['foo.pyx'])]放入setup.py,对我的项目进行了Cython化}。建筑和安装工作正常。但是,当我执行cd doc; make html时,Sphinx会失败,因为它无法导入任何现在为*.pyx的模块。

如果我修改doc/conf.py并将sys.path.insert(0, os.path.abspath('..'))更改为sys.path.insert(0, os.path.abspath('../build/temp.linux-x86_64-2.7')),那么Sphinx可以找到所有模块并生成文档,但在这种情况下,我会收到{{1}这样的错误}。大概这是因为现在Sphinx只能访问error while formatting arguments for foo.bar: <built-in function bar> is not a Python function文件,而不是源文件。同样的*.so修改也允许通过Sphinx(sys.path)运行doctests。

我尝试的其他解决方案是使用扩展程序make doctest而不是*.py(并在*.pyx中使用ext_modules = [Extension('foo', ['foo.py'])])。在这种情况下,文档构建正确,但我认为doctests现在绕过Cython。

我无法在网上找到有关一起使用Sphinx和Cython的任何信息。我查看了一些使用两者的项目的源代码,但它们似乎没有使用setup.py文件中的文档字符串。我知道Sage确实如此,但是这个项目太复杂了我无法分开。

Sphinx是否支持Cython文件中的文档字符串?如果是这样,我该如何工作呢?

3 个答案:

答案 0 :(得分:7)

你看起来有点困惑。 Sphinx并不是一个真正的语法分析器。您的Python代码必须是可运行的,以使Sphinx能够捕获文档字符串。这就是为什么将扩展文件重命名为“.py”无济于事。

好吧,我最近一直在与Sphinx和Cython合作,并希望分享我的经验...这里是从docstrings自动生成给定编译的Cython扩展的html文档的完整详细过程:< / p>

[注意:我使用的是Sphinx 1.1.3和Cython 0.17.4]

首先,使用Python的“docstrings”(具有它可能具有的所有限制 - 例如,您无法在Cython代码中描述构造函数。请参阅docstrings规范):

cdef class PyLabNode:
    """
    This is a LabNode !!!
    """
    cdef LabNode* thisptr
    cdef PyLabNetwork network

    def __cinit__(self):
       self.thisptr = new LabNode()

    def __dealloc__(self):
       if self.thisptr:
           del self.thisptr

    def SetNetwork(self, PyLabNetwork net):
        """
        Set the network !!!
        """
        self.network = net

重新编译“yourextension.so”。

然后运行“sphinx-quickstart”并回答问题。当被问到“autodoc”时,不要忘记说是。这将生成“Makefile”,“index.rst”文件和“conf.py”文件。

必须编辑最后一个“conf.py”以告诉Sphinx找到你的模块:

# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../../parent/dir/of/yourextension/'))

还必须编辑“index.rst”文件,以告知可能分析的模块:

Contents:

.. toctree::
   :maxdepth: 2


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

最后通过执行以下操作构建文档:

$ make html

这对我来说已经足够了(我在“... / _ build / html /”目录中得到了一组html文件)。可能是Sphinx和Cython自上一个问题被提出以来已经发展,但我没有“签名”问题需要处理。没有特定的Cython指令可供使用,也没有任何修复适用于Sphinx ...

希望这有帮助。

编辑:嗯,我想回复我的话。我在使用Epydoc时遇到了“Dan”提到有关“embedsignature”问题的问题(所以我想这也是Sphinx的一个问题)。激活此编译器指令不会发送符合python标准的签名:

PyLabNode.SetNetwork(self, PyLabNetwork net)

这有两个缺点:类前缀和类型参数的点分表示法。

最后,我能想出发送正确的唯一方法是在doc字符串的第一行写一个兼容的签名,如下所示:

def SetNetwork(self, PyLabNetwork net):
    """
    SetNetwork(self, net)
    Set the net !!!
    @param self: Handler to this.
    @type self: L{PyLabNode}
    @param net: The network this node belongs to.
    @type net: L{PyLabNetwork}
    """
    self.network = net

希望这可以帮助Sphinx和Epydoc用户......


编辑关于__cinit__,我能够通过加倍描述来成功生成Epidoc(未尝试使用Sphinx)的文档,如下所示:

# For Epydoc only (only used for docstring)
def __init__(self, sim):
    """
    __init__(self, sim)
    Constructor.
    @param sim: The simulator this binding is attached to.
    @type sim: L{PyLabSimulatorBase} 
    """ 

# Real Cython init
def __cinit__(self, PyLabSimulatorBase sim):
   self.thisptr = new LabNetBinding()
   self.sites = []
   simulator = sim

答案 1 :(得分:6)

随意留下更好的答案,但这是我找到的修复方法。

dipy项目从doc/conf.py手动导入自己的模块。这需要首先安装模块,但它修复了导入错误(并且doctests将在Cythonized文件上运行)。

然而,error while formatting arguments问题仍然存在。首先,您需要指示Cython将方法/函数签名嵌入到*.so文件中。通过设置embedsignature Cython指令来完成此操作。 dipy项目在每个*.pyx文件中设置此项,但也可以在setup.py中设置它(有关如何执行此操作,请参阅Cython文档)。这仍然不会将方法签名放入Sphinx文档中!方法签名问题here有一个错误报告和补丁。它至今仍未包含在最新的Sphinx版本中(1.1.3),但是如果你从开发回购中安装Sphinx它将会起作用。

答案 2 :(得分:1)

正如Golgauth所解释的那样,Sphinx的autodoc模块从.so而不是.pyx获取文档字符串。在cython化Python模块时,无需对Sphinx配置进行任何更改即可生成文档的最简单方法是在生成文档之前简单地构建扩展模块

python setup.py build_ext --inplace

通过这种方式,autodoc可以找到扩展模块和常规Python模块,并且能够按照您的预期生成文档。

为了不遗忘这一步骤,您可以修改Makefile生成的sphinx-quickstart,以便在运行sphinx-build之前构建扩展模块:

html:
  @cd /path/to/setup.py; python setup.py build_ext --inplace
  ...