skip to content

questions

4

What does Python's doctest module treat as a test inside a docstring?

level: juniorimportance: must knowfreq 40%

answer

  1. Executable documentation, not an assertion API
  2. The REPL prompt marks the example
  3. Expected output stops at a blank line
  4. Exact stdout text, echoed repr included
  5. Traceback header plus final exception line

basics

~20 s

Any docstring line that starts with the >>> prompt. doctest runs that statement and compares whatever it prints to standard output against the lines beneath it, character for character, up to the first blank line.

solid answer

~50 s

`doctest` parses docstrings — and plain text files — looking for interactive-session blocks: a line starting with `>>> `, optional `... ` continuation lines, and the expected output on the lines that follow, ending at a blank line or the next prompt. It executes each example in a namespace seeded from the module's globals, captures standard output, and compares that captured text with the expected block as an **exact string match** — not as an equality assertion. So the echoed value is compared as its `repr`: `>>> "ok"` must be followed by `'ok'` with quotes. An example with no expected output asserts that the statement prints nothing, which is why `>>> bids = [4, 2]` passes and binds a name for the next example. Expected exceptions are written as a `Traceback (most recent call last):` header, an ignored body, and the final exception line.

code

python · 18 lines
python
import doctest


def bid_floor(bids):
    """Return the lowest live bid in an auction.

    >>> bid_floor([4, 2, 9])
    2
    >>> bid_floor([])
    Traceback (most recent call last):
        ...
    ValueError: min() iterable argument is empty
    """
    return min(bids)


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

go deeper

for a junior

Be ready to point at a >>> line in a docstring and say what doctest will do with it: run it and compare the printed text below it exactly. Knowing that strings show their quotes is the detail interviewers check.

for a middle

Explain the mechanics: stdout capture, the repr echo, the blank-line terminator and <BLANKLINE>, and the fact that examples in one docstring share a namespace in order. Know that only the traceback header and final exception line are compared.

for a senior

Show you can read a doctest failure report quickly — distinguish the genuine failure from the cascading NameErrors it caused downstream in the same docstring, and say which examples in a codebase deserve to be doctests at all.

for a principal

Own the position that a doctest's real contract is with the reader, not the build: argue for where exact-output matching is a feature that keeps documentation honest and where it becomes coupling the organisation pays for on every refactor.

