Criando documentações com Sphinx | Victor Torres
Criando documentações com Sphinx
por Victor Torres em mai de 2020
Uma parte muito importante de um projeto de software é sua documentação. Existem diversas maneiras de gerar e gerenciar a documentação de um projeto. Em Python, uma das principais alternativas é o Sphinx.
O Sphinx – Python Documentation Generator – é um gerador de documentação que teve seu primeiro release público em 2008. Ele é escrito em Python e é utilizado por projetos famosos como Django e SQLAlchemy, mas pode ser utilizado em outros ambientes, como é o caso do Kernel do Linux.
Ele converte conteúdo reStructuredText (rst) em páginas web, documentos em PDF, LaTeX, EPub e vários outros. É extremamente extensível e conta com diversos plugins disponíveis na comunidade.
O Read the Docs é uma plataforma open-source de hospedagem para documentações que utiliza Sphinx para gerar o seu conteúdo. Está disponível desde 2010. Vários projetos famosos utilizam o site, por exemplo, o Scrapy. Você pode utilizar a plataforma para gerar e hospedar a documentação do seu projeto gratuitamente.
reStructuredText é a linguagem de marcação de texto padrão do Sphinx. Ela serve a um propósito semelhante ao do Markdown.
Recomendo que você aprenda pelo menos o básico sobre sua utilização aqui.
Recentemente, comecei a trabalhar no web-poet, um projeto open-source da Scrapinghub. É ele que utilizarei como base para escrever esse tutorial.
O primeiro passo para começar a trabalhar na documentação é clonar o repositório e instalar o pacote em modo de desenvolvimento num ambiente virtual:
Clonando e acessando o repositório
git clone git@github.com:scrapinghub/web-poet.git
cd web-poet
Criando e ativando um ambiente virtual
python -m virtualenv ~/.virtualenvs/web-poet
source ~/.virtualenvs/web-poet/bin/activate
Instalando o pacote em modo de desenvolvimento
Criando a documentação
Instalando o Sphinx
O Sphinx é um pacote Python que pode ser obtido do PyPI e instalado com o pip.
Inicializando a documentação
Vamos colocar a documentação dentro da pasta docs, para separar seu conteúdo do restante do projeto:
Depois disso, vamos rodar o quick-start do Sphinx:
Nesse ponto, o utilitário irá fazer diversas perguntas pra você. Vou colar as perguntas e as respostas que dei para que você possa se basear por elas. Onde não tiver y ou n, foi porque eu optei por utilizar a resposta padrão da pergunta.
Welcome to the Sphinx 1.8.5 quickstart utility.
> Project name: web-poet
> Author name(s): Scrapinghub
Basicamente, minhas únicas modificações em relação às respostas padrão do Sphinx foram:
habilitar o módulo autodoc para gerar documentação de código automaticamente
habilitar o módulo intersphinx para relacionar documentações externas de outros projetos sphinx
habilitar o módulo viewcode para disponibilizar links para visualizar o código-fonte
não gerar um command file pra Windows
Neste ponto, agora você já pode gerar a sua documentação utilizando o comando:
Escolhi o formato de página web em que o conteúdo é salvo em _build/html. No macOS, usei o seguinte comando para abrir o arquivo no meu navegador, mas você pode apenas abrir a página manualmente através do seu gerenciador de arquivos:
open -a Google\ Chrome _build/html/index.html
A página deve se parecer com isto:
Com a documentação funcionando, é hora de trocar o tema. Escolhi o tema do Read the Docs, pois é o tema utilizado também na documentação do Scrapy, o que fará com o que o usuário se sinta mais em casa ao ler a documentação do web-poet.
No arquivo conf.py, edite a região Options for HTML output para que se pareça com o seguinte:
# Add path to the RTD explicitly to robustify builds (otherwise might
# fail in a clean Debian build env)
Mais um make html e podemos ver como ficou a nossa documentação agora.
Escrevendo o índice
O arquivo index.rst é gerado automaticamente, mas eu particularmente não gosto muito da estrutura inicial. Prefiro um arquivo mais sucinto e direto ao ponto. Algo parecido com isto:
web-poet documentation
web-poet implements Page Object pattern for web scraping.
The goal of this project is to make reusable Page Objects that separates
extraction logic from crawling. They could be easily tested and distributed
across different projects. Also, they could make use of different backends,
for example, acquiring data from `Splash`_ and `AutoExtract`_ API.
Please, see also our Installation guide and our Tutorial for a quick start.
.. _`AutoExtract`: https://scrapinghub.com/autoextract
.. _`Splash`: https://scrapinghub.com/splash
.. _`web-poet`: https://github.com/scrapinghub/web-poet
Note que é importante que o seu arquivo de índice contenha pelo menos uma toctree. Você vai entender melhor como essa diretiva funciona na prática, mas resumidamente, é um índice que é utilizado para construir o menu de navegação e organizar suas ligações entre as páginas da documentação.
A primeira página que vou adicionar vai ser a página que contém a licença do projeto. O arquivo será chamado license.rst:
.. _`license`:
.. include:: ../LICENSE
Aqui aprendemos duas coisas muito interessantes.
A primeira delas é que podemos nomear uma seção da documentação para referenciá-la posteriormente. Nesse caso, fazemos com .. _`license`:. Com isso, podemos retornar ao arquivo index.rst e transformar o texto License em uma referência para esta página:
:ref:`license` is BSD 3-clause.
Também precisamos adicionar a página license a pelo menos uma toctree. Faremos isso na principal, também no arquivo index.rst, que ficará da seguinte maneira:
A outra coisa que aprendemos foi como inserir texto de outros arquivos do projeto. Nesse caso, estamos reaproveitando o texto que já existe no arquivo LICENSE, na raiz do projeto Python.
Nós faremos algo semelhante com o arquivo de changelog.
Nossa página changelog.rst será semelhante à nossa página de licença, ela vai incluir um arquivo da raiz do projeto.
Claro, precisamos adicionar a página ao nosso toctree principal no index.rst:
Quando você abre a página de changelog, veja como fica o sub-menu lateral:
Precisamos adicionar uma página com informações sobre como contribuir com o projeto. O nome do arquivo será contributing.rst:
web-poet is an open-source project. Your contribution is very welcome!
If you have a bug report, a new feature proposal or simply would like to make
a question, please check our issue tracker on Github: https://github.com/scrapinghub/web-poet/issues
Our source code is hosted on Github: https://github.com/scrapinghub/web-poet
Before opening a pull request, it might be worth checking current and previous
issues. Some code changes might also require some discussion before being
accepted so it might be worth opening a new issue before implementing huge or
We use tox_ to run tests with different Python versions::
Ele deverá ficar parecido com isto:
Aqui a brincadeira começa a ficar boa. Vamos usar o módulo autodoc para criar documentação de módulos, classes e funções da API do nosso pacote automaticamente.
O autodoc consegue descobrir as partes do seu código-fonte e gerar uma documentação automática pra ele, baseado em suas definições, anotações de tipo, retorno e docstrings.
Dentro das docstrings (do módulo, das classes ou das funções) você pode ir adicionando conteúdo que será inserido dentro da sua documentação depois de exportada.
Isso é excelente porque evita que você tenha de duplicar conteúdo inserindo texto tanto no código quanto na documentação e evita que exista uma diferença nesse conteúdo. Como ele é gerado automaticamente, vai estar sempre atualizado.
Dentro das docstrings, você também pode utilizar reStructuredText e diretivas do Sphinx, o que é muito interessante para referenciar documentações ou módulos externos. Por exemplo, imagine o seguinte arquivo Python:
"""Texto sobre meu módulo"""
"""Texto sobre minha classe, que por sua vez,
referencia :class:`.OutraClasse`.
"""Texto sobre meu método."""
class OutraClasse(MinhaClasse):
"""Texto sobre outra classe.
obj = OutraClasse()
"""Overrides :method:`.MinhaClasse.metodo`."""
Tem muita coisa disponível na própria Documentação do Sphinx. Recomendo também pesquisar um pouco mais sobre o autodoc e suas diretivas aqui.
Uma opção é pedir pra que o Sphinx gere a documentação do módulo automaticamente:
.. automodule:: web_poet.pages
Mas quero um pouco mais de controle e também poder ordenar os itens da melhor forma possível, então vou montar cada um individualmente:
.. autoclass:: web_poet.pages.Injectable
.. automethod:: web_poet.pages.is_injectable
.. autoclass:: web_poet.pages.ItemPage
.. autoclass:: web_poet.pages.WebPage
.. autoclass:: web_poet.pages.ItemWebPage
.. autoclass:: web_poet.page_inputs.ResponseData
.. autoclass:: web_poet.mixins.ResponseShortcutsMixin
Não esquecer de atualizar o toctree principal:
Todo esse texto já estava contido nas docstrings do projeto, que suporta rst.
Uma boa documentação deve ter um guia de instalação. A nossa não será diferente. Vamos colocar pela primeira vez uma página dentro de um diretório separado. Vamos criar o arquivo intro/install.rst:
.. _`intro-install`:
Installing web-poet
web-poet is a library that runs on Python 3.6 and above.
If you're already familiar with installation of Python packages, you can install
web-poet and its dependencies from PyPI with:
pip install web-poet
web-poet is written in pure Python and depends on two key Python packages:
- attrs_, reduces boilerplate when creating data-classes
- parsel_, responsible for css and xpath selectors
.. _attrs: https://github.com/python-attrs/attrs
.. _parsel: https://github.com/scrapinghub/parsel
Vamos adicionar um novo toctree ao nosso index.rst:
intro/install
O novo toctree e a utilização do parâmetro caption vai permitir que a gente tenha um resultado final assim:
Não vamos esquecer de atualizar nosso index.rst para fazer referência à nossa nova página:
Please, see also our :ref:`intro-install` and our Tutorial for a quick start.
Vou fazer a mesma coisa para o Tutorial, mas pra não alongar muito o post, vou deixar pra você conferir o resultado final neste pull request disponível no Github do projeto.
Interligando documentações externas
Dá pra fazer referência a outras documentações usando Sphinx. O seguinte código, por exemplo:
How to create a :ref:`Spider <scrapy:topics-spiders>`
Pode gerar o seguinte texto:
Para isso, precisamos configurar as ligações externas no arquivo conf.py. Neste exemplo, eu adiciono a documentação do Scrapy além da documentação do Python.
'python': ('https://docs.python.org/3', None, ),
'scrapy': ('https://docs.scrapy.org/en/latest', None, ),
No momento da build, o Sphinx vai carregar as referências desses outros projetos e gerar sua documentação com links atualizados.
Gosto de ignorar as pastas temporárias para que elas não sejam versionadas no repositório.
Adicionei isto ao .gitignore do projeto:
É sempre bom guardar as dependências necessárias para gerar a documentação.
Criei um arquivo requirements.txt dentro da pasta docs exclusivo para a documentação:
pip freeze | grep -i sphinx > requirements.txt
Isso gerou o seguinte conteúdo:
Sphinx==3.0.3
Esse arquivo pode ser utilizado pelo Read the Docs para instalar dependências necessárias para a construção da documentação, por exemplo, módulos que serão linkados por alguma parte do texto ou gerados automaticamente com o autodoc.