Documente automáticamente todos los módulos de forma recursiva con Sphinx autodoc

10 minutos de lectura

Avatar de usuario de Cory Walker
Cory Walker

Estoy tratando de usar Sphinx para documentar un proyecto de más de 5000 líneas en Python. Tiene alrededor de 7 módulos base. Hasta donde yo sé, para usar autodoc necesito escribir un código como este para cada archivo en mi proyecto:

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

Esto es demasiado tedioso porque tengo muchos archivos. Sería mucho más fácil si pudiera especificar que quiero que se documente el paquete ‘mods’. Sphinx podría luego revisar recursivamente el paquete y crear una página para cada submódulo.

¿Hay una característica como esta? Si no, podría escribir un script para hacer todos los archivos .rst, pero eso llevaría mucho tiempo.

  • Nadie dijo que fuera difícil. OP dijo que era tedioso, cual es. Dado que otros sistemas de documentos pueden hacer esto, no es irrazonable.

    – Gregg Lind

    26 de diciembre de 2010 a las 20:22

  • Solo usa pdoc.

    – K3—rnc

    15 de abril de 2020 a las 18:14

Avatar de usuario de Etienne
etienne

Puedes comprobar esto guion que he hecho. Creo que te puede ayudar.

Esta secuencia de comandos analiza un árbol de directorios en busca de módulos y paquetes de python y crea archivos ReST de manera adecuada para crear documentación de código con Sphinx. También crea un índice de módulos.

ACTUALIZAR

Este script ahora es parte de Sphinx 1.1 como apidoc.

  • ¿Dónde se supone que debes enviar los archivos? Intenté enviarlos a la carpeta _build predeterminada de Sphinx, pero al ejecutar sphinx-build -b html . ./_build no los recoge.

    – Cerín

    6 de enero de 2011 a las 18:13

  • Debes ponerlos en el source directory (. en tu caso). El directorio _build es donde se crearán los archivos HTML. Consulte para obtener más información: sphinx.pocoo.org/tutorial.html#running-the-build

    – Étienne

    6 de enero de 2011 a las 20:16

  • @Erienne: guión fantástico! justo lo que estaba buscando. Ojalá generara encabezados para clases individuales (el aspecto normal de esfinge no es agradable para las clases. Se pierden en módulos más grandes)

    – jbenet

    22 de diciembre de 2011 a las 14:40

  • Incluso sphinx-apidoc es bastante rudimentario. Para un paquete con uno o dos módulos, funciona bien, pero tenemos módulos profundamente anidados y sphinx-apidoc produce una salida bastante inmanejable.

    – slacy

    27/04/2012 a las 20:35

  • respuesta automática: añadir .. include:: modules.rst para usted index.rst

    – Ciro Santilli OurBigBook.com

    4 de abril de 2013 a las 13:27

Avatar de usuario de James Leedham
james leedham

Desde Sphinx versión 3.1 (junio de 2020), sphinx.ext.autosummary (¡por fin!) tiene recursividad automática.

Por lo tanto, no es necesario codificar los nombres de los módulos ni depender de bibliotecas de terceros como Sphinx AutoAPI o Sphinx AutoPackageResumen para su detección automática de paquetes nunca más.

