194 votes

Sphinx autodoc n'est pas assez automatique

J'essaie d'utiliser Sphinx pour documenter un projet de plus de 5 000 lignes en Python. Il comporte environ 7 modules de base. Pour autant que je sache, afin d'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 beaucoup de fichiers. Ce serait beaucoup plus facile si je pouvais juste spécifier que je veux que le paquet 'mods' soit documenté. Sphinx pourrait alors parcourir récursivement le paquet et créer une page pour chaque sous-module.

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

143 votes

Personne n'a dit que c'était difficile. L'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.

0 votes

Il suffit d'utiliser pdoc .

155voto

Etienne Points 6176

Vous pouvez vérifier ceci script que j'ai fait. Je pense que ça peut vous aider.

Ce script analyse une arborescence de répertoires à la recherche de modules et de paquets 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.

UPDATE

Ce script fait maintenant partie de Sphinx 1.1 en tant que apidoc .

1 votes

Où devez-vous envoyer les fichiers ? J'ai essayé de les sortir vers le dossier _build par défaut de Sphinx, mais l'exécution de la commande sphinx-build -b html . ./_build ne les ramasse pas.

1 votes

Vous devez 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

1 votes

@Erienne : fantastique script ! juste ce que je cherchais. J'aimerais qu'il génère des en-têtes pour les classes individuelles (l'aspect régulier de sphinx n'est pas agréable pour les classes. elles se perdent dans les modules plus grands).

90voto

James Leedham Points 816

À partir de la version 3.1 de Sphinx (juin 2020), sphinx.ext.autosummary (enfin !) a une récursion automatique.

Il n'est donc pas nécessaire de coder en dur les noms de modules ou de s'appuyer sur des bibliothèques tierces comme Sphinx AutoAPI o Sphinx AutoPackageSummary pour leur détection automatique des paquets.

Exemple de paquetage Python 3.7 à documenter ( voir le code sur Github y 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 (note nouvelle :recursive: option) :

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

Some words.

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

   mypackage

Ceci est suffisant pour résumer automatiquement chaque module du paquet, même s'il est profondément imbriqué. Pour chaque module, il résume ensuite chaque attribut, fonction, classe et exception de ce module.

Curieusement, cependant, la valeur par défaut sphinx.ext.autosummary Les modèles ne génèrent pas de pages de documentation distinctes pour chaque attribut, fonction, classe et exception, et ne créent pas de liens vers ces pages à partir des tableaux récapitulatifs. Il est possible d'étendre les modèles pour faire cela, 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 veulent ? J'en ai fait une demande de fonctionnalité .

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

  • Copie site-packages/sphinx/ext/autosummary/templates/autosummary/module.rst a mytoolbox/doc/source/_templates/custom-module-template.rst
  • Copie site-packages/sphinx/ext/autosummary/templates/autosummary/class.rst a mytoolbox/doc/source/_templates/custom-class-template.rst

Le crochet dans custom-module-template.rst est en index.rst ci-dessus, en utilisant le :template: option. (Supprimez cette ligne pour voir ce qui se passe en utilisant les modèles de paquets de sites 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 %}

50voto

firegurafiku Points 81

Je ne sais pas si Sphinx avait eu autosummary au moment où la question initiale a été posée, mais pour l'instant, il est tout à fait possible de mettre en place une génération automatique de ce type sans utiliser la fonction sphinx-apidoc ou un script similaire. Vous trouverez ci-dessous les paramètres qui fonctionnent pour l'un de mes projets.

  1. Activer autosummary (ainsi que l'extension autodoc ) en conf.py et définir son autosummary_generate option pour True . Cela peut être suffisant si vous n'utilisez pas de fonctions personnalisées. *.rst modèles. Sinon, ajoutez votre répertoire de modèles à la liste des exclusions, ou bien autosummary essaiera de les traiter comme des fichiers d'entrée (ce qui semble être un bug).

    extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary']
    autosummary_generate = True
    templates_path = [ '_templates' ]
    exclude_patterns = ['_build', '_templates']
  2. Utilice autosummary:: dans l'arbre TOC de votre index.rst fichier. Dans cet exemple, la documentation des modules project.module1 y project.module2 sera généré automatiquement et placé dans _autosummary répertoire.

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

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

En conclusion, il n'est pas nécessaire de garder _autosummary sous contrôle de version. De plus, vous pouvez lui donner le nom que vous voulez et le placer n'importe où dans l'arborescence des sources (en le plaçant au-dessous de _build ne fonctionnera pas, cependant).

5 votes

Cela a été d'une grande aide. 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 d'un paquet donné ? Il suffit de mettre "project" et de le faire renifler "module1" et "module2" ?

1 votes

Je suis assez surpris de ne pas trouver de réponse à cette question nulle part, l'avez-vous jamais résolue @Brown ?

3 votes

@AlisdairRobertson Non, mais la solution de résumé automatique fournie a fini par être plus que suffisante 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 autodétecter les noms des modules. Cependant, en pratique, la liste des modules ne change pas si souvent que ça, donc modifier juste un fichier de temps en temps n'est pas si déraisonnable. Je suis sûr que j'ai déjà passé beaucoup plus de temps à chercher une solution qu'il n'en faut pour éditer ce seul fichier !

21voto

Vito Points 313

Sphinx AutoAPI fait exactement cela.

13voto

S.Lott Points 207588

Dans chaque paquet, le __init__.py peut avoir .. automodule:: package.module pour chaque partie du paquet.

Alors vous pouvez .. automodule:: package et il fait la plupart du temps ce que vous voulez.

0 votes

Dois-je simplement mettre cette chaîne entre triple guillemets dans init .py ?

8 votes

@Cory Walker : Ce n'est pas "une" chaîne. Vous pouvez et devrait -- mettre des docstrings à triple guillemets dans chaque fichier. Tous les fichiers. Cela inclut le __init__.py dans vos paquets. La docstring peut inclure TOUTES les directives de documentation de Sphinx, notamment .. automodule:: pour les modules du paquet.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X