Сфінкса autodoc недостатньо автоматичний


149

Я намагаюся використовувати Sphinx для документування 5000-лінійного проекту в Python. Він має близько 7 базових модулів. Наскільки я знаю, для використання autodoc мені потрібно написати такий код для кожного файлу в моєму проекті:

.. automodule:: mods.set.tests
    :members:
    :show-inheritance:

Це занадто нудно, тому що у мене багато файлів. Було б набагато простіше, якби я міг просто вказати, що хочу, щоб пакет "модників" був задокументований. Потім Сфінкс може рекурсивно пройти через пакет і створити сторінку для кожного підмодуля.

Чи є така функція? Якщо ні, я міг би написати сценарій, щоб створити всі .rst файли, але це займе багато часу.


Що поганого в написанні невеликого сценарію, який використовує "os.walk" і пише все це? До речі, у мене 40 000+ лінійний проект і мені незрозуміло, про що ви говорите. Скільки файлів задіяно? Наскільки важко може бути маршрутом lsдо файлу та редагувати це?
С.Лотт

125
Ніхто не сказав, що це важко. ОП сказала, що це нудно , що це таке. Зважаючи на те, що це можуть робити інші системи док-станцій, це нерозумно.
Грегг Лінд

Просто використовуйте pdoc .
K3 --- rnc

Відповіді:


143

Ви можете перевірити цей сценарій який я створив. Я думаю, що це може вам допомогти.

Цей скрипт аналізує дерево каталогів, шукаючи модулі та пакети python, і створює файли ReST належним чином, щоб створити кодову документацію за допомогою Sphinx. Він також створює індекс модулів.

ОНОВЛЕННЯ

Цей сценарій зараз є частиною Сфінкса 1.1 як apidoc .


Куди ви повинні виводити файли? Я спробував вивести їх у папку _build за замовчуванням _ Sphinx, але запуск sphinx-build -b html . ./_buildне підбирає їх.
Серін

Ви повинні помістити їх у source directory(. У вашому випадку). У каталозі _build буде створено HTML-файли. Перевірте більше інформації: sphinx.pocoo.org/tutorial.html#running-the-build
Етьєн

1
@Erienne: фантастичний сценарій! просто те, що я шукав. Хочете, щоб вони генерували заголовки для окремих класів (звичайний вигляд сфінкса не приємний для класів. Вони губляться у великих модулях)
jbenet

1
Навіть сфінкс-апідок досить рудиментарний. Для пакету з одним або двома модулями він працює нормально, але у нас модулі вкладені глибоко, і сфінкс-apidoc дає деякий досить некерований вихід.
шило

4
.. include:: modules.rstindex.rst
самовідповідь

40

Я не знаю, чи був у Сфінкса autosummaryрозширення на той час, коли задавались оригінальні запитання, але наразі цілком можливо встановити автоматичну генерацію такого типу без використання sphinx-apidocабо подібного сценарію. Нижче є налаштування, які працюють для одного з моїх проектів.

  1. Увімкніть autosummaryрозширення (як і autodoc) у conf.pyфайлі та встановіть його autosummary_generateпараметр на True. Це може бути достатньо, якщо ви не використовуєте власні *.rstшаблони. В іншому випадку додайте каталог шаблонів, щоб виключити список, або autosummaryспробуєте розглянути їх як вхідні файли (що здається помилкою).

    extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary']
    autosummary_generate = True
    templates_path = [ '_templates' ]
    exclude_patterns = ['_build', '_templates']
  2. Використовуйте autosummary::в дереві TOC у вашому index.rstфайлі. У цьому прикладі документації для модулів project.module1і project.module2буде згенерований автоматично і поміщається в _autosummaryкаталог.

    PROJECT
    =======
    
    .. toctree::
    
    .. autosummary::
       :toctree: _autosummary
    
       project.module1
       project.module2
  3. За замовчуванням autosummaryбудуть генеруватися лише дуже короткі підсумки модулів та їх функцій. Щоб змінити, ви можете помістити файл власного шаблону _templates/autosummary/module.rst(який буде розібраний з Jinja2 ):

    {{ fullname }}
    {{ underline }}
    
    .. automodule:: {{ fullname }}
        :members:

На закінчення, немає необхідності тримати _autosummaryкаталог під контролем версій. Крім того, ви можете назвати все, що завгодно, і розмістити його в будь-якому місці у вихідному дереві (однак розміщення його нижче _buildне вийде).


4
Це була величезна допомога. У пункті 2, де у вас є "project.module1" та "project.module2", чи існує спосіб автоматичного генерування цього списку для кожного модуля в заданому пакеті? Щоб просто поставити "проект" і чи обнюхати його "module1" та "module2"?
Браун

Досить здивований, що я ніде не можу знайти відповіді на це, dod, коли-небудь випрацюєте це @Brown?
Елісдор Робертсон

3
@AlisdairRobertson Ні, але запропоноване рішення з автозапчастини в кінцевому підсумку було більш ніж адекватним для моїх потреб. Єдине інше, що я думав зробити, це написати сценарій для створення файла index.rst та автоматичного виявлення імен модулів. Однак на практиці список модулів змінюється не так часто, тому просто редагування одного файлу час від часу не є таким необґрунтованим. Я впевнений, що я вже витратив набагато більше часу на пошук рішення, ніж потрібно, щоб просто відредагувати цей один файл!
Коричневий

12

У кожному пакеті __init__.pyфайл може бути.. automodule:: package.module компоненти для кожної частини пакета.

Тоді ви можете, .. automodule:: packageі це здебільшого робить те, що ви хочете.


я просто поклав цей рядок у потрійні лапки в init .py?
Cory Walker

