L'autodoc Sphinx n'est pas assez automatique


149

J'essaie d'utiliser Sphinx pour documenter un projet de plus de 5000 lignes en Python. Il a environ 7 modules de base. Pour autant que je sache, pour utiliser autodoc, je dois écrire un code comme celui-ci pour chaque fichier de mon projet:

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

C'est beaucoup trop fastidieux car j'ai de nombreux fichiers. Ce serait beaucoup plus facile si je pouvais simplement spécifier que je voulais que le paquet 'mods' soit documenté. Sphinx pourrait alors parcourir récursivement le package et créer une page pour chaque sous-module.

Existe-t-il une fonctionnalité comme celle-ci? Sinon, je pourrais écrire un script pour créer tous les fichiers .rst, mais cela prendrait beaucoup de temps.


Quel est le problème avec l'écriture d'un petit script qui utilise "os.walk" et écrit tout cela? BTW, j'ai un projet de plus de 40 000 lignes et je ne sais pas de quoi vous parlez. Combien de fichiers sont impliqués? À quel point peut-il être difficile de router lsvers un fichier et de le modifier?
S.Lott

125
Personne n'a dit que c'était dur. OP a dit que c'était fastidieux , ce qui est le cas. Étant donné que d'autres systèmes de documentation peuvent le faire, ce n'est pas déraisonnable.
Gregg Lind

Utilisez simplement pdoc .
K3 --- rnc

Réponses:


143

Vous pouvez vérifier ce script que j'ai créé. Je pense que cela peut vous aider.

Ce script analyse une arborescence de répertoires à la recherche de modules et de packages python et crée des fichiers ReST de manière appropriée pour créer une documentation de code avec Sphinx. Il crée également un index des modules.

METTRE À JOUR

Ce script fait maintenant partie de Sphinx 1.1 car qu'apidoc .


Où êtes-vous censé sortir les fichiers? J'ai essayé de les sortir dans le dossier _build par défaut de Sphinx, mais l'exécution sphinx-build -b html . ./_buildne les récupère pas.
Cerin

Vous devriez les mettre dans le source directory(. Dans votre cas). Le répertoire _build est l'endroit où les fichiers HTML seront créés. Vérifiez pour plus d'informations: sphinx.pocoo.org/tutorial.html#running-the-build
Etienne

1
@Erienne: scénario fantastique! Exactement ce que je cherchais. Je souhaite qu'il génère des en-têtes pour des classes individuelles (le look normal du sphinx n'est pas agréable pour les classes. Ils se perdent dans des modules plus grands)
jbenet

1
Même le sphinx-apidoc est assez rudimentaire. Pour un paquet avec un ou deux modules, cela fonctionne bien, mais nous avons des modules imbriqués profondément, et sphinx-apidoc produit une sortie assez ingérable.
slacy

4
auto-réponse: ajoutez .. include:: modules.rstà votreindex.rst
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

40

Je ne sais pas si Sphinx avait eu une autosummaryextension au moment où la question initiale a été posée, mais pour l'instant, il est tout à fait possible de configurer une génération automatique de ce type sans utiliser sphinx-apidocou script similaire. Ci-dessous, il y a des paramètres qui fonctionnent pour l'un de mes projets.

  1. Activez l' autosummaryextension (ainsi que autodoc) dans le conf.pyfichier et définissez son autosummary_generateoption sur True. Cela peut suffire si vous n'utilisez pas de *.rstmodèles personnalisés . Sinon, ajoutez votre répertoire de modèles à la liste d'exclusion, ou autosummaryessayez de les traiter comme des fichiers d'entrée (ce qui semble être un bogue).

    extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary']
    autosummary_generate = True
    templates_path = [ '_templates' ]
    exclude_patterns = ['_build', '_templates']
  2. Utilisez autosummary::dans l'arborescence de la table des matières dans votre index.rstfichier. Dans cet exemple de documentation pour les modules project.module1et project.module2sera généré automatiquement et placé dans le _autosummaryrépertoire.

    PROJECT
    =======
    
    .. toctree::
    
    .. autosummary::
       :toctree: _autosummary
    
       project.module1
       project.module2
  3. Par défaut, autosummaryne générera que des résumés très courts pour les modules et leurs fonctions. Pour changer cela, vous pouvez insérer un fichier de modèle personnalisé dans _templates/autosummary/module.rst(qui sera analysé avec Jinja2 ):

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

