Сфинкс не документирует сложные классы Enum - PullRequest
3 голосов
/ 06 января 2020

В моем коде у меня есть несколько классов, которые являются сложными типами Enum. Например:

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, используя autodo c, этот класс просто пропускается. Я попытался добавить пользовательский документатор, подобный этому, в мой файл 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 документировать такие классы?

1 Ответ

2 голосов
/ 06 февраля 2020

Это ошибка в Sphinx autodoc, возникающая при некоторых применениях 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'] для включения комментариев в стиле Google.



Определенная комбинация c условий, вызывающих ошибку , идентифицирована, поэтому далеко, по ссылке @mzjn, внесенной вами и вашим сообщением, а именно:

  1. Использование @classmethod + IntEnum.
  2. Использование @classmethod + множественное наследование, одним из родителей является Enum .

Следует отметить: использование простого Enum с @classmethod не вызывает ошибку. (В этом случае .. autoclass:: ведет себя как ожидалось и заботится практически обо всем.)



Ошибка затрагивает несколько директив autodoc и их параметры, вызывая непредсказуемое поведение.

Необходимые обходные пути при написании .rst следующие:

  1. НЕ используйте :undoc-members: в Enum, иначе может произойти смена , Если вы это сделаете, @classmethod всегда будет включен без выбора дескриптора или строки документации, и исключение его с помощью :exclude-members: не будет иметь никакого эффекта.

  2. Далее __init__ - это Наиболее проблемный аспект c. То, что сработало, исключало его с :exclude-members: вместе с явным использованием .. automethod:: __init__.

  3. Вместе с вышеизложенным: вы НЕ МОЖЕТЕ поставить @classmethod рядом с __init__, используя :automethod: в .rst, иначе весь @classmethod будет "поглощен" как часть __init__ строки документации.

  4. Для меня лучше всего было включить / исключить все части Enum явно с :members: и :exclude-members:. Это гарантирует наилучшую согласованность с поведением директив / опций autodoc.



Две последние заметки относятся к документирование Enum с использованием Sphinx (напрямую не связано с ошибкой).

  1. При документировании членов Enum для лучшей согласованности используйте синтаксис #: вместо тройных кавычек ''' или встроенный #. Причина в том, что последние часто «путаются» или даже теряются Сфинксом.

    • Выше, как правило, так даже при использовании ..member-order: by source в качестве параметра директивы или в конфигурациях.
  2. Наконец, если вы хотите значения членов Enum, отображаемые в документации, в том виде, в котором они указаны в синтаксисе объявления класса. На мой взгляд, лучший способ - использовать :annotation:, как показано в .rst. В противном случае члены Enum будут отображаться в документации следующим образом:

enter image description here

Использование Python 3.8 с Sphinx v2.2.2 .

...