5
@Cory Walker: Це не "a" рядок. Ви можете - і повинні - вводити потрійні цитати в кожен файл. Кожен. Це включає __init__.pyфайли у ваших пакунках. Документальна стрічка може включати будь-які директиви щодо документації щодо Сфінкса, включаючи .. automodule::модулі в пакеті.
S.Lott

2
autodocце помилка друку automodule. але дякую за підказку!
mariotomo

9

З версії 3.1 Сфінкса 3.1 (червень 2020 р.) sphinx.ext.autosummary(Нарешті!) Відбулася рекурсія.

Тому не потрібно жорстко називати кодові модулі та покладатися на сторонні бібліотеки, такі як Sphinx AutoAPI або Sphinx AutoPackageSummary для їх автоматичного виявлення пакунків.

Приклад пакета Python 3.7 для документування ( див. Код на Github та результат на ReadTheDocs ):

mytoolbox
|-- mypackage
|   |-- __init__.py
|   |-- foo.py
|   |-- mysubpackage
|       |-- __init__.py
|       |-- bar.py
|-- doc
|   |-- source
|       |--index.rst
|       |--conf.py
|       |-- _templates
|           |-- custom-module-template.rst
|           |-- custom-class-template.rst

conf.py:

import os
import sys
sys.path.insert(0, os.path.abspath('../..'))  # Source code dir relative to this file

extensions = [
    'sphinx.ext.autodoc',  # Core library for html generation from docstrings
    'sphinx.ext.autosummary',  # Create neat summary tables
]
autosummary_generate = True  # Turn on sphinx.ext.autosummary

# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']

index.rst(зверніть увагу на новий :recursive:варіант):

Welcome to My Toolbox
=====================

Some words.

.. autosummary::
   :toctree: _autosummary
   :template: custom-module-template.rst
   :recursive:

   mypackage

Цього достатньо для автоматичного узагальнення кожного модуля в пакеті, який би глибоко вкладений. Потім для кожного модуля він підсумовує кожен атрибут, функцію, клас та виняток у цьому модулі.

Як не дивно, sphinx.ext.autosummaryшаблони за замовчуванням не продовжують генерувати окремі сторінки документації для кожного атрибута, функції, класу та винятку та посилатися на них із зведених таблиць. Можна розширити шаблони для цього, як показано нижче, але я не можу зрозуміти, чому це не поведінка за замовчуванням - напевно, саме цього хотіли б більшість людей ..? Я підняв це як запит на функції .

Мені довелося локально скопіювати шаблони за замовчуванням, а потім додати їх:

  • Скопіювати site-packages/sphinx/ext/autosummary/templates/autosummary/module.rstвmytoolbox/doc/source/_templates/custom-module-template.rst
  • Скопіювати site-packages/sphinx/ext/autosummary/templates/autosummary/class.rstвmytoolbox/doc/source/_templates/custom-class-template.rst

Гачок custom-module-template.rstзнаходиться index.rstвгорі, використовуючи :template:параметр. (Видаліть цей рядок, щоб побачити, що відбувається за допомогою шаблонів пакетів сайтів за замовчуванням.)

custom-module-template.rst (додаткові рядки, зазначені праворуч):

{{ fullname | escape | underline}}

.. automodule:: {{ fullname }}
  
   {% block attributes %}
   {% if attributes %}
   .. rubric:: Module Attributes

   .. autosummary::
      :toctree:                                          <-- add this line
   {% for item in attributes %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block functions %}
   {% if functions %}
   .. rubric:: {{ _('Functions') }}

   .. autosummary::
      :toctree:                                          <-- add this line
   {% for item in functions %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block classes %}
   {% if classes %}
   .. rubric:: {{ _('Classes') }}

   .. autosummary::
      :toctree:                                          <-- add this line
      :template: custom-class-template.rst               <-- add this line
   {% for item in classes %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block exceptions %}
   {% if exceptions %}
   .. rubric:: {{ _('Exceptions') }}

   .. autosummary::
      :toctree:                                          <-- add this line
   {% for item in exceptions %}
      {{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

{% block modules %}
{% if modules %}
.. rubric:: Modules

.. autosummary::
   :toctree:
   :template: custom-module-template.rst                 <-- add this line
   :recursive:
{% for item in modules %}
   {{ item }}
{%- endfor %}
{% endif %}
{% endblock %}

custom-class-template.rst (додаткові рядки, зазначені праворуч):

{{ fullname | escape | underline}}

.. currentmodule:: {{ module }}

.. autoclass:: {{ objname }}
   :members:                                    <-- add at least this line
   :show-inheritance:                           <-- plus I want to show inheritance...
   :inherited-members:                          <-- ...and inherited members too

   {% block methods %}
   .. automethod:: __init__

   {% if methods %}
   .. rubric:: {{ _('Methods') }}

   .. autosummary::
   {% for item in methods %}
      ~{{ name }}.{{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

   {% block attributes %}
   {% if attributes %}
   .. rubric:: {{ _('Attributes') }}

   .. autosummary::
   {% for item in attributes %}
      ~{{ name }}.{{ item }}
   {%- endfor %}
   {% endif %}
   {% endblock %}

6

Сфінкс AutoAPI робить саме це.


1
О Боже мій! Це працює набагато краще, ніж будь-що інше. Зауважте, що це НЕ "autodoc" чи "apidoc", це зовсім інше розширення.
скакалка

2
Дітто. Це ставить "auto" в "autodoc" .... Ось все, що наш проект повинен був зробити для перемикання: Перейти на autoapi з autodoc по nealmcb · Потягнути запит \ # 7 · gwexploratoryaudits / r2b2
nealmcb

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.