doctest — Exemples de tests interactifs en Python

Code source : Lib/doctest.py


Le module doctest cherche des extraits de texte ressemblant à des sessions Python interactives avant de les exécuter, de façon à vérifier que le fonctionnement correspond exactement à la description. Voici quelques cas d'utilisation de doctest :

  • Vérifier que les docstrings d'un module sont à jour en vérifiant que tous les exemples interactifs fonctionnent toujours tels que décrits.

  • Réaliser un test de régression en vérifiant que les exemples interactifs provenant d'un fichier de test ou d'un objet de test fonctionnent comme prévu.

  • Rédiger de la documentation sous forme de tutoriel pour un paquet, avec une abondance d'exemples ayant des entrées et des sorties. On pourrait voir ça comme des tests « dans le texte » ou de la « documentation exécutable », selon le point de vue.

Voici un petit exemple d'un module qui soit tout de même complet :

"""
This is the "example" module.

The example module supplies one function, factorial().  For example,

>>> factorial(5)
120
"""

def factorial(n):
    """Return the factorial of n, an exact integer >= 0.

    >>> [factorial(n) for n in range(6)]
    [1, 1, 2, 6, 24, 120]
    >>> factorial(30)
    265252859812191058636308480000000
    >>> factorial(-1)
    Traceback (most recent call last):
        ...
    ValueError: n must be >= 0

    Factorials of floats are OK, but the float must be an exact integer:
    >>> factorial(30.1)
    Traceback (most recent call last):
        ...
    ValueError: n must be exact integer
    >>> factorial(30.0)
    265252859812191058636308480000000

    It must also not be ridiculously large:
    >>> factorial(1e100)
    Traceback (most recent call last):
        ...
    OverflowError: n too large
    """

    import math
    if not n >= 0:
        raise ValueError("n must be >= 0")
    if math.floor(n) != n:
        raise ValueError("n must be exact integer")
    if n+1 == n:  # catch a value like 1e300
        raise OverflowError("n too large")
    result = 1
    factor = 2
    while factor <= n:
        result *= factor
        factor += 1
    return result


if __name__ == "__main__":
    import doctest
    doctest.testmod()

L'exécution du fichier example.py directement à partir de la ligne de commande démontre la magie de doctest :

$ python example.py
$

Il n'y a pas de sortie ! C'est normal, cela signifie que tous les exemples fonctionnent. Passez -v au script pour que doctest affiche un journal détaillé de ce qui a été essayé, avant d'afficher un résumé à la fin :

$ python example.py -v
Trying:
    factorial(5)
Expecting:
    120
ok
Trying:
    [factorial(n) for n in range(6)]
Expecting:
    [1, 1, 2, 6, 24, 120]
ok

Et ainsi de suite, jusqu'à ce qu'on atteigne :

Trying:
    factorial(1e100)
Expecting:
    Traceback (most recent call last):
        ...
    OverflowError: n too large
ok
2 items passed all tests:
   1 tests in __main__
   8 tests in __main__.factorial
9 tests in 2 items.
9 passed and 0 failed.
Test passed.
$

That's all you need to know to start making productive use of doctest! Jump in. The following sections provide full details. Note that there are many examples of doctests in the standard Python test suite and libraries. Especially useful examples can be found in the standard test file Lib/test/test_doctest/test_doctest.py.

Utilisation simple : vérifier des exemples dans des docstrings

The simplest way to start using doctest (but not necessarily the way you'll continue to do it) is to end each module M with:

if __name__ == "__main__":
    import doctest
    doctest.testmod()

doctest then examines docstrings in module M.

Exécuter le module comme un script a comme conséquence d'exécuter et de vérifier les exemples dans les docstrings :

python M.py

Ceci n'affiche rien à moins qu'un exemple échoue ; le cas échéant, les exemples défaillants et les causes du ou des échecs sont affichés sur stdout, et la ligne finale de la sortie est ***Test Failed*** *N failures*., où N est le nombre d'exemples défaillants.

À la place, exécutez-la avec l'option de ligne de commande -v :

python M.py -v

alors, un rapport détaillé de tous les exemples faisant partie de l'essai est affiché sur la sortie standard, accompagné à la fin de leurs résumés.

Vous pouvez activer le mode verbeux en passant verbose=True à testmod(), ou vous le désactiver en lui passant verbose=False. Dans ces deux cas, sys.argv n'est pas inspecté par testmod() (ainsi, lui passer -v ou pas n'a aucun effet).

Il y a un raccourci pour exécuter testmod() à partir de la ligne de commande. Vous demandez à l'interpréteur Python d'exécuter le module doctest directement à partir de la bibliothèque standard afin de passer le ou les noms des modules à partir de la ligne de commande ainsi :

python -m doctest -v example.py

Ceci importera example.py comme un module autonome et exécutera testmod() sur celui-ci. Notez que ceci peut ne pas fonctionner si le fichier fait partie d'un paquet et importe d'autres sous-modules de ce paquet.

Pour plus d'informations sur testmod(), consultez la section API de base.

Utilisation simple : vérifier des exemples dans un fichier texte

Une autre application simple de doctest est de tester des exemples interactifs dans un fichier texte. Ceci est fait avec la fonction testfile() :

import doctest
doctest.testfile("example.txt")

Ce court script exécute et vérifie chacun des exemples Python interactifs contenus dans le fichier example.txt. Le contenu du fichier est traité comme une seule docstring géante ; le fichier n'a pas besoin de contenir un programme Python ! Par exemple, prenons un fichier example.txt contenant :

The ``example`` module
======================

Using ``factorial``
-------------------

This is an example text file in reStructuredText format.  First import
``factorial`` from the ``example`` module:

    >>> from example import factorial

Now use it:

    >>> factorial(6)
    120

Exécuter doctest.testfile("example.txt") recherche les erreurs dans cette documentation :

File "./example.txt", line 14, in example.txt
Failed example:
    factorial(6)
Expected:
    120
Got:
    720

Comme pour testmod(), testfile() n'affichera rien sauf si un exemple échoue. Si un exemple échoue, alors le ou les exemples défaillants et leurs causes sont affichés sur stdout, dans le même format que testmod().

Par défaut, testfile() cherche les fichiers dans le répertoire où se situe le module qui l'appelle. Consultez la section API de base pour une description des options de ligne de commande à utiliser afin de chercher dans d'autres répertoires.

Comme pour testmod(), la verbosité de testfile() peut être ajustée avec l'option de ligne de commande -v ou avec le mot clé verbose.

Il y a un raccourci pour exécuter testfile() à partir de la ligne de commande. Demandez à l'interpréteur Python d'exécuter le module doctest directement à partir de la bibliothèque standard et de passer le ou les noms des modules à partir de la ligne de commande ainsi :

python -m doctest -v example.txt

Puisque le nom du fichier ne se termine pas par .py, doctest en déduit qu'il s'exécute à l'aide de testfile(), et non pas testmod().

Pour plus d'information sur testfile(), consultez la section API de base.

Comment ça marche

Cette section examine en détail le fonctionnement de doctest : quelles docstrings sont considérées, comment sont trouvés les exemples interactifs, quel est le contexte d'exécution sélectionné, comment les exceptions sont gérées, et de quelles façons les options de ligne de commande peuvent être utilisées pour définir le comportement. Ceci est l'information dont vous avez besoin pour écrire des exemples doctest ; pour de l'information sur l'exécution de doctest sur ces exemples, consultez les sections suivantes.

Quelles docstrings sont considérées ?

Les docstrings du module, de toutes les fonctions, classes, et méthodes sont cherchées. Les objets qui sont importés dans le module ne sont pas cherchés.

