sphinx.ext.doctest – Trechos de teste na documentação

Muitas vezes é útil incluir trechos de código em sua documentação e demonstrar os resultados de sua execução. Mas é importante garantir que a documentação esteja atualizada com o código.

Essa extensão permite testar esses trechos de código na documentação de maneira natural. Se você marcar os blocos de código como mostrado aqui, o construtor doctest irá coletá-los e executá-los como testes doctest.

Dentro de cada documento, você pode atribuir cada fragmento a um group. Cada grupo é composto por:

  • zero ou mais blocos setup code (por exemplo, importando o módulo para teste)

  • um ou mais blocos test

Ao construir os documentos com o construtor doctest, os grupos são coletados para cada documento e executados um após o outro, executando primeiro os blocos de códigos de configuração e, em seguida, os blocos de teste na ordem em que aparecem no arquivo.

Existem dois tipos de blocos de teste:

  • Os blocos doctest-style imitam as sessões interativas intercalando o código Python (incluindo o prompt do interpretador) e a saída.

  • Os blocos code-output-style consistem em uma parte ordinária do código Python e, opcionalmente, uma saída para esse código.

Diretivas

O argumento grupo abaixo é interpretado da seguinte forma: se estiver vazio, o bloco será atribuído ao grupo denominado default. Se for *, o bloco é atribuído a todos os grupos (incluindo o grupo default). Caso contrário, deve ser uma lista separada por vírgulas de nomes de grupos.

.. testsetup:: [group]

Um bloco de código de configuração. Este código não é mostrado na saída para outros construtores, mas executado antes dos doctests do (s) grupo (s) ao qual ele pertence.

.. testcleanup:: [group]

Um bloco de código de limpeza. Este código não é mostrado na saída para outros construtores, mas executado após os doctests do (s) grupo (s) ao qual ele pertence.

Adicionado na versão 1.1.

.. doctest:: [group]

Um bloco de código de estilo doctest. Você pode usar flags padrão doctest para controlar como a saída real é comparada com o que você fornece como saída. O conjunto padrão de flags é especificado pela variável de configuração doctest_default_flags.

