An introduction to doctest2 for existing users of doctest

The doctest2 module searches for pieces of text that look like interactive sessions, and executes them to verify that they behave as shown in the session. Here are some ways doctest2‘s predecessor, doctest, has been used in the past:

  • To write tutorial documentation for a package, liberally illustrated with input-output examples. Depending on whether the examples or the expository text are emphasized, this has the flavor of “literate testing” or “executable documentation”.
  • To check that a module’s docstrings are up-to-date by verifying that all interactive examples still work as documented.
  • To perform regression testing by verifying that interactive examples from a test file or a test object work as expected.

Unlike doctest, doctest2 supports more than just Python. It also supports Unix sh and Windows cmd, and will support other languages in the future.

Backwards compatibility

By and large, doctest2 is backwards compatible. All, or nearly all, examples should be tested and compared in the same way. In cases where they are run differently, doctest2 aims to be “better”, and never break anything. (However, some tests that failed before – incorrectly – may pass under doctest2)

Running

To run doctest2 on a file, use python -m doctest2 my_file, or use the invocation API specified later below.

New features

Python literal evaluation

The classic failure case of doctest is that dicts aren’t ordered, so that the following doctest may fail:

>>> {-1: 0, 1: 2}
{-1: 0, 1: 2}

doctest2 adds a Python literal evaluation mode which takes the entire output of a function, and the expected output, and parses each as a Python literal. In this way, the example is less fragile:

>>> {-1: 0, 1: 2} 
{-1: 0, 1: 2}

Session-wide doctest options

Often a certain option will be common throughout an entire example session, or a large part of it. doctest2 adds session-global doctest options. Where regular options are given as +FOO, global options are given as +!FOO. For example:

>>> 1 
2
>>> 1/0
>>> 0/0 # this is the last skipped doctest before...
>>> 1 
1

Exceptions and output

One of the more noticeable omissions in doctest is the inability to write a testable example of using a function that prints some output before it raises an exception. doctest2 allows you to specify both output _and_ exception:

>>> print('Hello, world!'); 1/0
Hello, world!
Traceback (most recent call last):
  ...
ZeroDivisionError: integer division or modulo by zero

From Python to sh

The most significant addition doctest2 makes to doctest is the ability to test more than just Python interactive sessions. doctest2 can also test example shell sessions, too!

Doctest directives look something like this:

>>> print(1)
1

This could be copy-pasted from an interactive Python session. When passed to doctest2, doctest2 executes the statement print(1) and checks whether the output is 1.

Extending over to multiple lines is done the same as in the interactive interpreter:

>>> print(
... 1)
1

doctest2‘s biggest change is that interactive sessions are no longer limited to Python. In particular, POSIX sh and Windows cmd have been added, and both use a different prompt value. Where Python doctests use >>> and ..., sh doctests use $ and >, and cmd doctests use cmd> and ?. For example:

$ python3 -c "print(1)"
1
cmd> python3 -c "print(1)"
1

This does a similar check, but runs it against sh and cmd.

Note

cmd support is a little shaky, and probably always will be. Even the lowest common denominator shell, sh, offers some features that cmd does not. (For example: inline comments, and parsing error detection)

Specifying languages to doctest2

When requesting that doctest2 run a file to test, the languages that are to be tested must also be tested. In general, doctest2 will default to checking as many language as it knows about. If only _some_ should be tested, doctest2 needs to know which ones.

The doctest2.languages package contains the various languages doctest can understand. For now, that is python (specifically, Python 3.x), sh, and cmd. Each language is represented by an object that doctest2 can use to handle doctests in that language (doctest2.languages.sh, doctest2.languages.cmd, doctest2.languages.python). A list of all available language objects is available at doctest2.languages.languages.

The move to supporting multiple languages comes with some cost in flexibility. In doctest, every doctest function accepted an instantiated finder or parser parameter that emulated doctest2.DocTestFinder or doctest2.DocTestParser respectively. This doesn’t work in doctest2, because these classes don’t know how different languages parse.

In addition some arguments that used to make sense for all doctests only make sense for some. The globs parameter does not make sense for and isn’t used for shell tests. This will be changed around in the future.

The updated Python invocation API

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