In addition, there are cases when you want tests to be part of a module but not part of the help text, which requires that the tests not be included in the docstring. Doctest looks for a module-level variable called __test__ and uses it to locate other tests. If M.__test__ exists, it must be a dict, and each entry maps a (string) name to a function object, class object, or string. Function and class object docstrings found from M.__test__ are searched, and strings are treated as if they were docstrings. In output, a key K in M.__test__ appears with name M.__test__.K.

For example, place this block of code at the top of example.py:

__test__ = {
    'numbers': """
>>> factorial(6)
720

>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
"""
}

The value of example.__test__["numbers"] will be treated as a docstring and all the tests inside it will be run. It is important to note that the value can be mapped to a function, class object, or module; if so, doctest searches them recursively for docstrings, which are then scanned for tests.

Toute classe trouvée est ainsi cherchée récursivement, afin de tester les docstrings contenues dans leurs méthodes et leurs classes imbriquées.

Comment les exemples docstring sont-ils identifiés ?

Dans la plupart des cas, un copier-coller d'une séance interactive de console fonctionne bien, mais doctest n'essaye pas de faire une simulation exacte d'un shell Python spécifique.

>>> # comments are ignored
>>> x = 12
>>> x
12
>>> if x == 13:
...     print("yes")
... else:
...     print("no")
...     print("NO")
...     print("NO!!!")
...
no
NO
NO!!!
>>>

Toute sortie souhaitée doit immédiatement suivre le dernier '>>> ' ou le dernier '... ' contenant le code, et la sortie souhaitée, s'il y en a une, s'étend jusqu'au prochain '>>> ' ou à la prochaine ligne vide.

En détail :

  • La sortie souhaitée ne peut pas contenir une ligne vide, puisque contenir une telle ligne signale la fin de la sortie souhaitée. Si la sortie souhaitée doit contenir une ligne vide, ajoutez <BLANKLINE> dans votre exemple doctest à chaque endroit où une ligne vide est souhaitée.

  • Tous les caractères de tabulation insécables (hard tab characters) sont convertis en espaces, en utilisant des taquets de tabulation de 8 espaces. Les tabulations se trouvant dans la sortie générée par le code test ne sont pas modifiées. Comme tout caractère de tabulation insécable est converti, ceci veut dire que si le code de sortie inclut des caractères de tabulation insécables, alors la seule façon que le doctest peut réussir est si l'option NORMALIZE_WHITESPACE ou si directive a cours. De façon alternative, le test peut être ré-écrit afin de capturer la sortie et de la comparer à un ensemble de valeurs attendues, et ce, en tant qu'étape du test. Cette gestion des tabulations à la source a été obtenue suite à un processus d'essais et d'erreurs ; il a été démontré que c'était là la façon de les gérer qui soit la moins susceptible de générer des erreurs. Il est possible d'utiliser un algorithme différent pour la gestion des tabulations en rédigeant une classe sur mesure DocTestParser.

  • La sortie vers stdout est capturée, mais pas la sortie vers stderr (les traces d'appel sont capturées par d'autres moyens).

  • Si vous souhaitez conserver les barres obliques inversées telles quelles lorsque vous terminez une ligne avec une barre oblique inversée dans une séance interactive, ou quand vous utilisez une telle barre pour toute autre raison, vous devez utiliser une docstring brute :

    >>> def f(x):
    ...     r'''Backslashes in a raw docstring: m\n'''
    >>> print(f.__doc__)
    Backslashes in a raw docstring: m\n
    

    Sinon, la barre oblique inversée est interprétée comme faisant partie de la chaîne de caractères. Par exemple, le \n ci-dessus est interprété comme un caractère de saut de ligne. De façon alternative, vous pouvez doubler chaque barre oblique inversée dans la version doctest (et n'utilisez pas dans ce cas de docstring brute) :

    >>> def f(x):
    ...     '''Backslashes in a raw docstring: m\\n'''
    >>> print(f.__doc__)
    Backslashes in a raw docstring: m\n
    
  • La colonne de départ n'a pas d'importance :

    >>> assert "Easy!"
          >>> import math
              >>> math.floor(1.9)
              1
    

    et autant d'espaces sont retirés de la sortie attendue qu'il y avait d'espaces avant la ligne commençant par '>>> '.

Quel est le contexte d'exécution ?

By default, each time doctest finds a docstring to test, it uses a shallow copy of M's globals, so that running tests doesn't change the module's real globals, and so that one test in M can't leave behind crumbs that accidentally allow another test to work. This means examples can freely use any names defined at top-level in M, and names defined earlier in the docstring being run. Examples cannot see names defined in other docstrings.

Vous pouvez forcer l'utilisation de votre propre dict comme contexte d'exécution en passant globs=your_dict à testmod() ou encore, à testfile().

Qu'en est-il des exceptions ?

Pas de problèmes, tant que la trace d'appels est la seule sortie produite par l'exemple : il suffit d'ajouter la trace. [1] Comme les traces d'appels contiennent des détails qui sont sujets à changement rapide (par exemple, le chemin exact vers un fichier et les numéros de ligne), ceci est un cas où doctest fait un effort pour être flexible dans ce qu'il accepte.

Exemple simple :

>>> [1, 2, 3].remove(42)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: list.remove(x): x not in list

Ce doctest réussit si ValueError est levée, avec le détail list.remote(x): x not in list tel que montré.

La sortie attendue pour une exception doit commencer par un en-tête de trace d'appels, qui peut être l'une des deux lignes suivantes, avec la même indentation que la première ligne de l'exemple :

Traceback (most recent call last):
Traceback (innermost last):

L'en-tête de la trace d'appels est suivi par une pile optionnelle de trace d'appels, dont le contenu est ignoré par doctest. La trace d'appels est habituellement omise, ou est copiée verbatim à partir d'une séance interactive.

La pile de trace d'appels est suivie par la partie la plus intéressante : la ou les lignes contenant le type et le détail de l'exception. Ceci est habituellement la dernière ligne de la trace d'appels ; dans le cas où l'exception a un détail sur plusieurs lignes, il est possible de prolonger sur plusieurs lignes :

>>> raise ValueError('multi\n    line\ndetail')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: multi
    line
detail

Les trois dernières lignes (en commençant par ValueError) sont comparées avec le type et le détail de l'exception ; tout le reste est ignoré.

La pratique optimale est d'omettre la pile de trace d'appels, à moins que celle-ci ait une valeur significative de documentation de l'exemple. Ainsi, le dernier exemple est probablement meilleur tel qui suit :

>>> raise ValueError('multi\n    line\ndetail')
Traceback (most recent call last):
    ...
ValueError: multi
    line
detail

Prenez note que les traces d'appels sont traitées de façon vraiment particulière. Précisément, dans l'exemple ré-écrit, l'utilisation de ... est indépendante de l'option doctest ELLIPSIS. Les points de suspension dans cet exemple peuvent être omis, ou peuvent aussi être trois (ou trois cents) virgules ou chiffres, ou une retranscription indentée d'une parodie de Monty Python.

Quelques détails que vous devriez lire une fois, mais que vous pouvez oublier :

  • Doctest ne peut pas deviner si votre sortie attendue provient d'une trace d'appels issue d'une exception ou d'un affichage ordinaire. Ainsi, si nous avons un exemple s'attendant à obtenir ValueError: 42 is prime, celui-ci réussira peu importe si ValueError est réellement levée ou si l'exemple affiche simplement ce texte de trace d'appels. Dans la pratique, une sortie ordinaire commence rarement par une ligne d'en-tête de trace d'appels ; ainsi, ceci ne pose pas de vrai problème.

  • Chaque ligne de la trace d'appel (s'il y en a) doit soit être indentée d'un niveau supplémentaire au niveau de la première ligne de l'exemple ou doit commencer par un caractère qui ne soit pas alphanumérique. La première ligne suivant l'en-tête de la trace d'appels qui soit indentée similairement et qui commence par un caractère alphanumérique est comprise comme étant le début du détail de l'exception. Bien sûr, ceci fait la chose adéquate pour les traces d'appels véritables.

  • Lorsque l'option de doctest IGNORE_EXCEPTION_DETAIL est définie, tout ce qui suit le point-virgule se trouvant le plus à gauche ainsi que toute information liée au module dans le nom de l'exception sont ignorés.

  • Le shell interactif omet la ligne d'en-tête de la trace d'appels pour certaines erreurs SyntaxError. Ceci étant dit, doctest utilise la ligne d'en-tête de la trace d'appels afin de faire une distinction entre les exceptions et les autres types d'erreurs. Ainsi, dans les rares cas où vous avez besoin de tester une erreur SyntaxError qui omet l'en-tête de la trace d'appels, il vous est nécessaire d'ajouter manuellement la ligne d'en-tête de la trace d'appels à l'exemple de test.

  • For some exceptions, Python displays the position of the error using ^ markers and tildes:

    >>> 1 + None
      File "<stdin>", line 1
        1 + None
        ~~^~~~~~
    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    

    Comme les lignes dénotant la position de l'erreur précèdent le type et le détail de l'exception, elles ne sont pas vérifiées par doctest. Par exemple, le test suivant réussira, même si le marqueur ^ n'est pas à la bonne place :

    >>> 1 + None
      File "<stdin>", line 1
        1 + None
        ^~~~~~~~
    TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
    

