У меня в качестве минимального примера есть следующая структура пакета (для удобства все загружено здесь):
.
├── sphinx
│ ├── build
│ ├── Makefile
│ └── source
│ ├── conf.py
│ ├── index.rst
│ └── train.rst
└── train
├── __init__.py
└── train.py
При написании пакетов Python необходимо указать константу __all__
в __init__.py
любого пакета, чтобы Sphinx мог отображать ссылку, такую как train.DatasetMeta
, на train.train.DatasetMeta
или аналогичный. Однако sphinx-apidoc
создает следующие разделы для этих пакетов:
train package
=============
Submodules
----------
train.train module
------------------
.. automodule:: train.train
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: train
:members:
:undoc-members:
:show-inheritance:
Это дублирует всю документацию, поскольку она содержит .. automodule:: module.file
, а также .. automodule:: module
, которые относятся к одному и тому же. Удаление любого из этих разделов приводит к появлению предупреждений о неопределенных ссылках (превращенных в ошибки при использовании -n
- SPHINXOPTS
).
sphinx_test/train/train.py:docstring of train.DatasetMeta:1:py:class reference target not found: train.train.DatasetMeta
Как я могу это решить?
поезд / train.py
from collections import namedtuple
class DatasetMeta(namedtuple('DatasetMeta', ['dataset', 'num_classes', 'shape'])):
@property
def size(self):
'''int: Number of examples in the dataset'''
return self.shape[0]
поезд / __ init__.py
from .train import *
__all__ = ['DatasetMeta']
сфинкс / источник / conf.py
import os
import sys
sys.path.insert(0, os.path.abspath('.'))
sys.path.insert(0, os.path.abspath('../../'))
project = 'test'
copyright = ''
author = ''
version = ''
release = '0'
extensions = [
'sphinx.ext.autodoc',
]
source_suffix = '.rst'
master_doc = 'index'
Я просто не могу понять, в чем тут логика.
Как я уже сказал, я не могу удалить это, так как получаю предупреждения sphinx_test/train/train.py:docstring of train.DatasetMeta:1:py:class reference target not found: train.train.DatasetMeta
. Я использую режим придирчивости, поэтому это ошибка, и я бы хотел, чтобы она была решена должным образом.
Проблема, по-видимому, частично связана с использованием :show-inheritance:
с классом, который наследуется от namedtuple
; удаление строки :show-inheritance:
приводит к созданию документации, но я не знаю, насколько это приемлемо.
Я предполагаю, что это то же самое для каждого класса, который наследуется от класса, живущего в подпакете.
Какую версию Sphinx вы используете? Вы видели github.com/sphinx-doc/sphinx/issues/4609? Ваше сообщение об ошибке выглядит так же фальшиво, как и сообщения в этом отчете об ошибке.
Я видел проблему и, конечно, мог бы обойти предупреждение, но это означало бы, что я не получу гиперссылку для ссылки.
Тот, который генерирует предупреждение / ошибку из вопроса.
Извините, я не понимаю, о чем вы говорите. На какой код или разметку RST в вашем проекте вы имеете в виду?
Извините, запуталась. На самом деле, вероятно, в этом случае он не создает ссылку, поскольку ошибка возникает просто при использовании .. automodule
в контексте наследования. Но если бы я использовал: class: train.DatasetMeta
в другом месте, у меня была бы проблема, заключающаяся в том, что я получаю эту ошибку при удалении одного из разделов, поэтому мне пришлось бы поместить это в список игнорирования и не получить ссылку для Это.
Это не проблема Sphinx - это проблема объявления класса DatasetMeta
. Вы объявляете класс с именем DatasetMeta
в списке наследования DatasetMeta
, поэтому DatasetMeta.__bases__
будет содержать train.train.DatasetMeta
- не ваш класс, а namedtuple
с таким же именем. Это наследство, которое получает Сфинкс.
В зависимости от того, какую версию Python вы используете: если это Python 3.6, я бы предложил создать подкласс typing.NamedTuple
и использовать аннотации переменных экземпляра, чтобы у вас было правильное подклассирование от tuple
stdlib. Или даже лучше, используйте классы данных, если вы ориентируетесь на Python 3.7.
@hoefling Отлично, похоже, в этом проблема, в некотором роде есть смысл.
Однако я все еще сталкиваюсь с этой проблемой, если я определяю класс в подмодуле и наследую от него в том же подмодуле. Должен быть способ обойти это.
В том же файле я могу явно указать атрибут __module__
для рассматриваемого класса, но это не сработает, если я наследую от этого класса в другом подмодуле.
@oarfish Это зависит от того, какого конечного результата вы хотите достичь. Если вы хотите сохранить наследование от namedtuple
, как показано в вашем вопросе, я бы пошел с отключением опции show-inheritance
для класса DatasetMeta
, поскольку он в основном бесполезен и не отражает фактическую кодовую базу (вы все равно не можете создать подкласс DatasetMeta
namedtuple , так зачем вообще это задокументировать?). Вы можете отключить show-inheritance
динамически в conf.py
с помощью событий. Если для этого понадобится пример, напишу ответ с рабочим кодом.
В общем, я бы хотел, чтобы во всей документации использовалось сокращенное имя, то есть train
вместо train.train
в этом примере. Для этого конкретного класса я мог бы отключить отображение наследования, но представьте, что модуль определяет класс, от которого я часто наследую (что происходит в моем исходном коде, из которого я получил этот пример). Эту иерархию полезно задокументировать, поэтому в этом случае я бы предпочел не выключать :show-inheritance:
.
Одна вещь, которую мы можем сделать, чтобы упростить ситуацию, - это небольшое переименование:
class DatasetMeta(namedtuple('DatasetMetaBase', ['dataset', 'num_classes', 'shape'])):
что должно сделать очевидным, что отсутствующая ссылка - это train.train.DatasetMetaBase
, когда вы удаляете блок train.train
из первого файла, созданного sphinx-apidoc
. В документации для train.DatasetMeta
и train.train.DatasetMeta
будет ссылка на train.train.DatasetMetaBase
; Я не знаю, как обойти это без исправления autodoc или добавления собственных директив.
Отсюда я вижу несколько вариантов:
(1) Переместите DatasetMetaBase
в другой модуль, который не импортирован в __init__.py
. Например
from .abstract import DatasetMetaBase
class DatasetMeta(DatasetMetaBase):
Таким образом, autodoc для DatasetMeta
ссылается на train.abstract.DatasetMetaBase
, который в вашем случае должен быть уникальной ссылкой.
(2) Создайте отдельный первый файл (скажем, hidden.rst
), который отображает документы для train.train.DatasetMetaBase
, но сначала скрыт от основного.
# hidden.rst
.. autodata:: train.train.DatasetMetaBase
Этого должно быть достаточно, чтобы добавить train.train.DatasetMetaBase
в sphinx и устранить предупреждение class reference target not found
.
Удаление блока
train.train
из сгенерированного документа Sphinx кажется мне самым простым решением. Какие «предупреждения о неопределенных ссылках» вы получаете, когда это делаете?