Ejemplo de paquete de Python 3.7 para documentar (ver código en Github y resultado en 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 (nota nueva :recursive: opción):

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

Some words.

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

   mypackage

Esto es suficiente para resumir automáticamente todos los módulos del paquete, por muy anidados que estén. Para cada módulo, luego resume cada atributo, función, clase y excepción en ese módulo.

Curiosamente, sin embargo, el valor predeterminado sphinx.ext.autosummary las plantillas no continúan generando páginas de documentación separadas para cada atributo, función, clase y excepción, y se vinculan a ellas desde las tablas de resumen. Es posible extender las plantillas para hacer esto, como se muestra a continuación, pero no puedo entender por qué este no es el comportamiento predeterminado; seguramente eso es lo que la mayoría de la gente querría… Lo he planteado como una solicitud de función..

Tuve que copiar las plantillas predeterminadas localmente y luego agregarlas:

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

el gancho en custom-module-template.rst es en index.rst arriba, usando el :template: opción. (Elimine esa línea para ver qué sucede con las plantillas de paquetes de sitio predeterminadas).

custom-module-template.rst (líneas adicionales anotadas a la derecha):

{{ 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 (líneas adicionales anotadas a la derecha):

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

  • ¡¡¡Muchas gracias por esto!!! Estuve a punto de rendirme y finalmente encontré esto. Una pregunta. yo estaba usando sys.path.insert(0, os.path.abspath('../../mypackage')) pero solo usas '../..'. ¿Por qué no hace la diferencia?

    – Samlaf

    6 de noviembre de 2020 a las 22:48


  • No hay problema, me alegro de que haya ayudado. Sphinx casi me vuelve loco hasta que me di cuenta; ahora todo funciona maravillosamente. En index.rstdebe nombrar explícitamente el paquete donde desea :recursive: extracción de docstring para comenzar, así que en mi ejemplo mypackage. En conf.py, solo proporciona la ruta a esa ubicación. Eso es porque en mi ejemplo mypackage es una carpeta de nivel superior en mytoolboxpero si estaba (p. ej.) anidado en un source/mypackage subcarpeta entonces conf.py leería ../../source.

    – James Leedham

    8 de noviembre de 2020 a las 9:58


  • @jamleed ¡Esto ha sido muy útil!. Gracias por tomarse el tiempo y escribir Sphinx AutoPackageSummary. Me ahorraste mucho tiempo. En ese proyecto de github, la parte make html (make.bat) no estaba disponible, por lo que el comando “make html” no funcionó de inmediato. Es posible que deba agregar algunas instrucciones al respecto o cargar ese archivo también. De lo contrario, funcionó como un encanto. (Editado – incluido el nombre de archivo que falta)

    – SKG

    17 de noviembre de 2020 a las 15:08

  • Esta respuesta vale oro, muchas gracias! Espero que su solicitud de función se implemente. De hecho, debería ser el comportamiento predeterminado.

    – Rickstaa

    24 de febrero de 2021 a las 15:47


  • Solo una pequeña mejora en custom-module-template.rstsi agregas :members: bajo la .. automodule:: {{ fullname }} (línea 3), la documentación para ese módulo se completará automáticamente con miembros (clases, funciones, etc.) además del toctree. Esto brinda a los usuarios la opción de escanear rápidamente la documentación además de identificar funciones utilizando el toctree.

    – FullmetalIngeniero

    11 de marzo de 2021 a las 16:57


avatar de usuario de firegurafiku
firegurafiku

No sé si Sphinx había tenido autosummary extensión en el momento en que se hizo la pregunta original, pero por ahora es muy posible configurar la generación automática de ese tipo sin usar sphinx-apidoc o guión similar. A continuación hay configuraciones que funcionan para uno de mis proyectos.

  1. Permitir autosummary extensión (así como autodoc) en conf.py archivo y establezca su autosummary_generate opción a True. Esto puede ser suficiente si no está usando personalizado *.rst plantillas. De lo contrario, agregue su directorio de plantillas a la lista de exclusión, o autosummary intentará tratarlos como archivos de entrada (lo que parece ser un error).

    extensions = ['sphinx.ext.autodoc', 'sphinx.ext.autosummary']
    autosummary_generate = True
    templates_path = [ '_templates' ]
    exclude_patterns = ['_build', '_templates']
    
  2. Usar autosummary:: en el árbol TOC en su index.rst archivo. En este ejemplo de documentación para módulos project.module1 y project.module2 se generará automáticamente y se colocará en _autosummary directorio.

    PROJECT
    =======
    
    .. toctree::
    
    .. autosummary::
       :toctree: _autosummary
    
       project.module1
       project.module2
    
  3. Por defecto autosummary generará solo resúmenes muy cortos para los módulos y sus funciones. Para cambiar eso, puede poner un archivo de plantilla personalizado en _templates/autosummary/module.rst (que se analizará con Jinja2):

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

En conclusión, no hay necesidad de mantener _autosummary directorio bajo control de versiones. Además, puede ponerle el nombre que desee y colocarlo en cualquier lugar del árbol de fuentes (colocándolo debajo _build aunque no funcionará).

  • Esto fue de gran ayuda. En el punto 2, donde tiene “project.module1” y “project.module2”, ¿hay alguna forma de generar automáticamente esa lista para cada módulo en un paquete determinado? ¿Simplemente poner “proyecto” y hacer que detecte “módulo1” y “módulo2”?

    – Marrón

    22 de junio de 2017 a las 21:24

  • Bastante sorprendido de que no pueda encontrar una respuesta a esto en ninguna parte, ¿alguna vez lo resolviste @Brown?

    – Alisdair Robertson

    9 de septiembre de 2017 a las 9:18

  • @AlisdairRobertson No, pero la solución de resumen automático provista terminó siendo más que adecuada para mis necesidades. Lo único que pensé en hacer fue escribir un script para generar el archivo index.rst y detectar automáticamente los nombres de los módulos. Sin embargo, en la práctica, la lista de módulos no cambia con tanta frecuencia, por lo que editar un archivo de vez en cuando no es tan descabellado. ¡Estoy seguro de que ya pasé mucho más tiempo buscando una solución de lo que se necesita para editar ese archivo!

    – Marrón

    13 de septiembre de 2017 a las 13:49

  • ¿No hay otros pasos para esto? Actualizar a esto sigue siendo solo hacer el directorio actual y no recursivo. También veo: ADVERTENCIA: Error en la directiva “autosummary”: opción desconocida: “recursiva”. El directorio actual solo está hecho en html.

    – lexalenka

    1 de septiembre de 2021 a las 17:58

Sphinx AutoAPI hace exactamente esto.

Avatar de usuario de S. Lott
S. Lott

En cada paquete, el __init__.py archivo puede tener .. automodule:: package.module componentes para cada parte del paquete.

Entonces tú puedes .. automodule:: package y sobre todo hace lo que quieres.

  • ¿Acabo de poner esa cadena entre comillas triples en en eso.py?

    –Cory Walker

    23 de abril de 2010 a las 21:36

  • @Cory Walker: No es una cadena “a”. Puedes – y debería — estar poniendo cadenas de documentos entre comillas triples en cada archivo. Todos. Eso incluye el __init__.py archivos en sus paquetes. La cadena de documentación puede incluir CUALQUIER directiva de documentación de Sphinx, incluidas .. automodule:: para módulos dentro del paquete.

    – S. Lott

    24 de abril de 2010 a las 22:35

Avatar de usuario de Edward Dale
eduardo valle

Tal vez lo que estás buscando es Epydoc y esto Extensión de esfinge.

  • ¿Acabo de poner esa cadena entre comillas triples en en eso.py?

    –Cory Walker

    23 de abril de 2010 a las 21:36

  • @Cory Walker: No es una cadena “a”. Puedes – y debería — estar poniendo cadenas de documentos entre comillas triples en cada archivo. Todos. Eso incluye el __init__.py archivos en sus paquetes. La cadena de documentación puede incluir CUALQUIER directiva de documentación de Sphinx, incluidas .. automodule:: para módulos dentro del paquete.

    – S. Lott

    24 de abril de 2010 a las 22:35

¿Ha sido útil esta solución?