Options de ligne de commande

Un ensemble d'options de ligne de commande contrôle différents aspects du comportement de doctest. Pour les options, des noms symboliques sont fournis comme des constantes de module, qui peuvent être composés par un OU bit à bit (bitwise ORed) et passés à diverses fonctions. Les noms peuvent aussi être utilisés dans des instructions doctest, et peuvent être passés à l'interface de ligne de commande de doctest à l'aide de l'option -o.

Nouveau dans la version 3.4: L'option de ligne de commande -o.

Le premier groupe d'options définit les sémantiques de test, de façon à contrôler comment doctest décide si la sortie obtenue correspond à la sortie attendue de l'exemple :

doctest.DONT_ACCEPT_TRUE_FOR_1

Par défaut, si un bloc de sortie attendu contient uniquement un 1, un vrai bloc de sortie contenant uniquement un 1 ou un True sera considéré comme étant une correspondance ; de façon similaire, nous avons une correspondance pour 0 et False. Lorsque l'option DONT_ACCEPT_TRUE_FOR_1 est précisée, aucune de ces substitutions n'est acceptée. Le comportement par défaut s'ajuste au fait que Python a changé le type de renvoi de plusieurs fonctions, passant de nombres entiers à des booléens ; les doctests s'attendant à une sortie de "petit entier" (little integer) fonctionnent encore dans ces cas. Cette option disparaîtra probablement, mais pas avant plusieurs années.

doctest.DONT_ACCEPT_BLANKLINE

Par défaut, si un bloc de sortie attendue contient une ligne contenant uniquement la chaîne de caractères <BLANKLINE>, alors cette ligne sera en correspondance avec une ligne vide dans la sortie réelle. Puisqu'une véritable ligne vide permet de délimiter la sortie attendue, ceci est la seule façon de communiquer qu'une ligne vide est souhaitée. Lorsque l'option DONT_ACCEPT_BLANKLINE est précisée, cette substitution n'est pas permise.

doctest.NORMALIZE_WHITESPACE

Lorsque précisé, toutes les séquences de caractères d'espacement et de caractères de saut de ligne sont traitées comme équivalentes. Toute séquence de caractères d'espacement à l'intérieur de la sortie attendue correspondra alors à toute séquence de caractères d'espacement à l'intérieur de la sortie réelle. Par défaut, les caractères d'espacement doivent correspondre de façon exacte. L'option NORMALIZE_WHITESPACE est particulièrement utile lorsqu'une ligne de sortie attendue est très longue, et que l'on souhaite la répartir sur plusieurs lignes dans le fichier source.

doctest.ELLIPSIS

Lorsque précisé, un marqueur de points de suspension (...) dans la sortie attendue peut correspondre à n'importe quelle partie de chaîne de caractères dans la sortie réelle. Ceci inclut les parties qui traversent les frontières de lignes, ainsi que les parties vides de chaînes de caractères ; ainsi, il est préférable d'en faire une utilisation simple. Les usages complexes mènent aux mêmes surprises du type "oups, il y avait trop de correspondances !" que l'utilisation de .* dans les expressions régulières.

doctest.IGNORE_EXCEPTION_DETAIL

When specified, doctests expecting exceptions pass so long as an exception of the expected type is raised, even if the details (message and fully qualified exception name) don't match.

For example, an example expecting ValueError: 42 will pass if the actual exception raised is ValueError: 3*14, but will fail if, say, a TypeError is raised instead. It will also ignore any fully qualified name included before the exception class, which can vary between implementations and versions of Python and the code/libraries in use. Hence, all three of these variations will work with the flag specified:

>>> raise Exception('message')
Traceback (most recent call last):
Exception: message

>>> raise Exception('message')
Traceback (most recent call last):
builtins.Exception: message

>>> raise Exception('message')
Traceback (most recent call last):
__main__.Exception: message

Note that ELLIPSIS can also be used to ignore the details of the exception message, but such a test may still fail based on whether the module name is present or matches exactly.

Modifié dans la version 3.2: Maintenant, IGNORE_EXCEPTION_DETAIL permet aussi d'ignorer toute information liée au module contenant l'exception qui est en train d'être testée.

doctest.SKIP

Lorsque précisé, cesse complètement l'exécution de tous les exemples. Ceci peut être utile dans des contextes où les exemples doctest sont à la fois de la documentation et des cas de tests, et qu'un exemple doit être inclus pour des raisons de documentation, mais ne devrait pas être vérifié. Par exemple, la sortie de l'exemple doit être aléatoire ; ou encore, lorsque l'exemple peut dépendre de ressources inatteignables pour l'exécuteur de test.

L'option SKIP peut aussi être utilisée temporairement afin de commenter des exemples et d'en empêcher l'exécution.

doctest.COMPARISON_FLAGS

Un masque binaire effectuant une composition avec OU de toutes les options de comparaisons ci-dessus.

Le deuxième groupe d'options détermine comment les échecs de tests sont signalés :

doctest.REPORT_UDIFF

Lorsque précisé, les défaillances qui font intervenir des sorties attendues et réelles multi-lignes sont affichées dans une diff unifiée.

doctest.REPORT_CDIFF

Lorsque précisé, les défaillances qui font intervenir des sorties attendues et réelles multi-lignes sont affichées dans une diff de contexte.

doctest.REPORT_NDIFF

Lorsque précisé, les différences sont obtenues grâce à difflib.Differ, en utilisant le même algorithme que le populaire utilitaire ndiff.py. Ceci est la seule méthode qui puisse faire la différence à l'intérieur des lignes ainsi que parmi les lignes prises conjointement. Par exemple, si une ligne de sortie attendue contient le chiffre 1 alors que la sortie réelle contient la lettre l, une ligne est insérée avec un marqueur caret démarquant les positions de colonnes où il n'y a pas de correspondance.

doctest.REPORT_ONLY_FIRST_FAILURE

Lorsque précisé, le premier exemple défaillant de chaque doctest est affiché, mais la sortie est supprimée pour tous les autres exemples. Ceci empêche doctest de rapporter les exemples adéquats qui échouent du fait d'échecs précédents ; ceci peut aussi cacher des exemples inadéquats qui échouent de façon indépendante au premier échec. Lorsque REPORT_ONLY_FIRST_FAILURE est précisé, les exemples restants sont toujours exécutés, et sont toujours comptabilisés dans le nombre total des lignes échouant ; seulement la sortie est omise.