Test examples in docstrings reachable from module m, starting with m.__doc__. Also test examples reachable from dict m.__test__ if it exists and is not None.

m.__test__ maps names to functions, classes and strings; function and class docstrings are tested even if the name is private; strings are tested directly, as if they were docstrings.

Parameters:
  • m (module) – module to be inspected / tested (defaults to __main__)
  • name (str) – name to call module by in reports (defaults to m.__name__)
  • globs (dict) –

    globals dict used inside doctests (defaults to m.__dict__)

    Each doctest is run inside a shallow copy of globs. Only used in Python doctests.

  • extraglobs (dict) – extra globals to merge into the globals dict
  • verbose (bool) – verbosity flag. When true, more report information will be sent to stdout. (defaults to '-v' in sys.argv)
  • report (bool) – When true, a summary will be printed at the end. The verbosity of the summary depends on verbose
  • optionflags (int) – Options for the doctest runner such as doctest2.ELLIPSIS (defaults to 0, i.e. no options)
  • raise_on_error (bool) – When true, an exception will be raised if ever a doctest fails or raises an unexpected exception. This allows for post-mortem debugging.
  • exclude_empty (bool) – When false, empty tests will be generated for objects with empty docstrings.
  • languages (language) – iterable of languages to test (defaults to all)
Returns:

(num_failures, num_attempts)

Return type:

tuple of (int, int)

Raises :

doctest2.DocTestFailure when raise_on_error is enabled and a doctest fails.

Raises :

doctest2.UnexpectedException when raise_on_error is enabled and a doctest raises an exception that wasn’t expected.

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

Test examples in the given file.

Parameters:
  • filename (str) – file to be inspected / tested)
  • encoding (str) – encoding of file (defaults to "utf-8")
  • module_relative (bool) –
    • If True, then the filename is relative to the current module (or package, if the package argument is provided).
    • If False, the filename is relative to the current working directory (or absolute)

    (defaults to True)

  • name (bool) – name to call file by in reports (defaults to m.__name__)
  • package (str) – package used for the base of the filename. If this is provided, then the file is package data. It is an error to provide this argument without module_relative being True.
  • globs (dict) –

    globals dict used inside doctests (defaults to m.__dict__)

    Each doctest is run inside a shallow copy of globs. Only used in Python doctests.

  • extraglobs (dict) – extra globals to merge into the globals dict
  • verbose (bool) – verbosity flag. When true, more report information will be sent to stdout. (defaults to '-v' in sys.argv)
  • report (bool) – When true, a summary will be printed at the end. The verbosity of the summary depends on verbose
  • optionflags (int) – Options for the doctest runner such as doctest2.ELLIPSIS (defaults to 0, i.e. no options)
  • raise_on_error (bool) – When true, an exception will be raised if ever a doctest fails or raises an unexpected exception. This allows for post-mortem debugging.
  • exclude_empty (bool) – When false, empty tests will be generated for objects with empty docstrings.
  • languages (language) – iterable of languages to test (defaults to all)
Returns:

(num_failures, num_attempts)

Return type:

tuple of (int, int)

Raises :

doctest2.DocTestFailure when raise_on_error is enabled and a doctest fails.

Raises :

doctest2.UnexpectedException when raise_on_error is enabled and a doctest raises an exception that wasn’t expected.

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

Test examples in the given object’s docstring (f), without recursing into attributes.

Parameters:
  • f (object) – Object with a __doc__ atribute to be tested.
  • globs (dict) –

    globals dict used inside doctests (defaults to m.__dict__)

    Each doctest is run inside a shallow copy of globs. Only used in Python doctests.

  • extraglobs (dict) – extra globals to merge into the globals dict
  • verbose (bool) – verbosity flag. When true, more report information will be sent to stdout. (defaults to '-v' in sys.argv)
  • name (bool) – name to call file by in reports (defaults to "NoName")
  • compileflags (flag) – the set of flags that should be used by the Python compiler when running the examples. (defaults to the set of future-import flags that apply to globs.)
  • optionflags (int) – Options for the doctest runner such as doctest2.ELLIPSIS (defaults to 0, i.e. no options)
  • languages (language) – iterable of languages to test (defaults to all)
Returns:

(num_failures, num_attempts)

Return type:

tuple of (int, int)