En conclusion, il n'est pas nécessaire de garder le _autosummaryrépertoire sous contrôle de version. De plus, vous pouvez le nommer comme vous le souhaitez et le placer n'importe où dans l'arborescence des sources (le placer ci-dessous _buildne fonctionnera cependant pas).


4
C'était une aide énorme. Au point 2, où vous avez "project.module1" et "project.module2", y a-t-il un moyen de générer automatiquement cette liste pour chaque module dans un package donné? Pour simplement mettre «projet» et lui faire renifler «module1» et «module2»?
Brown

Assez surpris que je ne trouve pas de réponse à cela nulle part, es-tu déjà arrivé à résoudre @Brown?
Alisdair Robertson le

3
@AlisdairRobertson Non, mais la solution de synthèse automatique fournie s'est avérée plus que adéquate pour mes besoins. La seule autre chose que j'ai pensé à faire était d'écrire un script pour générer le fichier index.rst et de détecter automatiquement les noms des modules. Cependant, dans la pratique, la liste des modules ne change pas souvent, il n'est donc pas déraisonnable d'éditer un fichier de temps en temps. Je suis sûr que j'ai déjà passé beaucoup plus de temps à chercher une solution qu'il n'en faut pour simplement éditer ce fichier!
Brown du

12

Dans chaque package, le __init__.pyfichier peut avoir des .. automodule:: package.modulecomposants pour chaque partie du package.

Ensuite, vous pouvez .. automodule:: packageet il fait principalement ce que vous voulez.


est-ce que je mets simplement cette chaîne entre guillemets triples dans init .py?
Cory Walker

5
@Cory Walker: Ce n'est pas "une" chaîne. Vous pouvez - et devriez - mettre des docstrings entre guillemets triples dans chaque fichier. Toutes les personnes. Cela inclut les __init__.pyfichiers de vos packages. La docstring peut inclure TOUTES les directives de documentation Sphinx, y compris .. automodule::pour les modules du package.
S.Lott

2
autodocest une faute de frappe, ça devrait être automodule. mais merci beaucoup pour l'indice!
mariotomo

9

À partir de la version 3.1 de Sphinx (juin 2020), sphinx.ext.autosummary(enfin!) A la récursivité.

Donc pas besoin de coder en dur les noms de modules ou de s'appuyer sur des bibliothèques tierces comme Sphinx AutoAPI ou Sphinx AutoPackage pour leur détection automatique des paquets.

Exemple de package Python 3.7 à documenter ( voir le code sur Github et le résultat sur 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(notez la nouvelle :recursive:option):

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

Some words.

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

   mypackage

Cela suffit pour résumer automatiquement chaque module du package, même profondément imbriqué. Pour chaque module, il récapitule ensuite chaque attribut, fonction, classe et exception de ce module.

Curieusement, cependant, les sphinx.ext.autosummarymodèles par défaut ne génèrent pas de pages de documentation séparées pour chaque attribut, fonction, classe et exception, et établissent des liens vers eux à partir des tableaux récapitulatifs. Il est possible d'étendre les modèles pour ce faire, comme indiqué ci-dessous, mais je ne comprends pas pourquoi ce n'est pas le comportement par défaut - c'est sûrement ce que la plupart des gens voudraient ..? Je l'ai soulevé comme une demande de fonctionnalité .

J'ai dû copier les modèles par défaut localement, puis y ajouter:

  • Copier site-packages/sphinx/ext/autosummary/templates/autosummary/module.rstversmytoolbox/doc/source/_templates/custom-module-template.rst
  • Copier site-packages/sphinx/ext/autosummary/templates/autosummary/class.rstversmytoolbox/doc/source/_templates/custom-class-template.rst

Le crochet dans custom-module-template.rstest en index.rstdessus, en utilisant l' :template:option. (Supprimez cette ligne pour voir ce qui se passe en utilisant les modèles de packages de site par défaut.)

custom-module-template.rst (lignes supplémentaires notées à droite):

{{ 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 (lignes supplémentaires notées à droite):

{{ 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 %}


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.