:redirect: blog/crear-documentacion-de-un-proyecto-python-con-sphinx
:date: 2020-01-06
:tags: python, sphinx, documentación, restructuredtext, generador de documentación
:category: tecnología
:author: Edward Villegas-Pulgarin
:language: es
Crear documentación de un proyecto Python con Sphinx
====================================================
Sin duda, una etapa importante en cualquier proyecto de desarrollo (y no solo
de *software*) es la generación de la documentación. En el caso de *software*
es posible asistirse de herramientas que ayudan a automatizar la generación de
la documentación mediante extracción de comentarios en el código, usar palabras
claves y lenguaje de marcado para modificación de estilo en el texto o
inclusión de otros elementos que no sean solo texto plano (imágenes,
ecuaciones, enlaces entre otros).
Algunas herramientas para este fin son `Doxygen `_
(habitual para proyectos en C/C++), `Javadoc
`_
(para Java, pero habitual también en TypeScript), `ESDoc `_
(para Javascript) y por supuesto, Sphinx, para Python.
En esta entrada instalaremos lo necesario para generar nuestra documentación de
un proyecto Python y haremos un pequeño ejemplo.
LaTeX
-----
Si deseamos generar documentación web, este paquete no es necesario, pero para
generar nuestra documentación en PDF es una dependencia obligatoria. La
instalación recomendada dependerá del sistema operativo que se use.
Mac
Puedes usar `MacTex `_ el cual incluye el
compilador TeXLive y editores como TeXShop, y otras dependencias para el
funcionamiento de LaTeX en Mac.
Windows
La opción más cómoda es el compilador `MikTeX `_,
el cual permite de forma predeterminada la descarga automática de paquetes
adicionales en la medida que sean requeridos (instalación *on the fly*).
Es importante que en la configuración no cambies al modo silencioso, pues
esto puede afectar la ejecución posterior en los casos que requieran de
instalación.
Si usas Anaconda, puedes incluirlo desde el canal de *conda-forge*,
:code:`conda install -c conda-forge miktex`.
En la primera forma de instalación requieres instalar Perl, en la segunda,
este viene como dependencia instalada por el gestor de paquetes. También
puedes usar `TeXLive `_ para Windows,
el cual asegura la consistencia en el resultado entre los 3 sistemas
operativos.
Linux
En Linux usaremos TeXLive pero su instalación la haremos directamente del
gestor de paquetes del sistema operativo. En la mayor parte de
distribuciones Linux estará disponible a través del gestor.
En el caso de las distribuciones basadas en Debian (Ubuntu y Linux Mint
entre otras) puedes instalar de la siguiente manera:
.. code::
sudo apt install -y texlive texlive-latex-base texlive-latex-extra \
texlive-lang-spanish latexmk
Sphinx
------
Si usamos Python a través de Anaconda podemos usar el gestor *conda* para la
instalación, así :code:`conda install sphinx`, en caso contrario, podemos usar
el gestor de paquetes *PIP*: :code:`pip install -U Sphinx`.
.. note::
Si deseas una experiencia en Windows similar a Linux, usando el
:code:`Makefile` tradicional y la posibilidad de usar en combinación con
Bash, te recomiendo usar Git Bash, y si es en conjunto con Anaconda puedes
leer mi publicación al respecto, :doc:`/es/blog/2019/usar-anaconda-python-en-git-bash` e
instalar el paquete :code:`make` con Anaconda (:code:`conda install make`) o
instalar `Mingw-w64 `_.
Configuración de Sphinx
-----------------------
Abriremos una consola (si es Windows, debes tener en cuenta que para usar
paquetes de Anaconda debes usar las consolas Anaconda Prompt, Anaconda
PowerShell u otra si la configuraste -como el caso de Git Bash que
mencioné en la sección anterior-) y debemos ubicarnos en el directorio que
destinaremos para la documentación. Es habitual que en la estructura de nuestro
proyecto destinemos un directorio :code:`docs` para este fin.
Ahora ejecutamos :code:`sphinx-quickstart` y respondemos las preguntas que
saldrán. Es necesario tener en cuenta, que si usas Windows debes agregar al
comando la terminación :code:`.exe`, ejemplo :code:`sphinx-quickstart.exe`.
.. code::
> Separate source and build directories (y/n) [n]: y
> Project name: proyecto
> Author name(s): Edward Villegas-Pulgarin
> Project release []: 0.1.0
> Project language [en]: es
Siempre recomiendo separar el directorio del código fuente de la documentación
del directorio de compilados de la misma. Respecto al esquema de versiones me
agrada el `versionamiento semántico `_ que permite al
usuario final intuir un poco más sobre la madurez del proyecto con el número,
pero puedes usar el `esquema basado en fecha de liberación `_.
En el lenguaje se especifica el lenguaje con el código a dos letras
internacional, acorde a los
`soportados por Sphinx `_.
Aunque en la terminal nos indican que podemos continuar con el archivo
:code:`index.rst`, debemos hacer unos pequeños cambios en el archivo
:code:`conf.py` que encontraremos en :code:`docs/source`.
Puedes saber más opciones de configuración en la documentación de Sphinx sobre
`conf.py `_.
Extensiones
~~~~~~~~~~~
Recomiendo incluir la extensión de Autodoc para extraer automáticamente la
documentación de la API, MathJax para el soporte de ecuaciones matemáticas en
la versión Web y Napoleon para el estilo de Numpy y Google en la documentación.
Con Coverage puedes validar que funciones se han documentado y dcotest integra
pruebas de código desde la documentación (comparar salidas con ejemplo de
documentación).
Modificar en el archivo.
.. code::
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.mathjax',
'sphinx.ext.napoleon',
'sphinx.ext.coverage',
'sphinx.ext.doctest'
]
Importar paquete
~~~~~~~~~~~~~~~~
Para apoyarte de ejemplos actualizados automáticamente, uso de metadatos desde
el código (ejemplo, el autor o la versión) puedes importar el paquete en el
archivo de configuración. Dado que estarás en modo de desarrollo probablemente,
el paquete no ha sido instalado y lo deberás hacer descomentando las tres
primeras líneas de código en la sección de *Path setup*. El punto que hay por
defecto indica la misma carpeta de :code:`docs/source`, por lo cual es
necesario reemplazar por :code:`../..` que se devuelve los dos niveles
necesarios.
.. code::
import os
import sys
import datetime
sys.path.insert(0, os.path.abspath('../..'))
import proyecto
Ahora, puedes hacer cosas como la siguiente, si está disponible en tu código.
.. code:: python
author = proyecto.__author__
copyright = str(datetime.date.today().year) + ', ' + author
release = proyecto.__version__
Esto tiene un impacto respecto a algunas dependencias, que pueden provocar
fallos o si para la generación de la documentación no tenemos todas las
dependencias del paquete. En mi caso, he tenido problemas cuando tengo como
dependencia Tensorflow o cuando tengo arcpy pero no tengo la licencia
instalada. En este caso, podemos hacer un falseo (*mock*) de los paquetes:
.. code:: python
autodoc_mock_imports = ["tensorflow", "arcpy"]
Referencias cruzadas
~~~~~~~~~~~~~~~~~~~~
Para usar referencias cruzadas, es decir, numeración de tablas, figuras,
códigos y ecuaciones si poseen pie de objeto, y ser referenciados en el texto
por el número, se requiere configurar lo siguiente.
.. code::
numfig = True
numfig_format = {'figure': 'Fig. %s', 'table': 'Tabla %s',
'code-block': 'Código %s', 'section': 'Sección %s'}
numfig_secnum_depth = 1
math_numfig = True
math_eqref_format = 'Ec. {number}'
Así, es posible usar :code:`:label:` para asignar una referencia a los objetos
y :code:`:numref:` y :code:`:eq:` a la hora de mencionarlos. Con
:code:`numfig_secnum_depth` configuras la numeración de los objetos, si es
continúa (0), por sección (1) y subsección (2).
LaTeX
~~~~~
Hay una configuración básica para LaTeX que puedes agregar. El documento
maestro, el nombre del archivo TeX, el nombre que nuestra documentación, el
nombre del autor (que podemos usar la variable que ya definimos) y el tipo de
documento (cuya clase *manual* está definida por Sphinx).
.. code::
master_doc = 'index'
latex_documents = [
(master_doc, 'proyecto.tex', 'Documentación Proyecto',
author, 'manual'),
]
Escritura en ReStructuredText
-----------------------------
Sobre esto, es referencia ver la documentación de
`DocUtils `_
y de Sphinx `ReStructuredText Primer `_.
Una vez tienes las bases de ReStructuredText puedes editar lo básico. De ahí, y
para tener todo el provecho de Sphinx hay elementos como los roles, directivas
y dominios que debes aprender a usar,
`Sphinx ReStructuredText `_.
¿Y por qué los dominios? Estos añaden sintaxis para manejar las relaciones con
el código, como enlazar a funciones relacionadas que se generaron con *autodoc*
y además la forma de como documentar la función (u otro elemento del código) en
su código fuente y que pueda ser extraída. Por ejemplo, el
`dominio de Python `_.
¿Qué archivos debo editar?
~~~~~~~~~~~~~~~~~~~~~~~~~~
Primero, editaremos :code:`docs/source/index.rst`, donde deberemos agregar los
nombres de los archivos que se incluyen en la documentación, tanto los
generados como los automáticos. Se agrega uno por línea, sin extensión y la
posición es relativa a la ubicación del archivo :code:`index.rst`.
Te recomiendo siempre un archivo :code:`README.rst` que fija la generalidad e
intención del proyecto, :code:`history.rst` para tener documentados los cambios
entre versiones (como un *changelog* pero a mano, más condensado), un
:code:`usage.rst` documentando el uso de nuestro proyecto,
:code:`installation.rst` con instrucciones de instalación y adicional, agregar
una ruta a la documentación de la API (la misma ruta la debemos indicar más
adelante). Puedes agregar más archivos, por ejemplo, yo suelo usar un
:code:`concepts.rst` para detallar los conceptos necesarios antes de usar el
software o detallar teoría que ayuda a interpretar resultados o que expande la
información para que alguien pueda analizar o continuar un desarrollo.
.. code::
.. toctree::
:maxdepth: 3
:caption: Contenido:
README
installation
usage
api/modules
concepts
history
Y podemos borrar las líneas posteriores de *Indices and tables*.
Vemos la mención a :code:`api/modules`, la cual es importante para incluir la
documentación automática extraída con Sphinx, que se explicará en la próxima
sección.
Ejecución de Sphinx
-------------------
Como estamos haciendo uso de *autodoc*, nuestro primer paso es generar la
extracción de la API.
.. code::
sphinx-apidoc -f -M -o source/api/ ../proyecto
Recordar que en Windows hay que agregar :code:`.exe`
(:code:`sphinx-apidoc.exe`). :code:`-f` es para forzar la regeneración de los
archivos (importante si actualizamos la documentación de la API), :code:`-M`
para ubicar primero la documentación de los módulos (por defecto primero son
las funciones, y esto no me parece natural). Luego, es la ruta para la
documentación de la API (uno de los archivos será el :code:`api/modules.rst`)
y finalmente la ruta donde se encuentra el paquete. Ambas rutas son relativas
al directorio de documentación.
Ahora, solo es necesario generar la documentación: :code:`make latexpdf` si es
con el *Makefile* o :code:`make.bat latexpdf` si no instalaste *make* en
Windows. Aquí debemos devolvernos un nivel en la carpeta para ejecutarlo.
Publicar
--------
Ahora encontrarás en la carpeta *build* los archivos LaTeX, y uno de ellos será
el PDF que queremos. También puedes hacer compilación HTML (:code:`make html`)
y usar esta para publicar como un `GitHub Pages `_ o
en `ReadTheDocs `_.