### doctest is a transcript checker, not an assertion framework `doctest` is a standard-library module that finds interactive-interpreter transcripts in text and runs them. It has no `assert` API, it does not collect functions named `test_*`, and it does not know anything about your test classes. It reads the `__doc__` string of a module, and of the classes, functions and methods defined in it — or a plain text file — and looks for the shape of a REPL session. ### The grammar of an example An **example** is three things in sequence: 1. a *source* line that begins with the prompt `>>> ` (three chevrons and one space), 2. zero or more *continuation* lines that begin with `... `, for multi-line statements, 3. the *expected output*: every line that follows, up to the first blank line or the next `>>>` prompt. Everything is measured relative to the indentation of the prompt, which is what lets an example sit inside an already-indented docstring without the leading spaces becoming part of the expected text. ### What "passing" means For each example doctest compiles the source, executes it in a namespace, and captures everything written to standard output while it runs — **including the value the REPL would echo**, which is that value's `repr()`. It then compares the captured text with the expected block as a **string**. Not `==`, not `assertEqual`: text. Four consequences follow directly, and each one is a real interview probe: * `>>> "ok"` must be followed by `'ok'` **with quotes**, because that is what `repr` prints. A bare `ok` fails. * An example with an *empty* expected block asserts that the statement prints nothing. `>>> bids = [4, 2]` passes silently and binds a name; `>>> bids` on the next line must be followed by `[4, 2]`. * Trailing spaces, line wrapping and the ordering of everything printed all matter, which is why `NORMALIZE_WHITESPACE` exists. * A genuinely blank line cannot appear inside expected output, because a blank line is the terminator. doctest reserves the marker `<BLANKLINE>` for it, and `DONT_ACCEPT_BLANKLINE` turns that convenience off. ### Expected exceptions An example may expect an exception. The expected block is written as the header line `Traceback (most recent call last):`, then an optional body, then the final `ExceptionType: message` line. The body is **ignored entirely** — you may paste real frames, write `...`, or leave it out — while the header and the final line are compared. That is a deliberate design choice: stack frames are file- and line-dependent, so pinning them would make every example fragile. The exception *message* is still compared, and `IGNORE_EXCEPTION_DETAIL` relaxes that down to the exception class when a message is likely to change. ### One namespace per docstring, shared in order All examples in a single docstring execute in the same globals mapping, in order, seeded with a shallow copy of the defining module's globals. That is what lets a docstring read like a session: an earlier example binds `live = sorted(...)` and a later one uses it. Two consequences worth naming out loud: * examples in a docstring are **order-dependent**; you cannot reorder them freely, and you cannot run one in isolation; * after a failure doctest keeps going (unless `FAIL_FAST` is set), so an example that raises unexpectedly leaves its name unbound and the following examples fail with `NameError` — one real defect can print as five failures. Different docstrings do **not** share state. Each gets its own copy of the module globals, so a name bound in one function's docstring is invisible in another's. ### Where doctest looks `doctest.testmod()` walks the module's own docstring plus the docstrings of the functions, classes and methods it defines, skipping objects that were imported from elsewhere. `doctest.testfile()` does the same for a text file, where the whole file is prose and the `>>>` blocks are the tests. Per-example behaviour is tuned with a directive comment on the source line — `# doctest: +ELLIPSIS`, `# doctest: +SKIP` — and run-wide behaviour with the `optionflags` argument or the `-o` command-line option. ### Why the exactness is both the feature and the price The whole value proposition is that a doctest **is** the documentation. A reader copies the example into a REPL and gets what the docstring promised, because the suite would have failed otherwise. Documentation cannot silently drift from behaviour. The identical property is the cost: an example whose printed form is not stable — a float carrying representation error, a set whose order depends on the hash seed, an object whose default `repr` embeds its address — fails for reasons that have nothing to do with correctness. That trade is the thing to understand before choosing where to use it.

  • Why must the example `>>> "ok"` be followed by `'ok'` with the quotes shown?
    Because doctest captures what the interactive interpreter would print, and the interpreter echoes a non-None expression value by its `repr`. The repr of a string includes quotes, so `'ok'` is the correct expected text and a bare `ok` fails the string comparison.
  • How do you write an example whose expected output contains a blank line?
    Write the marker `<BLANKLINE>` on that line. A real blank line would terminate the expected block, so doctest substitutes the marker when comparing. The `DONT_ACCEPT_BLANKLINE` option flag disables the convenience if you need a literal `<BLANKLINE>` in the output.
  • What happens to the examples that follow a failing one in the same docstring?
    They still run, in the same shared namespace, unless `FAIL_FAST` is set. So an example that raises unexpectedly leaves its name unbound and every later example using that name fails with `NameError` — one defect can surface as several failures, and you should read the first one.

A doctest is a transcript, not an assertion. doctest replays the session you pasted into the docstring and checks that the printout comes back word for word.

saying these in an interview costs you the question

  • Says doctest compares values with == rather than text
  • Thinks doctest collects functions named test_*
  • Omits the repr quotes on an expected string result
  • Assumes a blank line can sit inside expected output
  • Believes each example gets a fresh namespace
  • Thinks an example with no output line is skipped

context

open as a page

Why is a doctest brittle when its example prints a float, a set or a default repr?

level: middleimportance: should knowfreq 34%

basics

~20 s

Because doctest matches printed text exactly. 0.10 + 0.20 prints 0.30000000000000004, set order depends on the hash seed, and a default repr embeds a memory address, so the example fails for reasons unrelated to the code being correct.

open as a page

How do you run a module's doctests with doctest.testmod, python -m doctest or unittest?

level: middleimportance: should knowfreq 32%

basics

~20 s

Call doctest.testmod() inside the module to run its own docstring examples, run python -m doctest on a .py or text file from the shell, or add doctest.DocTestSuite() in a load_tests function so a normal unittest run reports them.

open as a page

When do doctests earn their place, and when should a dedicated unit test replace them?

level: seniorimportance: should knowfreq 26%

basics

~20 s

Doctests earn their place when the example is documentation first: a short, pure, deterministic call whose printed form is stable. Anything needing tolerance, fixtures, patching or many input cases belongs in a dedicated test instead.

open as a page