doctest.FAIL_FAST

Lorsque précisé, mettre fin à l'exécution après le premier exemple défaillant et ne pas essayer d'exécuter les exemples restants. Ainsi, le nombre d'échecs rapporté sera au plus un (1). Cette option peut être utile durant le débogage, étant donné que les exemples suivant le premier échec ne produiront aucune sortie de débogage.

La ligne de commande de doctest accepte l'option -f comme un raccourci de -o FAIL_FAST.

Nouveau dans la version 3.4.

doctest.REPORTING_FLAGS

Un masque binaire effectuant une composition avec le OU de toutes les options de signalement ci-dessus.

Il y a aussi une façon d'enregistrer des nouveaux noms d'option, quoique ceci n'est pas utile sauf dans le cas où vous devez faire une extension pour le code interne de doctest par le biais d'une sous-classe :

doctest.register_optionflag(name)

Crée une nouvelle option avec un nom donné, et renvoie la valeur en nombre entier de la nouvelle option. La fonction register_optionflag() peut être utilisée lors de la création de sous-classes à partir de OutputChecker ou DocTestRunner pour créer de nouvelles options qui sont supportées par vos sous-classes. La fonction register_optionflag() devrait toujours être appelée par l'expression suivante :

MY_FLAG = register_optionflag('MY_FLAG')

Instructions

Les instructions doctest peuvent être utilisées afin de modifier les options pour un exemple individuel. Les instructions doctest sont des commentaires Python spéciaux suivant le code source d'un exemple :

directive             ::=  "#" "doctest:" directive_options
directive_options     ::=  directive_option ("," directive_option)*
directive_option      ::=  on_or_off directive_option_name
on_or_off             ::=  "+" | "-"
directive_option_name ::=  "DONT_ACCEPT_BLANKLINE" | "NORMALIZE_WHITESPACE" | ...

Whitespace is not allowed between the + or - and the directive option name. The directive option name can be any of the option flag names explained above.

Les instructions d'un exemple doctest modifient le comportement de doctest et ce, seulement pour cet exemple. Utilisez + pour activer le comportement nommé, ou - pour le désactiver.

For example, this test passes:

>>> print(list(range(20)))  # doctest: +NORMALIZE_WHITESPACE
[0,   1,  2,  3,  4,  5,  6,  7,  8,  9,
10,  11, 12, 13, 14, 15, 16, 17, 18, 19]

Without the directive it would fail, both because the actual output doesn't have two blanks before the single-digit list elements, and because the actual output is on a single line. This test also passes, and also requires a directive to do so:

>>> print(list(range(20)))  # doctest: +ELLIPSIS
[0, 1, ..., 18, 19]

Multiple directives can be used on a single physical line, separated by commas:

>>> print(list(range(20)))  # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE
[0,    1, ...,   18,    19]

If multiple directive comments are used for a single example, then they are combined:

>>> print(list(range(20)))  # doctest: +ELLIPSIS
...                         # doctest: +NORMALIZE_WHITESPACE
[0,    1, ...,   18,    19]

As the previous example shows, you can add ... lines to your example containing only directives. This can be useful when an example is too long for a directive to comfortably fit on the same line:

>>> print(list(range(5)) + list(range(10, 20)) + list(range(30, 40)))
... # doctest: +ELLIPSIS
[0, ..., 4, 10, ..., 19, 30, ..., 39]

Prendre note que puisque toutes les options sont désactivées par défaut, et comme les instructions s'appliquent uniquement aux exemples dans lesquelles elles apparaissent, activer les options (par le biais de + dans une instruction) est habituellement le seul choix ayant du sens. Toutefois, les options peuvent aussi être passées aux fonctions qui exécutent les doctests, définissant de nouvelles valeurs par défaut. Dans de tels cas, désactiver une option par l'utilisation de - dans une instruction peut être utile.

Avertissements

Le module doctest est rigoureux pour ce qui est d'inclure des correspondances exactes dans la sortie attendue. Si un seul caractère ne correspond pas, le test échoue. Ceci vous surprendra probablement quelques fois, alors que vous apprenez exactement ce que Python garantit et ne garantit pas pour qui est des sorties. Par exemple, lorsqu'on affiche un ensemble (set), Python ne garantit pas que les éléments sont affichés dans un ordre particulier ; ainsi un test tel que

>>> foo()
{"Hermione", "Harry"}

est vulnérable ! Une alternative est de faire

>>> foo() == {"Hermione", "Harry"}
True

à la place. Une autre façon de faire est

>>> d = sorted(foo())
>>> d
['Harry', 'Hermione']

Il y en a d'autres, mais vous saisissez l'idée.

Another bad idea is to print things that embed an object address, like

>>> id(1.0)  # certain to fail some of the time  
7948648
>>> class C: pass
>>> C()  # the default repr() for instances embeds an address   
<C object at 0x00AC18F0>

The ELLIPSIS directive gives a nice approach for the last example:

>>> C()  # doctest: +ELLIPSIS
<C object at 0x...>

Les nombres à virgule flottante sont aussi sujets à de petites variations à la sortie, tout dépendamment de la plateforme utilisée, étant donné que Python s'en remet à la bibliothèque de la plateforme C pour la mise-en-forme des floats, et les bibliothèques C varient grandement pour ce qui de leur qualité sur ce point.

>>> 1./7  # risky
0.14285714285714285
>>> print(1./7) # safer
0.142857142857
>>> print(round(1./7, 6)) # much safer
0.142857

Numbers of the form I/2.**J are safe across all platforms, and I often contrive doctest examples to produce numbers of that form:

>>> 3./4  # utterly safe
0.75

Les fractions simples sont aussi plus faciles à comprendre, et cela fait une meilleure documentation.

API de base

Les fonctions testmod() et testfile() fournissent une interface simple pour doctest qui est suffisante pour les cas d'usage les plus élémentaires. Pour une introduction moins formelle à ces deux fonctions, voir les sections Utilisation simple : vérifier des exemples dans des docstrings et Utilisation simple : vérifier des exemples dans un fichier texte.

doctest.testfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=DocTestParser(), encoding=None)

Tous les arguments sauf filename sont optionnels, et doivent être précisés sous forme lettrée.

Teste les exemples dans le fichier nommé filename. Renvoie (failure_count, test_count).

L'argument optionnel module_relative précise comment le nom de fichier doit être interprété :

  • Si module_relative prend la valeur True (la valeur par défaut), alors filename précise un chemin relatif au module qui soit indépendant du système d'exploitation (OS). Par défaut, ce chemin est relatif au répertoire du module appelant ; mais si l'argument package est précisé, alors il est relatif à ce paquet. Pour garantir l'indépendance quant au système d'exploitation, filename doit utiliser des caractères / pour séparer chaque segment de chemin, et ne peut pas être un chemin absolu (c'est-à-dire qu'il ne peut pas commencer par /).

  • Si module_relative prend la valeur False, alors filename précise un chemin en fonction du système d'exploitation. Le chemin peut être absolu ou relatif ; les chemins relatifs sont résolus en rapport au répertoire actif.

L'option name désigne le nom du test ; par défaut, ou si None est passé en argument, os.path.basename(filename) est utilisé.

L'option package est un paquet Python ou le nom d'un paquet Python dont le répertoire doit être utilisé comme le répertoire principal pour un nom de fichier lié à un module. Si aucun paquet n'est spécifié, le répertoire du module appelé à l'exécution est utilisé comme le répertoire principal pour les noms de fichiers liés au module. C'est une erreur que de spécifier package si module_relative a False comme valeur.

L'option globs spécifie un dict à utiliser comme globals lorsque des exemples sont exécutés. Une copie superficielle de ce dict est créée pour le doctest ; ainsi, ces exemples commencent avec un état vide. Par défaut, ou si None est passé en argument, un nouveau dict vide est utilisé.

