Sphinx无法记录复杂的Enum类。

5

在我的代码中,有一些复杂的枚举类型类。例如:

class ComplexEnum(SomeOtherClass, Enum):
    """ Some documentation """

    MEMBER1 = SomeOtherClass(1)
    MEMBER2 = SomeOtherClass(2)

    def __init__(self, arg):
        """ more doc """
        pass

    def somemethod(self):
        """ more doc """
        pass

    @classmethod
    def someclassmethod(cls, otherparam):
        """ more doc """
        pass

当我使用Sphinx和autodoc创建文档时,这个类被直接跳过了。我尝试在我的conf.py文件中添加一个自定义文档生成器,如下所示:

from sphinx.ext.autodoc import ClassDocumenter

class MyClassDocumenter(ClassDocumenter):
    objtype = 'ComplexEnum'
    directivetype = 'class'

    @classmethod
    def can_document_member(cls, member, membername, isattr, parent):
        return isinstance(member, ComplexEnum)

def setup(app):
    app.add_autodocumenter(MyClassDocumenter)

但这也行不通。

我如何让Sphinx记录这些类型的类?


2
它对我来说几乎可以工作。该类并没有完全被跳过,但是该类方法的文档缺失。可能与https://github.com/sphinx-doc/sphinx/issues/6857有关。 - mzjn
嗯,对我来说整个类都被跳过了,很奇怪。但是是的,这可能与GitHub上的那个错误有关。 - Rittel
如果整个类被跳过,请尝试将枚举和父类隔离到一个模块中,然后逐步添加其他类。 - bad_coder
1个回答

7

这是Sphinx autodoc中的一个bug,与某些使用Enum的情况有关。

可以通过仔细编写.rst文件来解决这个问题。

话虽如此,我认为这是针对以下内容的:

enter image description here

相应的.rst文件:

my_module module
================

.. automodule:: my_module
   :exclude-members: ComplexEnum


   .. autoclass:: ComplexEnum
      :members: some_method
      :show-inheritance:
      :exclude-members: MEMBER1, MEMBER2, __init__, some_classmethod

      .. automethod:: some_classmethod  

      .. autoattribute:: MEMBER1
         :annotation: = SomeOtherClass(1)

      .. autoattribute:: MEMBER2
         :annotation: = SomeOtherClass(2)

      .. automethod:: __init__

   .. autoclass:: SomeOtherClass
      :special-members: __init__

我稍微修改了代码,以更好地解释一些解决方法的细节:

from enum import Enum


class SomeOtherClass:
    """ SomeOtherClass documentation """

    def __init__(self, other_arg):
        """Example of docstring on the __init__ method.

        Args:
            other_arg (int): Description of `other_arg`.
        """
        self.other_arg = other_arg


class ComplexEnum(SomeOtherClass, Enum):
    """ComplexEnum documentation."""

    #: :py:mod:`~my_package.my_module.SomeOtherClass`: MEMBER1 docstring comment.
    MEMBER1 = SomeOtherClass(1)
    #: :py:mod:`~my_package.my_module.SomeOtherClass`: MEMBER2 docstring comment.
    MEMBER2 = SomeOtherClass(2)

    def __init__(self, complex_arg):
        """Example of docstring on the __init__ method.

        Args:
            complex_arg (int): Description of `complex_arg`.
        """
        self.complex_arg = complex_arg
        super().__init__(complex_arg)

    def some_method(self):
        """The doc of some_method."""
        pass

    @classmethod
    def some_classmethod(cls, some_arg):
        """The doc of some_classmethod.

        Args:
            some_arg (int): Description of `some_arg`.
        """
        pass

您的conf.py可以保持标准不变,我只添加了extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']以启用谷歌风格注释。



到目前为止,已经确定了触发错误的特定条件,包括链接@mzjn提供的链接和您的帖子,即:

  1. 使用 @classmethod + IntEnum。
  2. 使用 @classmethod + 多重继承,其中一个父类是 Enum。

需要注意的是:仅使用简单的 Enum + @classmethod 不会触发错误。(在这种情况下,.. autoclass:: 的行为符合预期并且几乎处理了所有内容。)



该错误会影响多个autodoc指令及其选项,导致它们的行为与预期不同。

编写.rst文件所需的解决方法如下:

  1. 不要在 Enum 中使用 :undoc-members:,否则将会出现混乱。如果使用,@classmethod 将始终包含在内,而不会获取描述符或文档字符串,并且使用 :exclude-members: 排除它将无效。

  2. 接下来是最问题的部分__init__。最有效的方法是使用 :exclude-members: 将其排除,同时明确使用 .. automethod:: __init__

  3. 除此之外:不能在 .rst文件中使用:automethod:将 @classmethod 放在__init__ 旁边,否则整个 @classmethod 将被“吸收”为 __init__ 文档字符串的一部分。

  4. 对于我来说最有效的方法是使用 :members::exclude-members: 明确包含/排除 Enum 的所有部分。这能够保证最佳的一致性和autodoc 指令/选项的行为。



有两个注意事项与使用 Sphinx 记录 Enum 相关:

  1. 当记录Enum成员时,为了最佳的一致性,请使用#:语法而不是三引号'''或内联#。原因是后者经常被Sphinx“搞混”甚至丢失。

    • 即使使用..member-order: by source作为指令选项或配置,上述情况通常也会发生。
  2. 最后,如果您想在文档中显示Enum成员的值,就像它们出现在类声明语法中一样。根据我的经验,最好的方法是使用如.rst中所示的:annotation:。否则,Enum成员将以以下方式显示在文档中:

enter image description here

使用Python 3.8和Sphinx v2.2.2。


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