How Python doctest Runs Tests in Docstrings
Python’s built-in doctest module scans your code's
documentation strings (docstrings), extracts snippets that look like
interactive Python sessions, executes them, and verifies that the output
matches the documented results. By treating documentation examples as
automated tests, it ensures that your API reference remains both
accurate and functional with minimal setup.
How doctest Identifies and Parses Tests
The doctest module searches through modules, classes,
methods, and functions to inspect their docstrings. It looks
specifically for lines prefixed with the standard Python interactive
prompt:
>>>denotes the primary prompt containing code expressions or statements to evaluate....denotes continuation lines for multiline statements, loops, or function definitions.
Any text immediately following a line or block of
>>> inputs—up to the next prompt, an empty line,
or the end of the docstring—is treated as the expected output.
def add(a, b):
"""
Return the sum of a and b.
>>> add(2, 3)
5
>>> add(-1, 1)
0
"""
return a + bIn this example, doctest identifies two separate tests:
add(2, 3) with an expected output of 5, and
add(-1, 1) with an expected output of 0.
The Execution Mechanism
Once doctest parses the code snippets and their expected
outputs, it runs them through an automated execution pipeline:
- Namespace Isolation: By default,
doctestcreates a shallow copy of the target module's global namespace, ensuring tests can access the functions, classes, and imported modules defined in that file. - Evaluation: The extracted code is executed
dynamically using Python's runtime evaluation mechanisms
(
exec()for statements andeval()for expressions). - Stream Interception: Standard output
(
sys.stdout) is intercepted during execution so that any returned values or printed text are captured as raw strings. - Exception Handling: If an example expects an error,
doctestlooks for a traceback header (Traceback (most recent call last):) followed by the exception type and message. It checks whether the raised exception matches the documented behavior.
Output Comparison and Directives
doctest performs an exact string comparison between the
captured output and the expected output in the docstring. A test passes
only if the actual output matches character-for-character, including
whitespace and line breaks.
To handle dynamic or variable outputs, doctest supports
inline directives that modify comparison rules:
+NORMALIZE_WHITESPACE: Collapses multiple spaces, tabs, and newlines into single spaces, making tests resilient to formatting variations.+ELLIPSIS: Allows the use of...inside expected output to act as a wildcard matching any substring, which is useful for memory addresses, object representations, or timestamps.+SKIP: Tellsdoctestto skip running a specific test block entirely.
def get_user():
"""
>>> get_user() # doctest: +ELLIPSIS
<User object at 0x...>
"""
passRunning doctests
You can execute docstring tests directly from the command line without modifying your source code:
python -m doctest -v script.pyThe -v (verbose) flag displays every test executed and
whether it passed or failed. Without the flag, doctest runs
silently and only prints output if a test fails.
Alternatively, you can trigger execution within the script itself by adding a standard entry point:
if __name__ == "__main__":
import doctest
doctest.testmod()When run as a standalone script, doctest.testmod()
inspects the current module's docstrings, executes all embedded
sessions, and reports failures to standard error.