L'option extraglobs spécifie un dict intégré dans les variables globales utilisées pour exécuter l'exemple. Ceci fonctionne comme dict.update() : si globs et extraglobs ont une clé commune, la valeur associée à extraglobs apparaît dans le dict combiné. Par défaut, ou si None est passé en argument, aucune variable globale supplémentaire est utilisée. Ceci est une fonctionnalité avancée qui permet la configuration des doctests. Par exemple, un doctest peut être rédigé pour une classe de base, en utilisant un nom générique pour la classe, puis réutilisé afin de tester un nombre indéfini de sous-classes en passant un dict extraglobs reliant le nom générique à la sous-classe qui doit être testée.

L'option verbose affiche une grande quantité d'information si elle est vraie, et affiche uniquement les défaillances si elle est fausse ; par défaut, ou si None, celle-ci est vraie si et seulement si -v est présent dans sys.argv.

L'option report affiche un résumé à la fin lorsque vraie ; sinon, rien n'est affiché à la fin. En mode verbose, le résumé est détaillé, sinon le résumé est très bref (en fait, vide si tous les tests ont réussi).

L'option optionflags (dont la valeur par défaut est de zéro) calcule la valeur bitwise OR des options de ligne de commande. Voir la section Options de ligne de commande.

L'option raise_on_error est fausse par défaut. Si elle est vraie, une exception est levée à la première défaillance ou à la première exception qui ne soit prévue dans l'exemple. Ceci permet aux défaillances d'être analysées lors d'un post-mortem. Le comportement par défaut est de poursuivre l'exécution des exemples.

L'option parser définit une classe ou une sous-classe DocTestParser qui doit être utilisée pour extraire les tests des fichiers. Par défaut, on utilise un analyseur normal (c'est-à-dire, DocTestParser()).

L'option encoding définit un encodage à utiliser pour convertir le fichier en format unicode.

doctest.testmod(m=None, name=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, exclude_empty=False)

Toutes les options sont facultatives, et toutes sauf m doivent être définies en format lettré.

Ceci teste les exemples en docstrings dans les fonctions et les classes accessibles depuis le module m (ou depuis le module __main__ si m n'a pas été défini ou est None), en commençant par m.__doc__.

Also test examples reachable from dict m.__test__, if it exists. m.__test__ maps names (strings) to functions, classes and strings; function and class docstrings are searched for examples; strings are searched directly, as if they were docstrings.

Seulement les docstrings attribuées à des objets appartenant au module m sont fouillées.

Renvoie (failure_count, test_count).

L'option name donne le nom du module ; par défaut, ou si None, m.__name__ est utilisé.

Optional argument exclude_empty defaults to false. If true, objects for which no doctests are found are excluded from consideration. The default is a backward compatibility hack, so that code still using doctest.master.summarize in conjunction with testmod() continues to get output for objects with no tests. The exclude_empty argument to the newer DocTestFinder constructor defaults to true.

Les options extraglobs, verbose, report, optionflags, raise_on_error, et globs sont les mêmes que pour la fonction testfile() ci-dessus, sauf pour globs, qui est m.__dict__ par défaut.

doctest.run_docstring_examples(f, globs, verbose=False, name='NoName', compileflags=None, optionflags=0)

Les exemples de test associés à l'objet f ; par exemple, f peut être une chaîne de caractères, un module, une fonction, ou un objet de classe.

Une copie superficielle de l'argument-dictionnaire globs est utilisée pour le contexte d'exécution.

L'option name est utilisée pour les messages d'échec, et prend "NoName" comme valeur par défaut.

Si l'option verbose est vraie, les sorties sont générées même s'il n'y a aucun échec. Par défaut, la sortie est générée seulement si un exemple échoue.

L'option compileflags donne l'ensemble des options qui doit être utilisée par le compilateur Python lorsqu'il exécute les exemples. Par défaut, ou si None, les options sont inférées à partir de l'ensemble des fonctionnalités futures trouvées dans globs.

L'option optionflags fonctionne similairement à la fonction testfile() ci-dessus.

API de tests unitaires

As your collection of doctest'ed modules grows, you'll want a way to run all their doctests systematically. doctest provides two functions that can be used to create unittest test suites from modules and text files containing doctests. To integrate with unittest test discovery, include a load_tests function in your test module:

import unittest
import doctest
import my_module_with_doctests

def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(my_module_with_doctests))
    return tests

Il y a deux fonctions principales pour créer des instances de la classe unittest.TestSuite à partir de fichiers textes et de modules ayant des doctests :

doctest.DocFileSuite(*paths, module_relative=True, package=None, setUp=None, tearDown=None, globs=None, optionflags=0, parser=DocTestParser(), encoding=None)

Convertit des tests doctest à partir d'un ou plusieurs fichiers vers une classe unittest.TestSuite.

La classe renvoyée unittest.TestSuite doit être exécutée dans le cadriciel de tests unitaires et exécute les exemples interactifs trouvés dans chaque fichier. Si un exemple de n'importe quel fichier échoue, alors le test unitaire de synthèse échoue aussi, et une exception failureException est levée, affichant le nom du fichier contenant le test et un numéro de ligne (celui-ci est parfois approximatif).

Passe un ou plusieurs chemins (sous forme de chaînes de caractères) à des fichiers textes afin d'être vérifiés.

Les options peuvent être fournies comme des options lettrées :

L'option module_relative précise comment les noms de fichiers dans paths doivent être interprétés :

  • Si module_relative a True comme valeur (valeur par défaut), alors chaque nom de fichier dans paths précise un chemin relatif au module qui soit indépendant du système d'exploitation. Par défaut, ce chemin est relatif au répertoire du module appelant ; mais si l'option package est précisée, alors il est relatif à ce paquet. Afin de garantir l'indépendance face au système d'exploitation, chaque nom de fichier doit utiliser des caractères / afin de séparer les segments de chemin, et ne peut pas être un chemin absolu (c'est-à-dire, il ne peut pas commencer par /).

  • Si module_relative prend la valeur False, alors filename précise un chemin en fonction du système d'exploitation. Le chemin peut être absolu ou relatif ; les chemins relatifs sont résolus en rapport au répertoire actif.

L'option package est un paquet Python ou le nom d'un paquet Python dont le répertoire dont être utilisé comme le répertoire principal pour un nom de fichier dans paths qui soit lié à un module. Si aucun paquet n'est spécifié, le répertoire du module appelé à l'exécution est utilisé comme le répertoire principal pour les noms de fichiers liés au module. C'est une erreur que de spécifier package si module_relative a False comme valeur.

L'option setUp précise une fonction de mise-en-place pour la suite de tests. Ceci est appelé avant l'exécution des tests dans chaque fichier. La fonction setUp est passée à un objet DocTest. La fonction setUp peut accéder aux valeurs globales du test par le biais de l'attribut globs du test passé.

L'option tearDown précise une fonction de démolition pour la suite de tests. Celle-ci est appelée après avoir exécuté les tests dans chaque fichier. La fonction tearDown est passée à un objet DocTest. La fonction setUp peut accéder aux valeurs globales du test par l'attribut globs du test passé.

L'option globs est un dictionnaire contenant les variables globales initiales pour les tests. Une nouvelle copie de ce dictionnaire est créée pour chaque test. Par défaut, globs est un nouveau dictionnaire vide.

Les options optionflags précisent les options par défaut de doctest pour les tests, créées en composant par un OU les différentes options individuelles. Voir la section Options de ligne de commande. Voir la fonction set_unittest_reportflags() ci-dessous pour une meilleure façon de préciser des options de rapport.

L'option parser définit une classe ou une sous-classe DocTestParser qui doit être utilisée pour extraire les tests des fichiers. Par défaut, on utilise un analyseur normal (c'est-à-dire, DocTestParser()).

