Documentación
Herramientas y convenciones para documentar proyectos Python con rigor
Sobre documentación en Python
La documentación de un proyecto Python serio se sostiene sobre tres decisiones casi ortogonales: qué generador produce el sitio, qué convención de docstring se sigue dentro del código y qué tema y hosting lo presentan. Confundirlas lleva a configuraciones frágiles que mezclan plantillas, plugins y autodoc de tres ecosistemas a la vez.
El paisaje real se reduce a tres grandes opciones:
- Sphinx es el estándar histórico y sigue siendo gold standard para librerías serias (NumPy, SciPy, scikit-learn, pandas, todo el ecosistema científico, CPython). Está pensado para documentar APIs:
autodocintrospecta el código,sphinx.ext.napoleonentiende docstrings NumPy/Google,intersphinxenlaza cruzadamente con la documentación de otras librerías. La fricción está en el lenguaje fuente (reStructuredText), que MyST mitiga aportando un dialecto de Markdown con todas las directivas de Sphinx. - MkDocs + mkdocs-material es la opción pragmática moderna para documentación de proyecto (guías, tutoriales, manuales de usuario): Markdown puro, build instantáneo, tema cuidado, search cliente listo. Para APIs Python,
mkdocstringscubre el hueco de autodoc con calidad razonable. Es lo que usan FastAPI, Pydantic, Typer y la mayoría de proyectos jóvenes orientados a aplicación. - pdoc es la opción minimalista: cero configuración, genera HTML directamente desde el código y los docstrings. Apropiado para librerías pequeñas o internas donde montar Sphinx es desproporcionado.
Sobre la convención de docstring, PEP 257 define la norma básica (qué es un docstring y cómo se formatea), pero deja libre la estructura interna. En la práctica dominan dos estilos: NumPy (el del ecosistema científico, secciones marcadas con guiones) y Google (más compacto, secciones con : final). Ambos los entiende napoleon en Sphinx y mkdocstrings con su handler de Python. El estilo nativo de reStructuredText (:param x:) es legible solo dentro de Sphinx y conviene evitarlo en proyectos nuevos.
Esta página cataloga las piezas en orden de jerarquía: primero los generadores (Sphinx, MkDocs, pdoc), después los temas y el hosting (mkdocs-material, Read the Docs), y por último las convenciones de docstring (NumPy, Google) con sus mecanismos de integración (autodoc, napoleon, doctest).
Sphinx
Sphinx es el generador de documentación canónico del ecosistema Python. Nació para documentar la propia CPython y se ha consolidado como estándar de facto en cualquier librería con pretensión de seriedad: NumPy, SciPy, scikit-learn, pandas, matplotlib, todo el stack científico, la Python Standard Library. Produce HTML, PDF (vía LaTeX), ePub y man pages desde una única fuente.
Su valor real no está en “generar HTML desde texto” sino en su ecosistema de extensiones maduras: autodoc introspecta módulos y extrae signaturas y docstrings. intersphinx resuelve referencias cruzadas entre proyectos (un enlace a numpy.ndarray apunta automáticamente a la documentación oficial de NumPy). doctest ejecuta los ejemplos embebidos en los docstrings. autosummary genera índices de API. viewcode enlaza cada símbolo documentado a su fuente.
Cuándo usarlo
- Librerías Python que se distribuyen públicamente (PyPI, conda-forge) y que necesitan referencia exhaustiva de API.
- Proyectos donde la documentación contiene referencias cruzadas a otras librerías (
intersphinx). - Cuando se necesita PDF de calidad tipográfica (LaTeX) además de HTML, informes técnicos, libros, theses.
- Proyectos que ya viven en el ecosistema científico Python (NumPy, SciPy, pandas) y se benefician de seguir la convención mayoritaria.
Cuándo NO usarlo
- Documentación de proyecto orientada a aplicación (tutoriales, user guide, getting started):
MkDocs + mkdocs-materialda mejor experiencia con mucho menos esfuerzo. - Librerías pequeñas o internas sin necesidad de API exhaustiva:
pdocresuelve el problema en minutos sinconf.py. - Equipos sin experiencia previa en RST/Sphinx que no van a invertir tiempo en aprender la herramienta, el coste de configuración inicial es real.
Conceptos clave
conf.pyes el corazón del proyecto: lista de extensiones, tema, opciones deautodoc, rutas deintersphinx_mapping, configuración del output.- reStructuredText (
.rst) es el lenguaje fuente nativo. Más expresivo que Markdown pero con curva de aprendizaje. La alternativa moderna es MyST (ver más abajo): Markdown + directivas Sphinx. - Directivas: bloques con sintaxis
.. directive:: argque generan HTML/PDF estructurado (admoniciones, código, figuras, tablas, índices, toctree). toctreedefine la jerarquía de navegación del sitio. No es opcional: si una página no aparece en algúntoctree, Sphinx la marca como huérfana.autodoc+napoleones la combinación estándar:autodocintrospecta el código,napoleontraduce docstrings NumPy/Google a RST antes de procesarlos.intersphinx_mappingpermite enlaces tipo:class:numpy.ndarray`` que resuelven contra la documentación remota de NumPy.
Patrón mínimo
pip install sphinx furo # furo es un tema moderno popular
sphinx-quickstart docs # interactivo, genera estructura base# docs/conf.py
project = "mi_proyecto"
author = "Autora del Proyecto"
extensions = [
"sphinx.ext.autodoc", # introspección de módulos
"sphinx.ext.napoleon", # docstrings NumPy/Google
"sphinx.ext.intersphinx", # enlaces cruzados a otras docs
"sphinx.ext.viewcode", # enlace al código fuente
"sphinx.ext.doctest", # ejecutar ejemplos de docstrings
]
html_theme = "furo"
intersphinx_mapping = {
"python": ("https://docs.python.org/3", None),
"numpy": ("https://numpy.org/doc/stable/", None),
"pandas": ("https://pandas.pydata.org/docs/", None),
}
napoleon_google_docstring = False # usar NumPy style en este proyecto
napoleon_numpy_docstring = Truesphinx-build -b html docs docs/_build/html # build local
sphinx-build -b doctest docs docs/_build # ejecutar doctestsTrampas habituales
- Ruta a los módulos.
autodocnecesita poder importar el código. Si los fuentes viven ensrc/mi_proyecto/, añadesys.path.insert(0, os.path.abspath("../src"))al inicio deconf.py, o (mejor) instala el proyecto en editable mode (pip install -e .) antes de buildear. - Mezclar estilos de docstring. Si activas
napoleon_google_docstring = Trueynapoleon_numpy_docstring = True, la heurística falla en docstrings ambiguos. Decide un estilo por proyecto y desactiva el otro. toctreecon:maxdepth:mal puesto. Un:maxdepth: 1muestra solo el título. Un:maxdepth: 4infla el índice. Para sitios grandes, usa variostoctreepor sección en vez de uno único profundo.- Versionado de la documentación. Sphinx no lo gestiona. Lo resuelven
sphinx-multiversion,Read the Docs(build por tag/branch) omike(más típico en MkDocs).
Enlaces
Relacionados en esta página
MyST, escribir Sphinx en Markdown.mkdocsypdoc, alternativas para nichos distintos.autodoc + napoleon, combinación canónica para introspección.Read the Docs, hosting natural de Sphinx.
MkDocs
MkDocs es un generador de sitios estáticos pensado desde el principio para documentación de proyecto en Markdown. Su modelo mental es radicalmente más simple que Sphinx: una carpeta docs/ con ficheros .md, un mkdocs.yml que define la navegación, y mkdocs serve que recarga en caliente al editar.
No compite directamente con Sphinx, son herramientas con objetivos distintos. MkDocs gana cuando la documentación es prosa (tutoriales, manuales, user guide). Sphinx gana cuando es referencia de API exhaustiva con intersphinx, doctests y PDF tipográfico. Para librerías Python modernas orientadas a aplicación (FastAPI, Pydantic, Typer, HTTPX) el patrón habitual es MkDocs + mkdocs-material + mkdocstrings.
Cuándo usarlo
- Documentación orientada a prosa: tutoriales, getting started, guías de uso, ADRs, playbooks internos.
- Proyectos donde el equipo escribe Markdown habitualmente y se quiere mantener una única convención.
- Librerías pequeñas o medianas donde
mkdocstringscubre la API y no se necesita PDF, intersphinx o doctest exhaustivo. - Sitios internos de equipo / engineering handbooks.
Cuándo NO usarlo
- Librerías científicas con cientos de funciones, intersphinx contra el resto del ecosistema Python y exigencia de PDF, Sphinx es notablemente más maduro para este nicho.
- Cuando se necesita doctest ejecutado en CI sobre los ejemplos del docstring: el soporte en MkDocs es marginal frente a
sphinx.ext.doctest. - Proyectos donde la documentación ya está en RST y migrarla a Markdown no aporta valor neto.
Conceptos clave
mkdocs.ymles el único fichero de configuración. Definenav(navegación explícita),theme,plugins,markdown_extensions.naves jerárquica y explícita. No hay equivalente directo altoctreeautomático de Sphinx (aunqueawesome-navlo aproxima).- Plugins clave:
mkdocstrings(autodoc Python),search(incluido),mike(versionado),git-revision-date-localized(timestamps por commit). markdown_extensionsactiva sintaxis enriquecida del paquetepymdown-extensions: admoniciones, tabs, details, código con resaltado, footnotes.mkdocs servesirve con live reload, la iteración local es prácticamente instantánea.
Patrón mínimo
pip install mkdocs mkdocs-material mkdocstrings[python]
mkdocs new mi_proyecto
cd mi_proyecto# mkdocs.yml
site_name: Mi Proyecto
site_url: https://docs.mi-proyecto.example/
theme:
name: material
features:
- navigation.instant
- navigation.tabs
- content.code.copy
plugins:
- search
- mkdocstrings:
handlers:
python:
options:
docstring_style: numpy
show_source: true
markdown_extensions:
- admonition
- pymdownx.details
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
nav:
- Inicio: index.md
- Tutorial: tutorial.md
- Referencia API: api.md<!-- docs/api.md -->
# Referencia
::: mi_proyecto.modulo.funcion
options:
show_signature_annotations: truemkdocs serve # http://127.0.0.1:8000 con live reload
mkdocs build # site/ con HTML estáticoTrampas habituales
navmanual. A diferencia de Sphinx, MkDocs no genera navegación automática a partir de los ficheros. Si la añades a mano, recuerda actualizarnavcada vez que renombres o muevas un.md.awesome-pagesoawesome-navautomatizan esto.mkdocstringsnecesita importar el código. Si el paquete no está instalado en el entorno donde corremkdocs build, la API aparecerá vacía. Instala el proyecto en editable mode (pip install -e .) en CI antes del build.- No es Sphinx. No esperes
intersphinx,doctesto salida LaTeX. Si los necesitas, vuelve a Sphinx (o combina ambos en proyectos grandes, práctica poco común pero viable). - Markdown ≠ MyST. El Markdown de MkDocs es CommonMark +
pymdown-extensions, no MyST. Las directivas que funcionan en uno no funcionan en el otro.
Enlaces
Relacionados en esta página
mkdocs-material, el tema dominante.Sphinx, la alternativa para librerías serias.pdoc, alternativa minimalista.
mkdocs-material
mkdocs-material es el tema de MkDocs en cualquier proyecto serio escrito hoy. Va mucho más allá de una hoja de estilos: añade búsqueda cliente con resaltado, modo claro/oscuro, navegación instantánea (SPA), tabs anidados, anclas con copia automática, soporte de iconos completo, y un conjunto extenso de features: que se activan por flag.
Mantenido por Martin Donath (squidfunk), con un modelo Insiders (sponsor-only) para features puntuales que terminan migrando a la versión pública tras un periodo. La versión pública es totalmente suficiente para 99% de proyectos.
Cuándo usarlo
- Cualquier proyecto que use MkDocs y quiera un sitio visualmente cuidado sin invertir tiempo en CSS.
- Cuando se necesitan features de UX modernas, instant navigation, dark mode, back-to-top, anchor tracking, tooltips.
- Documentación que sirve también como landing / brand surface del proyecto.
Cuándo NO usarlo
- Proyecto en Sphinx,
mkdocs-materialno funciona ahí. Para Sphinx, los temas equivalentes en calidad son Furo, PyData Sphinx Theme o Sphinx Book Theme. - Sitios con restricciones de tamaño extremas (embedded docs):
mkdocs-materialcarga assets propios. Un tema más ligero (readthedocsclásico,mkdocsbase) puede ser preferible. - Estilo corporativo que rompe completamente con la paleta y tipografía del tema, forkear y mantener es más realista que reescribir.
Conceptos clave
theme.features:es la palanca principal.navigation.instantactiva carga SPA.navigation.tabsañade tabs superiores.content.code.copyañade botón de copia.search.suggestactiva autocomplete.content.tabs.linksincroniza tabs entre páginas.theme.palette:define el esquema de colores. Soportascheme: slate(oscuro) ydefault(claro) contoggle:para conmutar.theme.icon:ytheme.logo:configuran iconografía. Soporta los sets de Material, FontAwesome, Octicons y SimpleIcons sin instalación adicional.extra.social:añade iconos enlazados a redes/repos en el footer.extra_css:/extra_javascript:permiten overrides puntuales sin forkear el tema.
Patrón mínimo
theme:
name: material
palette:
- media: "(prefers-color-scheme: light)"
scheme: default
primary: indigo
toggle:
icon: material/weather-night
name: Cambiar a modo oscuro
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: indigo
toggle:
icon: material/weather-sunny
name: Cambiar a modo claro
features:
- navigation.instant
- navigation.tabs
- navigation.sections
- navigation.expand
- navigation.top
- search.suggest
- search.highlight
- content.code.copy
- content.code.annotate
extra:
social:
- icon: fontawesome/brands/github
link: https://github.com/org/proyectoTrampas habituales
- Mezclar features que se contradicen.
navigation.expand(todo expandido) ynavigation.sections(secciones plegables) interactúan. Algunas combinaciones rompen la usabilidad en sites grandes. Prueba en local antes de fijar la combinación. - Versionar el tema. El changelog del tema es activo. Un upgrade mayor puede cambiar la apariencia. Fija la versión en
requirements.txtopyproject.tomly haz upgrades deliberados. navigation.instantrompe scripts que asumen carga completa de página. Si embebes widgets de terceros (analytics custom, comments), valida que disparen tras la navegación SPA, no solo enDOMContentLoaded.- Iconos no encontrados. El nombre del icono es sensible a casing y namespace (
material/...,fontawesome/brands/...). Consulta el buscador oficial de iconos antes de inventar nombres.
Enlaces
Relacionados en esta página
MkDocs, el generador sobre el que se monta.Read the Docs, alternativa de hosting con su propio tema clásico (más austero).
pdoc
pdoc es el generador minimalista del ecosistema. Sin conf.py, sin toctree, sin extensiones que configurar: apunta a un módulo, introspecta su árbol, lee los docstrings y produce HTML navegable. Una sola línea de comando.
No compite con Sphinx ni con MkDocs en proyectos grandes, su nicho es librerías pequeñas, paquetes internos, prototipos donde montar Sphinx es desproporcionado y la documentación es principalmente referencia API.
Cuidado con la confusión histórica: existen dos proyectos con nombres casi idénticos: pdoc (mantenido, mhils/pdoc) y pdoc3 (fork antiguo, menos mantenido). En proyectos nuevos, usa pdoc (sin el 3).
Cuándo usarlo
- Paquetes internos sin tiempo o presupuesto para Sphinx.
- Prototipos y librerías pequeñas donde la API cabe en una página.
- Cuando los docstrings ya están bien escritos y solo falta servirlos como HTML.
- Documentación generada on the fly en CI sin pipeline complicado.
Cuándo NO usarlo
- Librerías públicas serias: la falta de extensibilidad (no
intersphinx, no temas avanzados, no doctest formal) se nota rápido. - Documentación narrativa (tutoriales, guías):
pdocsolo cubre la API. El contenido tipo manual no encaja. - Proyectos con necesidad de versionado, changelog integrado, PDF, Sphinx + Read the Docs es lo que toca.
Conceptos clave
- Cero configuración por defecto. Funciona con un solo comando contra un módulo importable.
- Soporta NumPy, Google y reStructuredText docstrings, con conversor interno. No necesita
napoleon. - Modo
--httplevanta un servidor con live reload. Modo build estático vuelca HTML a un directorio. - Templates personalizables vía Jinja2, para branding puntual sin forkear.
- Renderiza type hints (PEP 484) automáticamente en las signaturas.
Patrón mínimo
pip install pdoc
# Servidor local con live reload
pdoc mi_proyecto
# Build estático
pdoc -o docs/ mi_proyecto
# Múltiples módulos
pdoc -o docs/ mi_proyecto otro_proyecto# src/mi_proyecto/calculo.py
def media_movil(serie, ventana):
"""Calcula la media móvil de una serie.
Parameters
----------
serie : array_like
Serie temporal de entrada.
ventana : int
Número de elementos por ventana.
Returns
-------
numpy.ndarray
Serie suavizada con la media móvil aplicada.
Examples
--------
>>> media_movil([1, 2, 3, 4], 2)
array([1.5, 2.5, 3.5])
"""
...Trampas habituales
pdocvspdoc3. No son intercambiables. La salida HTML, los flags y los templates difieren. En proyectos nuevos, usapdoc(mhils/pdoc).- Necesita importar el código. Si el módulo tiene
importpesados o efectos secundarios al cargarse (conexiones, descargas), el build se vuelve lento o frágil. Considera lazy imports oif TYPE_CHECKING:para dependencias opcionales. - No hay
intersphinx. Los enlaces a librerías externas son texto plano. Si te importa el enlace cruzado, estás eligiendo la herramienta equivocada. - Versionado de docs. No incluido. Para múltiples versiones, gestiona los directorios manualmente o cambia a Sphinx/MkDocs + Read the Docs/mike.
Enlaces
Relacionados en esta página
Sphinx, alternativa rica para librerías serias.MkDocs, alternativa con prosa + API víamkdocstrings.
Read the Docs
Read the Docs (RTD) es el hosting estándar de la documentación open-source en Python. Cumple tres funciones: build automatizado al hacer push (webhook contra el repo), hosting estático con CDN, y versionado por tag y branch (stable, latest, v1.2.3…) servidos en URLs canónicas.
No es solo un static hosting, es un build farm. Cada push dispara un build aislado en un contenedor que instala dependencias del requirements.txt o environment.yml, ejecuta sphinx-build (o mkdocs build), y publica el resultado. Es el motivo por el que casi toda la ciencia Python documentada en Sphinx vive en RTD.
Cuándo usarlo
- Librería open-source en GitHub/GitLab que quiere docs con versionado por tag y URLs estables (
https://proyecto.readthedocs.io/en/latest/). - Proyectos en Sphinx que necesitan PDF y ePub generados automáticamente, RTD los produce en cada build sin configuración adicional.
- Cuando se necesita selector de versiones automático en el sidebar (típico de proyectos científicos:
v2.1,v2.0,v1.x,stable).
Cuándo NO usarlo
- Documentación interna / privada sin necesidad de hosting público, usa GitHub Pages, GitLab Pages, Netlify, Vercel o un bucket S3 + CloudFront. RTD tiene plan Business (
readthedocs.com) para privado pero suele ser desproporcionado. - Sitios con branding corporativo fuerte que rompe los moldes de RTD, el control de plantilla es limitado en el plan gratuito.
- Cuando el build necesita herramientas pesadas (cómputo, GPU, datos externos a la imagen): los runners gratuitos tienen límites de tiempo y RAM.
Conceptos clave
.readthedocs.yamles el fichero de configuración. Vive en la raíz del repo. Define la versión de Python, el sistema de build (sphinx/mkdocs), el path del config y los formatos de output (htmlzip,pdf,epub).- Versionado: cada tag git produce una versión navegable.
latestapunta almainystableal último tag estable. htmlzip,pdf,epubse generan automáticamente desde Sphinx en cada build.pre_build:/post_build:hooks permiten ejecutar comandos arbitrarios antes/después del build (descargar datos, generar diagramas, etc.).- El equivalente moderno en MkDocs para versioning sin RTD es
mike.
Patrón mínimo
# .readthedocs.yaml (en la raíz del repo)
version: 2
build:
os: ubuntu-22.04
tools:
python: "3.12"
sphinx:
configuration: docs/conf.py
fail_on_warning: true # falla el build ante warnings de Sphinx
python:
install:
- method: pip
path: .
extra_requirements:
- docs
formats:
- htmlzip
- pdf
- epub# pyproject.toml — extra "docs" con dependencias de la documentación
[project.optional-dependencies]
docs = [
"sphinx >=7",
"furo",
"myst-parser",
"sphinx-copybutton",
]Trampas habituales
- Confundir
readthedocs.org(open-source, gratis) conreadthedocs.com(Business, privado, de pago). Las URLs y las cuentas son distintas. El flag--site readthedocs.comaparece en algunas configuraciones. - No instalar el paquete. Sin
python.install: { method: pip, path: . },autodocno puede importar el código y la API sale vacía. Es el bug número uno de RTD. - Versiones colgando. RTD construye cada tag automáticamente. Si tienes 200 tags antiguos rotos, el dashboard se llena de builds fallidos. Marca como inactive las versiones que no quieres mantener.
- Tiempo de build límite. Los builds tienen timeout (típicamente 15-30 min en cuenta gratuita). Si el
pip installo la generación de docs los excede, el build falla en silencio.
Enlaces
Relacionados en esta página
Sphinx, el generador habitual servido por RTD.MkDocs, también soportado. Alternativa de versionado autohospedado esmike.
Docstrings (PEP 257)
Un docstring es la primera cadena literal de un módulo, clase o función. PEP 257 (Docstring Conventions) define la norma general: triple comilla doble, primera línea como resumen imperativo terminado en punto, línea en blanco, descripción extendida, y cierre alineado.
PEP 257 deja deliberadamente abierta la estructura interna de la descripción extendida, qué secciones (Parameters, Returns, Raises, Examples), qué formato. Esa decisión la resuelven las convenciones de comunidad: NumPy y Google dominan. El estilo nativo RST (:param x:) es más legible solo dentro de Sphinx.
Cuándo usarlo
- Siempre. Es la primera y más importante capa de documentación de cualquier código Python.
- Tanto en librerías públicas como en código interno, un docstring no es más cuestión que un comentario, pero estructurado y accesible vía
help(), IDEs y autodoc.
Cuándo NO usarlo
- No hay cuándo no. La ausencia de docstrings es una decisión por omisión, no una alternativa válida.
- Hay sí debate sobre profundidad: docstrings detallados en API pública vs. una línea en helpers internos triviales. La regla práctica: si la firma no es obvia, hace falta docstring.
Conceptos clave
__doc__es el atributo donde Python guarda el docstring.help(obj), los IDEs y las herramientas de doc lo leen de ahí.- Primera línea: resumen en una frase, en imperativo (
"Calcula la media...", no"Calcula la media..."ni"Esta función calcula..."). - Línea en blanco obligatoria entre resumen y cuerpo extendido, todas las convenciones la asumen.
- Las convenciones de estructura (qué secciones, qué orden) las imponen NumPy/Google, no PEP 257.
- Type hints (PEP 484) en la signatura complementan los docstrings. No los sustituyen, el tipo es la firma. La semántica va en el docstring.
Patrón mínimo
def normaliza(serie, metodo="zscore"):
"""Normaliza una serie numérica con el método indicado.
El comportamiento exacto depende del método: "zscore" centra y escala
por desviación típica; "minmax" reescala al rango [0, 1].
Parameters
----------
serie : array_like
Serie numérica de entrada (1D).
metodo : {"zscore", "minmax"}, optional
Método de normalización. Por defecto "zscore".
Returns
-------
numpy.ndarray
Serie normalizada con la misma longitud que la entrada.
Raises
------
ValueError
Si `metodo` no es uno de los soportados.
"""
...Trampas habituales
- Mezclar convenciones. NumPy, Google y RST nativo son incompatibles a nivel de formato. Decide una por proyecto y aplícala con
pydocstyleoruff(reglaD...). - Docstring vs comentario. Un
# comentariono es accesible vía__doc__. Si la información sirve a quien usa la función, va en el docstring. Si es para quien lee el código por dentro, va en comentario. - Resumen como descripción. El resumen es UNA frase. Toda explicación adicional va después del salto de línea en blanco.
- No documentar
Raises. Las excepciones que la función lanza son parte de su contrato. Documentarlas evita sorpresas en el llamante.
Enlaces
- PEP 257, Docstring Conventions
- PEP 484, Type Hints
pydocstyle, linter de estilo de docstring.
Relacionados en esta página
NumPy styleyGoogle style, las dos convenciones dominantes.autodoc + napoleon, herramientas que consumen estos docstrings.
NumPy style
El estilo NumPy es la convención dominante en el ecosistema científico Python: NumPy, SciPy, scikit-learn, pandas, matplotlib, astropy. Estructura el docstring en secciones nombradas seguidas de una línea de guiones (Parameters\n----------), con cada parámetro descrito en un bloque “nombre : tipo / descripción indentada”.
Tiene una desventaja clara, es más verboso que Google style, y dos ventajas reales: legibilidad como texto plano (las secciones con guiones se leen bien en la terminal con help()) y adopción masiva en el ecosistema científico, lo que reduce fricción para usuarios de pandas/NumPy/SciPy que ya están entrenados a leerlo.
Cuándo usarlo
- Librerías que viven en el ecosistema científico (NumPy, SciPy, pandas, sklearn): el usuario espera ese formato.
- Cuando el docstring contiene muchos parámetros con tipos complejos, el estilo NumPy se mantiene legible mejor que Google con muchas entradas.
- Equipos ya entrenados en NumPy/SciPy/sklearn.
Cuándo NO usarlo
- Librerías orientadas a aplicación / framework (FastAPI, Pydantic, Typer) donde Google style es más habitual y más compacto.
- Docstrings cortos con uno o dos parámetros, Google style ahorra espacio sin perder claridad.
- Si el equipo ya tiene una convención Google establecida, no la cambies por capricho, la mezcla es peor que cualquiera de las dos.
Conceptos clave
- Las secciones canónicas son:
Parameters,Returns,Yields,Raises,Warns,See Also,Notes,References,Examples. - Cada sección lleva línea de guiones del mismo ancho que el título.
- Formato de parámetro:
nombre : tipo(con espacio antes y después de:), seguido de la descripción indentada. - Tipos opcionales: se anotan con
, optionalal final del tipo. See Alsoadmite referencias cruzadas (numpy.ndarray,scipy.signal.lfilter) queintersphinxresuelve automáticamente.Examplesadmite doctest ejecutable sisphinx.ext.doctestestá activo.
Patrón mínimo
def ajusta_modelo(X, y, *, alpha=1.0, max_iter=1000):
"""Ajusta un modelo de regresión Ridge a los datos.
Resuelve el problema de mínimos cuadrados regularizado con penalización L2.
Implementación basada en `scipy.linalg.lstsq` con regularización añadida.
Parameters
----------
X : ndarray of shape (n_samples, n_features)
Matriz de diseño.
y : ndarray of shape (n_samples,)
Vector de respuesta.
alpha : float, optional
Fuerza de la regularización. Mayor valor implica más shrinkage.
Por defecto 1.0.
max_iter : int, optional
Iteraciones máximas del solver. Por defecto 1000.
Returns
-------
coef : ndarray of shape (n_features,)
Coeficientes ajustados.
intercept : float
Término independiente.
Raises
------
ValueError
Si `X` e `y` no tienen el mismo número de filas.
See Also
--------
sklearn.linear_model.Ridge : Implementación de referencia en scikit-learn.
Examples
--------
>>> import numpy as np
>>> X = np.array([[1, 0], [0, 1], [1, 1]])
>>> y = np.array([1.0, 1.0, 2.0])
>>> coef, intercept = ajusta_modelo(X, y, alpha=0.5)
"""
...Trampas habituales
- Indentación inconsistente. La descripción de cada parámetro va indentada 4 espacios bajo la línea
nombre : tipo. Mezclar 2 y 4 espacios rompe el parsing denapoleon. - Ancho de los guiones. Debe coincidir con el ancho del título (
Parameters→ 10 guiones). Si no coinciden, algunos parsers lo aceptan y otros no, no merece la pena el riesgo. Returnsmal estructurado. Si la función devuelve una tupla, hay dos patrones válidos: declarar dos entradas separadas (recomendado) o una sola entrada de tipotuple. Lo que no funciona bien es mezclar prosa con la sintaxis nombre/tipo.Examplesque no son doctests. Si la secciónExamplescontiene>>>, Sphinx condoctestlos ejecutará. Si no quieres que se ejecuten (porque tienen efectos secundarios), usa código sin prompts o marca con# doctest: +SKIP.
Enlaces
Relacionados en esta página
Google style, la alternativa más compacta.autodoc + napoleon, Napoleon parsea NumPy style.doctest, ejecuta los ejemplos.
Google style
El estilo Google estructura el docstring con secciones nombradas seguidas de dos puntos (Args:, Returns:, Raises:) y entradas indentadas. Más compacto que NumPy style. Cada parámetro es una línea (nombre (tipo): descripción) en vez de bloque de dos.
Dominante en el ecosistema TensorFlow, Google Cloud SDKs, parte importante de FastAPI/Pydantic y la mayoría de librerías de aplicación modernas. La elección entre Google y NumPy es en gran medida cuestión de ecosistema: si te lees código científico, encajarás NumPy. Si te lees frameworks web/cloud, encajarás Google.
Cuándo usarlo
- Librerías y aplicaciones donde el público objetivo ya viene del mundo de Google Cloud, TensorFlow, FastAPI.
- Proyectos donde la brevedad importa, Google style ocupa menos vertical que NumPy.
- Docstrings cortos con pocos parámetros.
Cuándo NO usarlo
- Si tu librería se integra estrechamente con NumPy/SciPy/sklearn y se espera que los usuarios la lean en el mismo flujo que la documentación de NumPy, la coherencia visual con NumPy style importa.
- En proyectos que ya tienen NumPy style establecido. Mezclar es peor.
Conceptos clave
- Secciones canónicas:
Args:,Returns:,Yields:,Raises:,Attributes:,Note:,Example:/Examples:. - Cada entrada en
Args:es una línea:nombre (tipo): descripción.(el tipo va entre paréntesis). - Más compacto: una función con 5 parámetros ocupa típicamente la mitad de líneas que con NumPy style.
napoleontambién lo parsea si activasnapoleon_google_docstring = True.
Patrón mínimo
def ajusta_modelo(X, y, *, alpha=1.0, max_iter=1000):
"""Ajusta un modelo de regresión Ridge a los datos.
Resuelve el problema de mínimos cuadrados regularizado con penalización L2.
Args:
X (ndarray): Matriz de diseño de shape (n_samples, n_features).
y (ndarray): Vector de respuesta de shape (n_samples,).
alpha (float): Fuerza de la regularización. Mayor valor implica más
shrinkage. Por defecto 1.0.
max_iter (int): Iteraciones máximas del solver. Por defecto 1000.
Returns:
tuple[ndarray, float]: Coeficientes ajustados y término independiente.
Raises:
ValueError: Si `X` e `y` no tienen el mismo número de filas.
Example:
>>> coef, intercept = ajusta_modelo(X, y, alpha=0.5)
"""
...Trampas habituales
Args:vsArguments:. Ambos son aceptados pornapoleon, pero la convención oficial de Google esArgs:. Usa una forma y sé consistente.- Indentación continuada. Cuando la descripción de un parámetro ocupa varias líneas, las siguientes van indentadas a la altura del texto, no del nombre. Equivocarse rompe el parser.
- Confundir con NumPy style. No mezcles secciones con guiones (NumPy) y secciones con
:(Google) en el mismo proyecto. - Tipos en
Args:ya no son obligatorios si tienes type hints en la signatura, son redundantes. La práctica moderna es: type hints en la signatura, descripción en el docstring.
Enlaces
Relacionados en esta página
NumPy style, la alternativa más detallada.autodoc + napoleon, Napoleon también parsea Google style.
autodoc y napoleon
autodoc y napoleon son dos extensiones de Sphinx que casi nunca se usan por separado. autodoc introspecta módulos Python, importa el código y extrae signaturas y docstrings. napoleon interpone un pre-procesador que convierte docstrings NumPy o Google style al RST nativo que el resto del pipeline de Sphinx espera.
Sin esta pareja, documentar API en Sphinx implicaría escribir RST a mano para cada función. Con ella, el flujo es: escribes los docstrings en el estilo que prefieras, listas los módulos a documentar (vía automodule / autoclass / autofunction o, mejor, autosummary) y Sphinx hace el resto.
Cuándo usarlo
- Siempre que uses Sphinx y tengas docstrings NumPy o Google. No es opcional para librerías Python.
- Cuando quieras que la documentación de API se mantenga automáticamente sincronizada con el código, añadir un parámetro a una función actualiza la doc en el siguiente build.
Cuándo NO usarlo
- Si usas MkDocs en lugar de Sphinx: el equivalente es
mkdocstrings, noautodoc + napoleon. - Si tu librería tiene
importcon efectos secundarios pesados (conexiones, carga de modelos):autodoclos ejecutará en cada build. Refactoriza a lazy loading o usamock_imports.
Conceptos clave
automodule,autoclass,autofunctionson las directivas básicas: documentan un módulo, una clase o una función.autosummarygenera tablas-resumen con enlaces a páginas detalladas. Combinado con:toctree:crea automáticamente las páginas de cada símbolo.napoleon_numpy_docstring/napoleon_google_docstringactivan/desactivan los parsers. Mejor activar solo uno por proyecto.autodoc_mock_importspermite “fingir” imports pesados sin que rompan el build (útil cuandonumpy/torchestán enrequirements.txtpero no en el entorno de RTD).autodoc_default_optionscentraliza opciones (members,undoc-members,show-inheritance) para no repetirlas en cada directiva.
Patrón mínimo
# docs/conf.py
extensions = [
"sphinx.ext.autodoc",
"sphinx.ext.autosummary",
"sphinx.ext.napoleon",
"sphinx.ext.viewcode",
]
autosummary_generate = True # generar páginas de cada símbolo
autodoc_default_options = {
"members": True,
"show-inheritance": True,
"undoc-members": False,
}
napoleon_numpy_docstring = True
napoleon_google_docstring = False.. docs/api.rst
==========
Referencia
==========
.. autosummary::
:toctree: generated/
:recursive:
mi_proyecto.modulo_a
mi_proyecto.modulo_bTrampas habituales
autodocno encuentra el módulo. Es el error número uno. El proyecto debe ser importable: añade elsrc/alsys.pathenconf.pyo (mejor) instala conpip install -e .antes del build.- Mezclar estilos. Activar simultáneamente
napoleon_numpy_docstringynapoleon_google_docstringcon docstrings ambiguos lleva a parsings inconsistentes. Decide uno. autosummarysin:recursive:documenta solo el nivel superior. Para librerías con submódulos profundos,:recursive:es casi siempre lo que quieres.- Heredados sin
:inherited-members:. Si una clase hereda métodos relevantes de una base, por defecto no aparecerán. Activa:inherited-members:(con cuidado: hereda también__init_subclass__y compañía).
Enlaces
Relacionados en esta página
Sphinx, el generador donde viven.NumPy styleyGoogle style, convenciones que parsea Napoleon.doctest, ejecuta los ejemplos embebidos.
doctest
doctest es el módulo de la stdlib (y la extensión sphinx.ext.doctest) que ejecuta los ejemplos >>> embebidos en los docstrings y verifica que la salida real coincide con la documentada. Es la forma más barata de mantener los ejemplos de la documentación honestos: si cambias el código y rompes la signatura, el doctest falla en CI.
No sustituye a un test suite completo (pytest), pero cubre el segmento crítico: los ejemplos que los usuarios leerán y copiarán. Un ejemplo de docstring incorrecto erosiona la confianza en toda la documentación.
Cuándo usarlo
- Cualquier proyecto donde los docstrings contengan ejemplos
>>>. Si están ahí, deben funcionar. - Librerías científicas donde los ejemplos son a la vez documentación y micro-spec.
- Como smoke test rápido en CI antes del test suite completo.
Cuándo NO usarlo
- Para tests complejos con fixtures, mocks, parametrización:
pytestes la herramienta correcta.doctestcubre el caso simple. - Cuando los ejemplos tienen output no determinista (timestamps, hashes, orden de dicts en versiones antiguas de Python): mantenerlos verdes requiere
# doctest: +ELLIPSISo reescribir el ejemplo.
Conceptos clave
- Un doctest es literalmente una sesión REPL embebida:
>>>para input, línea siguiente para output esperado. - Directivas (
# doctest: +ELLIPSIS,+SKIP,+NORMALIZE_WHITESPACE) modifican el comportamiento por ejemplo. pytest --doctest-modulesejecuta los doctests de todos los módulos del proyecto sin configuración adicional.sphinx.ext.doctestlos ejecuta como parte del build de Sphinx (sphinx-build -b doctest).- En NumPy style, la sección
Examplescon>>>es ejecutada por defecto sidoctestestá activo.
Patrón mínimo
def factorial(n):
"""Calcula el factorial de un entero no negativo.
Examples
--------
>>> factorial(0)
1
>>> factorial(5)
120
>>> factorial(10)
3628800
"""
if n == 0:
return 1
return n * factorial(n - 1)# Ejecutar todos los doctests del proyecto
pytest --doctest-modules src/
# O bien, dentro del build de Sphinx
sphinx-build -b doctest docs docs/_build/doctest# Ejemplo con directivas para output no determinista
def info_sistema():
"""Devuelve información del sistema.
Examples
--------
>>> info_sistema() # doctest: +ELLIPSIS
{'os': ..., 'python': '3...'}
"""
...Trampas habituales
Espacios en blanco. El doctest compara carácter a carácter. Un espacio extra al final de la línea de output esperado hace que el test falle silenciosamente.
+NORMALIZE_WHITESPACEayuda pero esconde otros problemas.Orden de dicts. Antes de Python 3.7, los dicts no tenían orden garantizado. Aún hoy, el output de
repr(set)no es determinista. Usasorted(...)o+ELLIPSISen esos casos.Imports. Cada doctest se ejecuta en un namespace limpio dentro del módulo. Los imports tienen que estar visibles, añade
>>> import numpy as npal inicio de ejemplos que usen NumPy.Excepciones esperadas. Para tests que esperan excepciones, el formato es:
>>> factorial(-1) Traceback (most recent call last): ... ValueError: n debe ser no negativoEl
...enTracebackactiva la tolerancia al stack completo.
Enlaces
Relacionados en esta página
NumPy styleyGoogle style, la secciónExamplesadmite doctests.Sphinx, donde corresphinx-build -b doctest.
MyST
MyST (Markedly Structured Text) es un dialecto de Markdown extendido que añade toda la potencia de las directivas y roles de reStructuredText. Es el puente que permite escribir documentación Sphinx en Markdown en lugar de RST, sin perder ninguna feature del ecosistema (intersphinx, doctest, autodoc, admoniciones, cross-references).
Mantenido por la organización Executable Books, es la convención emergente en proyectos científicos modernos que quieren la potencia de Sphinx pero la familiaridad de Markdown, particularmente fuerte en Jupyter Book, donde MyST es nativo.
Cuándo usarlo
- Proyectos en Sphinx donde el equipo prefiere Markdown sobre RST.
- Documentación que mezcla prosa (mejor en Markdown) con directivas Sphinx (admoniciones, toctree, autodoc).
- Sitios que combinan documentación + notebooks ejecutables (Jupyter Book usa MyST por defecto).
Cuándo NO usarlo
- Proyectos basados en MkDocs, el Markdown de MkDocs (CommonMark +
pymdown-extensions) no es MyST. Las directivas son distintas y no se importan entre sí. - Cuando el proyecto ya tiene cientos de páginas en RST estable: el coste de migración rara vez compensa.
Conceptos clave
- Activación: instalar
myst-parsery añadir"myst_parser"aextensionsenconf.py. Sphinx procesa automáticamente.mdademás de.rst. - Directivas se escriben con triple-backtick:
```{directive} args(en RST sería.. directive:: args). - Roles (referencias en línea) usan
{role}\target`(en RST sería:role:`target``). myst_enable_extensionsactiva features opcionales:colon_fence,deflist,dollarmath,linkify,substitution.- Soporta cross-references Sphinx completos:
{ref}`label`,{doc}`page`,{class}`numpy.ndarray`.
Patrón mínimo
# docs/conf.py
extensions = [
"myst_parser",
"sphinx.ext.autodoc",
"sphinx.ext.napoleon",
"sphinx.ext.intersphinx",
]
source_suffix = {
".rst": "restructuredtext",
".md": "markdown",
}
myst_enable_extensions = [
"colon_fence", # ::: como alternativa a ```
"deflist", # listas de definición
"dollarmath", # math con $...$
]<!-- docs/guia.md -->
# Guía rápida
```{note}
Esta página describe la API de alto nivel.
```
Ver también {func}`mi_proyecto.calculo.media_movil` y la documentación
oficial de {class}`numpy.ndarray`.
```{toctree}
:maxdepth: 2
instalacion
tutorial
referencia
```Trampas habituales
- Confundir MyST con Markdown de MkDocs. Son incompatibles a nivel de directivas.
```{note}funciona en MyST pero no en MkDocs (en MkDocs usarías!!! note). - Tildes vs
colon_fence. MyST acepta tanto```{directive}como:::directive(sicolon_fenceestá activo). Mezclarlos en el mismo proyecto es legible pero ruidoso, decide una convención. - Cross-references. El formato es
{role}\target``, con backticks alrededor del target. Olvidar los backticks es el error más común. - Mezclar
.rsty.mdestá soportado pero genera fricción: los enlaces relativos cambian de sintaxis. Para proyectos nuevos, comprométete con uno.
Enlaces
- Documentación oficial, MyST Parser
- Guía completa, MyST syntax
- Jupyter Book, uso intensivo de MyST.