Esta diretiva tem suporte a cinco opções:

  • hide, uma opção de flag, oculta o bloco doctest em outros construtores. Por padrão, ele é mostrado como um bloco doctest realçado.

  • options, uma opção string, pode ser usada para fornecer uma lista separada por vírgulas das flags doctest que se aplicam a cada exemplo nos testes. (Você ainda pode fornecer flags explícitas por exemplo, com comentários doctest, mas eles também serão exibidos em outros construtores.)

  • pyversion, uma opção string, pode ser usada para especificar a versão necessária do Python para o exemplo ser testado. Por exemplo, no caso a seguir, o exemplo será testado apenas para versões do Python maiores que 3.12:

    .. doctest::
       :pyversion: > 3.12
    

    Os seguintes operandos são suportados:

    • ~=: Cláusula de liberação compatível

    • ==: Cláusula de correspondência de versão

    • !=: Cláusula de exclusão de versão

    • <=, >=: Cláusula de comparação ordenada inclusiva

    • <, >: Cláusula de comparação ordenada exclusiva

    • ===: Cláusula de igualdade arbitrária.

    A opção pyversion é seguida por PEP-440: Especificadores de Versão.

    Adicionado na versão 1.6.

    Alterado na versão 1.7: Operandos e notações da PEP-440 suportados

  • trim-doctest-flags e no-trim-doctest-flags, uma opção de sinalizador, sinalizadores de doctest (comentários parecidos com # doctest: FLAG, ...) no final das linhas e marcadores <BLANKLINE> são removidos (ou não removidos) individualmente. O padrão é trim-doctest-flags.

Observe que, assim como nos doctests padrão, você precisa usar <BLANKLINE> para sinalizar uma linha em branco na saída esperada. O <BLANKLINE> é removido ao criar a saída da apresentação (HTML, LaTeX etc.).

Além disso, você pode dar opções de doctest em linha, como em doctest:

>>> datetime.date.now()   # doctest: +SKIP
datetime.date(2008, 1, 1)

Elas serão respeitados quando o teste for executado, mas retirados da saída da apresentação.

.. testcode:: [group]

Um bloco de código para um teste de estilo de saída de código.

Esta diretiva suporta três opções:

  • hide, uma opção de flag, oculta o bloco de códigos em outros construtores. Por padrão, é mostrado como um bloco de códigos realçado.

  • trim-doctest-flags e no-trim-doctest-flags, uma opção de sinalizador, sinalizadores de doctest (comentários parecidos com # doctest: FLAG, ...) no final das linhas e marcadores <BLANKLINE> são removidos (ou não removidos) individualmente. O padrão é trim-doctest-flags.

Nota

O código em um bloco testcode é sempre executado de uma só vez, não importa quantas instruções ele contenha. Portanto, a saída não será gerada para expressões simples – use print. Exemplo:

.. testcode::

   1+1         # this will give no output!
   print(2+2)  # this will give output

.. testoutput::

   4

Além disso, esteja ciente de que, como o módulo doctest não suporta a mixagem de saída regular e uma mensagem de exceção no mesmo snippet, isso também se aplica a testcode/testoutput.

.. testoutput:: [group]

A saída correspondente, ou a mensagem de exceção, para o último bloco testcode.

Esta diretiva tem suporte a quatro opções:

  • hide, uma opção de flag, oculta o bloco de saída em outros construtores. Por padrão, é mostrado como um bloco literal sem destacar.

  • options, uma opção de string, pode ser usada para fornecer flags doctest (separados por vírgulas) como nos blocos doctest normais.

  • trim-doctest-flags e no-trim-doctest-flags, uma opção de sinalizador, sinalizadores de doctest (comentários parecidos com # doctest: FLAG, ...) no final das linhas e marcadores <BLANKLINE> são removidos (ou não removidos) individualmente. O padrão é trim-doctest-flags.

Exemplo:

.. testcode::

   print('Output     text.')

.. testoutput::
   :hide:
   :options: -ELLIPSIS, +NORMALIZE_WHITESPACE

   Output text.

O seguinte é um exemplo para o uso das diretivas. O teste via doctest e o teste via testcode e testoutput são equivalentes:

The parrot module
=================

.. testsetup:: *

   import parrot

The parrot module is a module about parrots.

Doctest example:

.. doctest::

   >>> parrot.voom(3000)
   This parrot wouldn't voom if you put 3000 volts through it!

Test-Output example:

.. testcode::

   parrot.voom(3000)

This would output:

.. testoutput::

   This parrot wouldn't voom if you put 3000 volts through it!

Ignorando testes condicionalmente

skipif, uma opção de string, pode ser usada para ignorar diretivas condicionalmente. Isto pode ser útil, e. quando um conjunto diferente de testes deve ser executado dependendo do ambiente (hardware, rede/VPN, dependências opcionais ou diferentes versões de dependências). A opção skipif é suportada por todas as diretivas doctest. Abaixo estão os casos de uso típicos de skipif quando usados para diretivas diferentes:

  • testsetup e testcleanup

    • condicionalmente pular a configuração do teste e/ou a limpeza

    • personalizar o código de configuração/limpeza por ambiente

  • doctest

    • condicionalmente pular um teste e sua verificação de saída

  • testcode

    • condicionalmente pular um teste

    • personalizar código de teste por ambiente

  • testoutput

    • condicionalmente ignorar a declaração de saída para um teste ignorado

    • esperar saída diferente dependendo do ambiente

O valor da opção skipi é avaliado como uma expressão Python. Se o resultado for um valor verdadeiro, a diretiva é omitida da execução de teste, como se ela não estivesse presente no arquivo.

Em vez de repetir uma expressão, a opção de configuração doctest_global_setup pode ser usada para atribuí-la a uma variável que pode ser usada em seu lugar.

Aqui está um exemplo que pula alguns testes se o Pandas não estiver instalado:

conf.py
extensions = ['sphinx.ext.doctest']
doctest_global_setup = '''
try:
    import pandas as pd
except ImportError:
    pd = None
'''
contents.rst
.. testsetup::
   :skipif: pd is None

   data = pd.Series([42])

.. doctest::
   :skipif: pd is None

   >>> data.iloc[0]
   42

.. testcode::
   :skipif: pd is None

   print(data.iloc[-1])

.. testoutput::
   :skipif: pd is None

   42

Configuração

A extensão doctest usa os seguintes valores de configuração:

doctest_default_flags

Por padrão, essas opções estão ativadas:

  • ELLIPSIS, permitindo colocar elipses na saída esperada que correspondam a qualquer coisa na saída real;

  • IGNORE_EXCEPTION_DETAIL, fazendo com que tudo seguindo os dois pontos mais à esquerda e qualquer informação do módulo no nome da exceção seja ignorada;

  • DONT_ACCEPT_TRUE_FOR_1, rejeitando True na saída onde 1 é dado – o comportamento padrão de aceitar essa substituição é uma relíquia de 2.2 vezes antes do Python.

Adicionado na versão 1.5.

doctest_show_successes

O padrão é True. Controla se os sucessos são relatados.

Para um projeto com muitos doctests, pode ser útil definir isto como False para realçar apenas falhas.

Adicionado na versão 7.2.

doctest_path

Uma lista de diretórios que serão incluídos no sys.path quando o construtor doctest for usado. (Certifique-se de que contém paths absolutos.)

doctest_global_setup

Código Python tratado como se fosse colocado em uma diretiva testsetup para cada arquivo testado e para cada grupo. Você pode usar isso para, por exemplo, módulos de importação que você sempre precisará em seus doctests.

Adicionado na versão 0.6.

doctest_global_cleanup

Código Python tratado como se fosse colocado numa diretiva testcleanup para cada arquivo testado e para cada grupo. Você pode usar isso para, por exemplo, remover todos os arquivos temporários que os testes deixam para trás.

Adicionado na versão 1.1.

doctest_test_doctest_blocks

Se esta for uma string não vazia (o padrão é 'default'), os blocos padrão de doctest do reStructuredText também serão testados. Eles serão atribuídos ao nome do grupo fornecido.

Os blocos de doctest do reStructuredText são simplesmente doctests colocados em um parágrafo próprio, assim:

Some documentation text.

>>> print(1)
1

Some more documentation text.

(Observe que nenhum :: especial é usado para introduzir um bloco doctest; os docutils os reconhecem do >>> inicial. Além disso, nenhuma indentação adicional é usado, embora não atrapalhe.)

Se este valor for deixado em seu valor padrão, o trecho acima será interpretado pelo construtor doctest exatamente como o seguinte:

Some documentation text.

.. doctest::

   >>> print(1)
   1

Some more documentation text.

Esse recurso torna mais fácil para você testar doctests em docstrings incluídos com a extensão autodoc sem marcá-los com uma diretiva especial.

Note que não pode haver linhas em branco nos blocos de doctest do reStructuredText. Elas serão interpretadas como um bloco terminando e outro bloco começando. Além disso, a remoção das opções <BLANKLINE> e # doctest: só funciona em blocos doctest, embora você possa definir trim_doctest_flags para conseguir isso em todos os blocos de código com o conteúdo de console Python.