L'option encoding définit un encodage à utiliser pour convertir le fichier en format unicode.

La valeur globale __file__ est ajoutée aux valeurs globales fournies par les doctests, ceux-ci étant téléchargés d'un fichier texte utilisant la fonction DocFileSuite().

doctest.DocTestSuite(module=None, globs=None, extraglobs=None, test_finder=None, setUp=None, tearDown=None, checker=None)

Convertit les tests doctest pour un module donné à une classe unittest.TestSuite.

La classe renvoyée unittest.TestSuite doit être exécutée par le cadriciel de test unitaire, afin d'exécuter chaque doctest dans le module. Si n'importe lequel des doctests échoue, alors le test unitaire de synthèse échoue, et une exception failureException est levée, affichant le nom du fichier contenant le test et un numéro de ligne pouvant être approximatif.

L'option module fournit le module qui sera testé. Il peut prendre la forme d'un objet-module ou celle du nom d'un module (possiblement dotted). Si non-précisée, le module appelant cette fonction est utilisé.

L'option globs est un dictionnaire contenant les variables globales initiales pour les tests. Une nouvelle copie de ce dictionnaire est créée pour chaque test. Par défaut, globs est un nouveau dictionnaire vide.

L'option extraglobs précise un ensemble supplémentaire de variables globales, à fusionner avec globs. Par défaut, aucune variable globale supplémentaire est utilisée.

L'option test_finder est l'instance de DocTestFinder (ou un remplacement drop-in) qui est utilisée pour extraire les doctests à partir du module.

Les options setUp, tearDown et optionflags sont les mêmes que pour la fonction DocFileSuite() ci-dessus.

Cette fonction utilise la même technique de recherche que testmod().

Modifié dans la version 3.5: La fonction DocTestSuite() renvoie une instance vide de la classe unittest.TestSuite si module ne contient aucune docstring, et ce, au lieu de lever l'exception ValueError.

exception doctest.failureException

When doctests which have been converted to unit tests by DocFileSuite() or DocTestSuite() fail, this exception is raised showing the name of the file containing the test and a (sometimes approximate) line number.

Under the covers, DocTestSuite() creates a unittest.TestSuite out of doctest.DocTestCase instances, and DocTestCase is a subclass of unittest.TestCase. DocTestCase isn't documented here (it's an internal detail), but studying its code can answer questions about the exact details of unittest integration.

Similarly, DocFileSuite() creates a unittest.TestSuite out of doctest.DocFileCase instances, and DocFileCase is a subclass of DocTestCase.

So both ways of creating a unittest.TestSuite run instances of DocTestCase. This is important for a subtle reason: when you run doctest functions yourself, you can control the doctest options in use directly, by passing option flags to doctest functions. However, if you're writing a unittest framework, unittest ultimately controls when and how tests get run. The framework author typically wants to control doctest reporting options (perhaps, e.g., specified by command line options), but there's no way to pass options through unittest to doctest test runners.

Pour cette raison, doctest implémente le concept d'options de rapport de doctest qui soit spécifique à unittest, par le biais de cette fonction :

doctest.set_unittest_reportflags(flags)

Voir les options de ligne de commandes de doctest pour l'utilisation.

L'argument flags prend la composition OU bit à bit des arguments. Voir la section Options de ligne de commande. Ce sont uniquement les "options de rapport" qui peuvent être utilisées.

This is a module-global setting, and affects all future doctests run by module unittest: the runTest() method of DocTestCase looks at the option flags specified for the test case when the DocTestCase instance was constructed. If no reporting flags were specified (which is the typical and expected case), doctest's unittest reporting flags are bitwise ORed into the option flags, and the option flags so augmented are passed to the DocTestRunner instance created to run the doctest. If any reporting flags were specified when the DocTestCase instance was constructed, doctest's unittest reporting flags are ignored.

La valeur prise par les options de rapport de unittest et ce, avant que la fonction n'ait été appelée, est renvoyée par la fonction.

API avancé

The basic API is a simple wrapper that's intended to make doctest easy to use. It is fairly flexible, and should meet most users' needs; however, if you require more fine-grained control over testing, or wish to extend doctest's capabilities, then you should use the advanced API.

The advanced API revolves around two container classes, which are used to store the interactive examples extracted from doctest cases:

  • Example : Un unique statement Python, pris conjointement avec sa sortie attendue.

  • DocTest : Une collection de Example, habituellement extraits d'une seule docstring ou fichier texte.

Additional processing classes are defined to find, parse, and run, and check doctest examples:

The relationships among these processing classes are summarized in the following diagram:

                            list of:
+------+                   +---------+
|module| --DocTestFinder-> | DocTest | --DocTestRunner-> results
+------+    |        ^     +---------+     |       ^    (printed)
            |        |     | Example |     |       |
            v        |     |   ...   |     v       |
           DocTestParser   | Example |   OutputChecker
                           +---------+

Objets doctest

class doctest.DocTest(examples, globs, name, filename, lineno, docstring)

A collection of doctest examples that should be run in a single namespace. The constructor arguments are used to initialize the attributes of the same names.

DocTest définit les attributs suivants. Ils sont initialisés par le constructeur, et ne doivent pas être modifiés directement.

examples

A list of Example objects encoding the individual interactive Python examples that should be run by this test.

globs

The namespace (aka globals) that the examples should be run in. This is a dictionary mapping names to values. Any changes to the namespace made by the examples (such as binding new variables) will be reflected in globs after the test is run.

name

A string name identifying the DocTest. Typically, this is the name of the object or file that the test was extracted from.

filename

The name of the file that this DocTest was extracted from; or None if the filename is unknown, or if the DocTest was not extracted from a file.

lineno

The line number within filename where this DocTest begins, or None if the line number is unavailable. This line number is zero-based with respect to the beginning of the file.

docstring

The string that the test was extracted from, or None if the string is unavailable, or if the test was not extracted from a string.

Exemples d'objets

class doctest.Example(source, want, exc_msg=None, lineno=0, indent=0, options=None)

A single interactive example, consisting of a Python statement and its expected output. The constructor arguments are used to initialize the attributes of the same names.

Example defines the following attributes. They are initialized by the constructor, and should not be modified directly.

source

A string containing the example's source code. This source code consists of a single Python statement, and always ends with a newline; the constructor adds a newline when necessary.

want

The expected output from running the example's source code (either from stdout, or a traceback in case of exception). want ends with a newline unless no output is expected, in which case it's an empty string. The constructor adds a newline when necessary.

exc_msg

The exception message generated by the example, if the example is expected to generate an exception; or None if it is not expected to generate an exception. This exception message is compared against the return value of traceback.format_exception_only(). exc_msg ends with a newline unless it's None. The constructor adds a newline if needed.

lineno

The line number within the string containing this example where the example begins. This line number is zero-based with respect to the beginning of the containing string.

indent

The example's indentation in the containing string, i.e., the number of space characters that precede the example's first prompt.

options

A dictionary mapping from option flags to True or False, which is used to override default options for this example. Any option flags not contained in this dictionary are left at their default value (as specified by the DocTestRunner's optionflags). By default, no options are set.

Objets DocTestFinder

class doctest.DocTestFinder(verbose=False, parser=DocTestParser(), recurse=True, exclude_empty=True)

A processing class used to extract the DocTests that are relevant to a given object, from its docstring and the docstrings of its contained objects. DocTests can be extracted from modules, classes, functions, methods, staticmethods, classmethods, and properties.

The optional argument verbose can be used to display the objects searched by the finder. It defaults to False (no output).

The optional argument parser specifies the DocTestParser object (or a drop-in replacement) that is used to extract doctests from docstrings.

If the optional argument recurse is false, then DocTestFinder.find() will only examine the given object, and not any contained objects.

If the optional argument exclude_empty is false, then DocTestFinder.find() will include tests for objects with empty docstrings.

La classe DocTestFinder définit la méthode suivante :

find(obj[, name][, module][, globs][, extraglobs])

Return a list of the DocTests that are defined by obj's docstring, or by any of its contained objects' docstrings.

The optional argument name specifies the object's name; this name will be used to construct names for the returned DocTests. If name is not specified, then obj.__name__ is used.

The optional parameter module is the module that contains the given object. If the module is not specified or is None, then the test finder will attempt to automatically determine the correct module. The object's module is used:

  • As a default namespace, if globs is not specified.

  • To prevent the DocTestFinder from extracting DocTests from objects that are imported from other modules. (Contained objects with modules other than module are ignored.)

  • Afin de trouver le nom du fichier contenant l'objet.

  • To help find the line number of the object within its file.

If module is False, no attempt to find the module will be made. This is obscure, of use mostly in testing doctest itself: if module is False, or is None but cannot be found automatically, then all objects are considered to belong to the (non-existent) module, so all contained objects will (recursively) be searched for doctests.

The globals for each DocTest is formed by combining globs and extraglobs (bindings in extraglobs override bindings in globs). A new shallow copy of the globals dictionary is created for each DocTest. If globs is not specified, then it defaults to the module's __dict__, if specified, or {} otherwise. If extraglobs is not specified, then it defaults to {}.

Objets DocTestParser

class doctest.DocTestParser

A processing class used to extract interactive examples from a string, and use them to create a DocTest object.

La classe DocTestFinder définit les méthodes suivantes :

get_doctest(string, globs, name, filename, lineno)

Extrait tous les exemples de doctests à partir de la chaîne de caractère donnée, et les réunit dans un objet DocTest.

Notez que globs, name, filname et lineno sont des attributs pour le nouvel objet DocTest. Voir la documentation pour DocTest pour plus d'information.

get_examples(string, name='<string>')

Extract all doctest examples from the given string, and return them as a list of Example objects. Line numbers are 0-based. The optional argument name is a name identifying this string, and is only used for error messages.

parse(string, name='<string>')

Divide the given string into examples and intervening text, and return them as a list of alternating Examples and strings. Line numbers for the Examples are 0-based. The optional argument name is a name identifying this string, and is only used for error messages.

Objets DocTestRunner

class doctest.DocTestRunner(checker=None, verbose=None, optionflags=0)

A processing class used to execute and verify the interactive examples in a DocTest.

The comparison between expected outputs and actual outputs is done by an OutputChecker. This comparison may be customized with a number of option flags; see section Options de ligne de commande for more information. If the option flags are insufficient, then the comparison may also be customized by passing a subclass of OutputChecker to the constructor.

The test runner's display output can be controlled in two ways. First, an output function can be passed to TestRunner.run(); this function will be called with strings that should be displayed. It defaults to sys.stdout.write. If capturing the output is not sufficient, then the display output can be also customized by subclassing DocTestRunner, and overriding the methods report_start(), report_success(), report_unexpected_exception(), and report_failure().

The optional keyword argument checker specifies the OutputChecker object (or drop-in replacement) that should be used to compare the expected outputs to the actual outputs of doctest examples.

The optional keyword argument verbose controls the DocTestRunner's verbosity. If verbose is True, then information is printed about each example, as it is run. If verbose is False, then only failures are printed. If verbose is unspecified, or None, then verbose output is used iff the command-line switch -v is used.

The optional keyword argument optionflags can be used to control how the test runner compares expected output to actual output, and how it displays failures. For more information, see section Options de ligne de commande.

DocTestRunner defines the following methods:

report_start(out, test, example)

Report that the test runner is about to process the given example. This method is provided to allow subclasses of DocTestRunner to customize their output; it should not be called directly.

example is the example about to be processed. test is the test containing example. out is the output function that was passed to DocTestRunner.run().

report_success(out, test, example, got)

Report that the given example ran successfully. This method is provided to allow subclasses of DocTestRunner to customize their output; it should not be called directly.

example is the example about to be processed. got is the actual output from the example. test is the test containing example. out is the output function that was passed to DocTestRunner.run().

report_failure(out, test, example, got)

Report that the given example failed. This method is provided to allow subclasses of DocTestRunner to customize their output; it should not be called directly.

example is the example about to be processed. got is the actual output from the example. test is the test containing example. out is the output function that was passed to DocTestRunner.run().

report_unexpected_exception(out, test, example, exc_info)

Report that the given example raised an unexpected exception. This method is provided to allow subclasses of DocTestRunner to customize their output; it should not be called directly.

example is the example about to be processed. exc_info is a tuple containing information about the unexpected exception (as returned by sys.exc_info()). test is the test containing example. out is the output function that was passed to DocTestRunner.run().

run(test, compileflags=None, out=None, clear_globs=True)

Run the examples in test (a DocTest object), and display the results using the writer function out.

The examples are run in the namespace test.globs. If clear_globs is true (the default), then this namespace will be cleared after the test runs, to help with garbage collection. If you would like to examine the namespace after the test completes, then use clear_globs=False.

compileflags gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to globs.

The output of each example is checked using the DocTestRunner's output checker, and the results are formatted by the DocTestRunner.report_*() methods.

summarize(verbose=None)

Print a summary of all the test cases that have been run by this DocTestRunner, and return a named tuple TestResults(failed, attempted).

The optional verbose argument controls how detailed the summary is. If the verbosity is not specified, then the DocTestRunner's verbosity is used.

Objets OutputChecker

class doctest.OutputChecker

A class used to check the whether the actual output from a doctest example matches the expected output. OutputChecker defines two methods: check_output(), which compares a given pair of outputs, and returns True if they match; and output_difference(), which returns a string describing the differences between two outputs.

La classe OutputChecker définit les méthodes suivantes :

check_output(want, got, optionflags)

Return True iff the actual output from an example (got) matches the expected output (want). These strings are always considered to match if they are identical; but depending on what option flags the test runner is using, several non-exact match types are also possible. See section Options de ligne de commande for more information about option flags.

output_difference(example, got, optionflags)

Return a string describing the differences between the expected output for a given example (example) and the actual output (got). optionflags is the set of option flags used to compare want and got.

Débogage

Doctest fournit plusieurs mécanismes pour déboguer des exemples doctest :

  • Plusieurs fonctions convertissent les doctests en programmes Python exécutables, qui peuvent être exécutés grâce au débogueur Python, pdb.

  • The DebugRunner class is a subclass of DocTestRunner that raises an exception for the first failing example, containing information about that example. This information can be used to perform post-mortem debugging on the example.

  • The unittest cases generated by DocTestSuite() support the debug() method defined by unittest.TestCase.

  • You can add a call to pdb.set_trace() in a doctest example, and you'll drop into the Python debugger when that line is executed. Then you can inspect current values of variables, and so on. For example, suppose a.py contains just this module docstring:

    """
    >>> def f(x):
    ...     g(x*2)
    >>> def g(x):
    ...     print(x+3)
    ...     import pdb; pdb.set_trace()
    >>> f(3)
    9
    """
    

    Alors une séance interactive de Python peut ressembler à ceci :

    >>> import a, doctest
    >>> doctest.testmod(a)
    --Return--
    > <doctest a[1]>(3)g()->None
    -> import pdb; pdb.set_trace()
    (Pdb) list
      1     def g(x):
      2         print(x+3)
      3  ->     import pdb; pdb.set_trace()
    [EOF]
    (Pdb) p x
    6
    (Pdb) step
    --Return--
    > <doctest a[0]>(2)f()->None
    -> g(x*2)
    (Pdb) list
      1     def f(x):
      2  ->     g(x*2)
    [EOF]
    (Pdb) p x
    3
    (Pdb) step
    --Return--
    > <doctest a[2]>(1)?()->None
    -> f(3)
    (Pdb) cont
    (0, 3)
    >>>
    

Functions that convert doctests to Python code, and possibly run the synthesized code under the debugger:

doctest.script_from_examples(s)

Convertit du texte contenant des exemples en un script.

Argument s is a string containing doctest examples. The string is converted to a Python script, where doctest examples in s are converted to regular code, and everything else is converted to Python comments. The generated script is returned as a string. For example,

import doctest
print(doctest.script_from_examples(r"""
    Set x and y to 1 and 2.
    >>> x, y = 1, 2

    Print their sum:
    >>> print(x+y)
    3
"""))

displays:

# Set x and y to 1 and 2.
x, y = 1, 2
#
# Print their sum:
print(x+y)
# Expected:
## 3

Cette fonction est utilisée à l'interne par d'autres fonctions (voir ci-bas), mais peut aussi être utile lorsque l'on souhaite transformer une séance interactive de Python en script Python.

doctest.testsource(module, name)

Convertit en script l'objet doctest.

Argument module is a module object, or dotted name of a module, containing the object whose doctests are of interest. Argument name is the name (within the module) of the object with the doctests of interest. The result is a string, containing the object's docstring converted to a Python script, as described for script_from_examples() above. For example, if module a.py contains a top-level function f(), then

import a, doctest
print(doctest.testsource(a, "a.f"))

prints a script version of function f()'s docstring, with doctests converted to code, and the rest placed in comments.

doctest.debug(module, name, pm=False)

Débogue les doctests pour un objet.

The module and name arguments are the same as for function testsource() above. The synthesized Python script for the named object's docstring is written to a temporary file, and then that file is run under the control of the Python debugger, pdb.

Une copie superficielle de module.__dict__ est utilisée à la fois pour les contextes d'exécution locaux et globaux.

Optional argument pm controls whether post-mortem debugging is used. If pm has a true value, the script file is run directly, and the debugger gets involved only if the script terminates via raising an unhandled exception. If it does, then post-mortem debugging is invoked, via pdb.post_mortem(), passing the traceback object from the unhandled exception. If pm is not specified, or is false, the script is run under the debugger from the start, via passing an appropriate exec() call to pdb.run().

doctest.debug_src(src, pm=False, globs=None)

Débogue les doctests dans une chaîne de caractères.

Ceci est similaire à la fonction debug() décrite ci-haut, mis-à-part qu'une chaîne de caractères contenant des exemples doctest est définie directement, par l'option src.

L'option pm a la même définition que dans la fonction debug() ci-haut.

L'option globs définit un dictionnaire à utiliser comme contexte d'exécution global et local. Si elle n'est pas définie, ou si None, un dictionnaire vide est utilisé. Si définie, une copie superficielle du dictionnaire est utilisée.

The DebugRunner class, and the special exceptions it may raise, are of most interest to testing framework authors, and will only be sketched here. See the source code, and especially DebugRunner's docstring (which is a doctest!) for more details:

class doctest.DebugRunner(checker=None, verbose=None, optionflags=0)

A subclass of DocTestRunner that raises an exception as soon as a failure is encountered. If an unexpected exception occurs, an UnexpectedException exception is raised, containing the test, the example, and the original exception. If the output doesn't match, then a DocTestFailure exception is raised, containing the test, the example, and the actual output.

Pour de l'information sur les paramètres et méthodes du constructeur, voir la documentation pour la classe DocTestrunner dans la section API avancé.

Il y a deux exceptions qui peuvent être levées par des instances DebugRunner :

exception doctest.DocTestFailure(test, example, got)

Une exception levée par DocTestRunner pour signaler que la sortie obtenue suite à un exemple doctest ne correspond pas à la sortie attendue. Les arguments du constructeur sont utilisés pour initialiser les attributs des mêmes noms.

DocTestFailure définit les attributs suivants :

DocTestFailure.test

L'objet issu de la classe DocTest qui était en cours d'exécution lorsque l'exemple a échoué.

DocTestFailure.example

L'exemple Example qui a échoué.

DocTestFailure.got

La sortie obtenue par l'exécution de l'exemple.

exception doctest.UnexpectedException(test, example, exc_info)

Une exception levée par DocTestRunner afin de signaler qu'un exemple doctest a levé une exception inattendue. Les arguments du constructeur sont utilisés pour initialiser les attributs des mêmes noms.

UnexpectedException définit les attributs suivants :

UnexpectedException.test

L'objet issu de la classe DocTest qui était en cours d'exécution lorsque l'exemple a échoué.

UnexpectedException.example

L'exemple Example qui a échoué.

UnexpectedException.exc_info

Un n-uplet contenant l'information au sujet de l'exception inattendue, telle que retourné par sys.exc_info().

Éditorial

Comme mentionné dans l'introduction, doctest a présentement trois usages principaux :

  1. Vérifier les exemples dans les docstrings.

  2. Test de régression.

  3. De la documentation exécutable / des tests littéraires.

These uses have different requirements, and it is important to distinguish them. In particular, filling your docstrings with obscure test cases makes for bad documentation.

When writing a docstring, choose docstring examples with care. There's an art to this that needs to be learned---it may not be natural at first. Examples should add genuine value to the documentation. A good example can often be worth many words. If done with care, the examples will be invaluable for your users, and will pay back the time it takes to collect them many times over as the years go by and things change. I'm still amazed at how often one of my doctest examples stops working after a "harmless" change.

Doctest also makes an excellent tool for regression testing, especially if you don't skimp on explanatory text. By interleaving prose and examples, it becomes much easier to keep track of what's actually being tested, and why. When a test fails, good prose can make it much easier to figure out what the problem is, and how it should be fixed. It's true that you could write extensive comments in code-based testing, but few programmers do. Many have found that using doctest approaches instead leads to much clearer tests. Perhaps this is simply because doctest makes writing prose a little easier than writing code, while writing comments in code is a little harder. I think it goes deeper than just that: the natural attitude when writing a doctest-based test is that you want to explain the fine points of your software, and illustrate them with examples. This in turn naturally leads to test files that start with the simplest features, and logically progress to complications and edge cases. A coherent narrative is the result, instead of a collection of isolated functions that test isolated bits of functionality seemingly at random. It's a different attitude, and produces different results, blurring the distinction between testing and explaining.

Regression testing is best confined to dedicated objects or files. There are several options for organizing tests:

  • Write text files containing test cases as interactive examples, and test the files using testfile() or DocFileSuite(). This is recommended, although is easiest to do for new projects, designed from the start to use doctest.

  • Define functions named _regrtest_topic that consist of single docstrings, containing test cases for the named topics. These functions can be included in the same file as the module, or separated out into a separate test file.

  • Define a __test__ dictionary mapping from regression test topics to docstrings containing test cases.

Lorsque vous placez vos tests dans un module, le module lui-même peut être l'exécuteur de tests. Lorsqu'un test échoue, vous pouvez signifier à votre exécuteur de tests de rouler une seconde fois uniquement les tests qui échouent et ce, tant que vous travaillez sur le problème. Voici un exemple minimal d'un test exécuteur de tests :

if __name__ == '__main__':
    import doctest
    flags = doctest.REPORT_NDIFF|doctest.FAIL_FAST
    if len(sys.argv) > 1:
        name = sys.argv[1]
        if name in globals():
            obj = globals()[name]
        else:
            obj = __test__[name]
        doctest.run_docstring_examples(obj, globals(), name=name,
                                       optionflags=flags)
    else:
        fail, total = doctest.testmod(optionflags=flags)
        print("{} failures out of {} tests".format(fail, total))

Notes