Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Python  Module 12 – Testing, debugging and code quality

doctest: examples that test themselves

Write doctests in docstrings, run them with python -m doctest and testmod(), and keep them passing when output changes, as with sets and object reprs.

  • Intermediate
  • 20 minutes
  • Examples run with Python 3.14.8 and Pyodide 314.0.7
  • By MySmartCoPilot
Free core, Pro depth: 8 of 20 minutes free
Free: A doctest is a shell example and the text it should print · doctest is silent until an example disagrees · Any difference in the text fails an example, even when the code is right · Check yourself. With a pass: 2 in-depth parts and 3 interview answers, about 12 minutes.

What you will learn

  • Write doctests, including an expected exception, inside docstrings
  • Run doctests from the command line and from code, and read a failure report
  • Fix doctests whose output varies between runs, such as sets and memory addresses
  • Run doctests together with unit tests and check the examples of a README
  • Decide when a check belongs in a doctest and when in a unit test

Before you start

What you’ll learn · Before you start

What you will learn

  • Write doctests, including an expected exception, inside docstrings
  • Run doctests from the command line and from code, and read a failure report
  • Fix doctests whose output varies between runs, such as sets and memory addresses
  • Run doctests together with unit tests and check the examples of a README
  • Decide when a check belongs in a doctest and when in a unit test

Before you start

On this page

A docstring: A string written as the first statement of a module, class or function. Python keeps it as the object's __doc__ attribute, which help(), editors and doctest read. More in “Docstrings, comments and PEP 8 style” promises that inr(1234567) gives '₹12,34,567'; a later change to the code makes it give '₹1,234,567', and the documentation goes on promising the old answer. doctest, a module of Python’s standard library, catches that drift: it searches docstrings for text that looks like a session in the interactive shell, a line starting with >>> followed by what the shell printed, runs each example and checks that it prints exactly that text.

Your examples then do two jobs: they show readers how to call the function, and they fail as soon as the code stops doing what the documentation says. doctest suits small, pure functions and the examples of a module’s documentation; checks that need setup, many cases or large data belong in unittest or pytest, the next lessons of this module. Below, doctest checks five examples step by step, catches a stale one and fails two right functions on their text.

A doctest is a shell example and the text it should print

A function that splits a restaurant bill in paise, with five examples in its docstring and, at the bottom, a call that runs them and reports each one:

A docstring with five doctests, including an expected exception Python · split/bill.py
"""Split a restaurant bill in paise, so that the shares always add up to the total."""


def split_bill(total_paise, people):
    """Return each person's share in paise; the first shares carry the paise left over.

    >>> split_bill(900_00, 3)
    [30000, 30000, 30000]
    >>> split_bill(100_00, 3)
    [3334, 3333, 3333]
    >>> sum(split_bill(100_00, 3))
    10000
    >>> split_bill(1, 4)
    [1, 0, 0, 0]
    >>> split_bill(500, 0)
    Traceback (most recent call last):
      ...
    ValueError: people must be at least 1, not 0
    """
    if people < 1:
        raise ValueError(f"people must be at least 1, not {people}")
    share, left_over = divmod(total_paise, people)
    return [share + 1 if i < left_over else share for i in range(people)]


if __name__ == "__main__":
    import doctest

    doctest.run_docstring_examples(split_bill, globals(), verbose=True, name="split_bill")

Output

Finding tests in split_bill
Trying:
    split_bill(900_00, 3)
Expecting:
    [30000, 30000, 30000]
ok
Trying:
    split_bill(100_00, 3)
Expecting:
    [3334, 3333, 3333]
ok
Trying:
    sum(split_bill(100_00, 3))
Expecting:
    10000
ok
Trying:
    split_bill(1, 4)
Expecting:
    [1, 0, 0, 0]
ok
Trying:
    split_bill(500, 0)
Expecting:
    Traceback (most recent call last):
      ...
    ValueError: people must be at least 1, not 0
ok

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 bill.py

Each example is a >>> line, plus ... lines when a statement continues, followed by the expected output, which runs until a blank line or the next >>>. The expected output is what the interactive shell would show: the repr() of an expression’s value, or whatever the code prints. An expected exception starts with the line Traceback (most recent call last):; doctest ignores the stack after it, usually written as ..., and compares the last line, the exception’s type and message.

Here is what doctest does with each example:

doctest finds each >>> example in a docstring, runs it, captures what the shell would print and compares that text with the expected lines.Docstring text>>> split_bill(100_00, 3)[3334, 3333, 3333]Find each example: a >>> line,any ... lines, then the expected outputRun the code in a copyof the module's globalsCapture what the shell would print:print() output, or the repr of the valueCompare as text with theexpected lines (option flags relax it)Same text: okDifferent: Failed example,Expected and Got

How doctest checks one example

Text description of the diagram

The diagram is a flow of five steps from top to bottom, ending in two outcomes.

  1. The docstring holds an example: the line >>> split_bill(100_00, 3) followed by the expected output [3334, 3333, 3333].
  2. doctest finds each example: a line starting with >>>, any continuation lines starting with ..., and the expected output, which runs up to the next blank line or the next >>>.
  3. It runs the code in a copy of the module's global names, so examples see the module's functions but do not change them.
  4. It captures what the interactive shell would print: anything passed to print(), or the repr of the value of an expression.
  5. It compares that text with the expected lines, character for character, unless option flags relax the comparison.

If the texts are the same, the example is ok. If they differ, doctest reports a failed example with the expected and the actual output.

Step through the same loop on the five examples of split_bill, as the run above printed them:

Interactive · stage by stage doctest checks the five examples of split_bill Step through the run of bill.py. Each pass of the loop takes one example, runs it and compares what it printed with the expected lines.
doctest checks the five examples of split_bill, step 9 of 9. Showing split_bill's docstring, Find the next example (split_bill(500, 0)), Run its code, Capture what it prints (ValueError and its message), Compare the two texts, The result (5 of 5 ok). In focus: Compare the two texts.next examplesplit_bill's docstringfive >>> examplesFind the next examplesplit_bill(500, 0)Run its codein a copy of the globalsCapture what it printsValueError and its messageCompare the two textscharacter for characterThe result5 of 5 ok

The drawing shows the whole scene; its 9 steps are listed below.

Every step as text
  1. Five examples. run_docstring_examples() reads the docstring of split_bill and finds five examples, four that should give a value and one that should raise.
  2. The first example. split_bill(900_00, 3) is the first >>> line. Its expected output is the line below it, [30000, 30000, 30000], which ends where the next >>> line starts.
  3. Run it. doctest runs the call in a copy of the module's global names, so the example can use split_bill without changing anything the module holds.
  4. What the shell would show. The call returns a list, and the interactive shell would show its repr, so that is the text doctest keeps.
  5. Same text, ok. The text it got matches the expected line character for character, so the example passes and the verbose report prints ok.
  6. The paise left over. The loop takes the next example. 100_00 paise for 3 people gives [3334, 3333, 3333]: the first share carries the paisa left over, and the text matches.
  7. Two more values. sum(split_bill(100_00, 3)) prints 10000, the promise that the shares add up to the total, and split_bill(1, 4) prints [1, 0, 0, 0]. Both match.
  8. An expected exception. The last example, split_bill(500, 0), expects Traceback (most recent call last): as its first line, so doctest expects an exception instead of a value.
  9. Only the last line counts. The call raises ValueError. doctest skips the stack, written as ..., and compares the last line, ValueError: people must be at least 1, not 0. It matches, and all five pass.

Checkpoint

Check: An example and its expected text

  1. Question 1 of 2 In a docstring, where does the expected output of an example end?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: At the first blank line or the next >>> line

    An example is a >>> line, plus ... lines when its statement continues, followed by the expected output, which runs until a blank line or the next >>>.

  2. Question 2 of 2 split_bill(500, 0) raises ValueError("people must be at least 1, not 0"). Which expected output makes its example pass?

    Choose one answer.

    A hint

    An expected exception starts with a header line, and doctest compares the last line in full.

    Show the answer: Question 2 of 2

    Answer: Traceback (most recent call last): ... ValueError: people must be at least 1, not 0

    An expected exception is written as the traceback header line, an optional ... for the stack, and the exception's last line, its type and message, exactly as Python prints it.

doctest is silent until an example disagrees

There are three usual ways to run doctests:

  • python -m doctest bill.py runs every example in the file and prints nothing when all of them pass; add -v to list each one, -o ELLIPSIS to turn on an option and -f to stop at the first failure.
  • doctest.testmod(), called at the bottom of a module, checks all of the module’s docstrings and returns TestResults(failed, attempted); since Python 3.13 the result also counts skipped examples. The example above uses doctest.run_docstring_examples(), which checks the docstring of one object.
  • doctest.testfile("README.txt") checks the examples in a text file, such as a project’s documentation.

The value shows on the day the code and its documentation disagree. Here a function’s output was changed and its docstring was not:

A stale example caught by python -m doctest

cli/inr.py

def inr(amount):
    """Format whole rupees with Indian digit grouping.

    >>> inr(1234567)
    '₹12,34,567'
    >>> inr(999)
    '₹999'
    """
    return f"₹{amount:,}"  # a later "simplification": the , format groups digits in threes

cli/run_doctest_cli.py

"""Runs python -m doctest on inr.py, as you would in a terminal, and shows its exit status."""
import subprocess
import sys

result = subprocess.run([sys.executable, "-m", "doctest", "inr.py"], capture_output=True, text=True)
print(result.stdout, end="")
print("exit status:", result.returncode)

Output

**********************************************************************
File "inr.py", line 4, in inr.inr
Failed example:
    inr(1234567)
Expected:
    '₹12,34,567'
Got:
    '₹1,234,567'
**********************************************************************
1 item had failures:
   1 of   2 in inr.inr
***Test Failed*** 1 failure.
exit status: 1

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 run_doctest_cli.py

The report names the file and line, the example, the text it expected and the text it got. The second example of the docstring still passed, and the summary counts one failure out of two. The exit status of 1 matters as much: it makes a build or a continuous integration job stop, which a page of documentation could never do. In a terminal, Python 3.13 and later print the report in colour.

Key idea

doctest says nothing while the examples and the code agree; when they disagree it shows Expected and Got, and python -m doctest exits with status 1, which stops a build.

Text Diff Paste the Expected and Got lines of a long failure to see exactly where they differ.

Checkpoint

Check: Running doctests and reading a failure

  1. Question 1 of 2 python -m doctest inr.py finds one failing example among two. What exit status does it end with?

    Type a number.

    Show the answer: Question 1 of 2

    Answer: 1

    python -m doctest exits with status 1 when any example fails and 0 when none does. That non-zero status is what makes a build or a continuous integration job stop.

  2. Question 2 of 2 python -m doctest bill.py prints nothing at all. What does that tell you?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: That no example failed; -v would list every example and how many passed

    python -m doctest prints nothing when every example passes and a report with Expected and Got when one fails. Add -v to list each example.

Any difference in the text fails an example, even when the code is right

doctest compares text, character by character, so anything that prints differently from the docstring breaks an example even when the code is right. Here are two such examples, each as an author might first write it and then rewritten. For each failure the program prints the text doctest expected and the text it got:

Two examples that fail on their text, not on a bug Python · text/brittle.py
"""Two doctests that fail although the code is right, and the same examples written so that they pass."""
import doctest


def average_bill(totals):
    """Return the average of some bills, in rupees.

    >>> average_bill([250.1, 250.2, 250.3])
    250.2
    """
    return sum(totals) / len(totals)


def receipt(lines):
    """Print each item and its price, a blank line, then the total.

    >>> receipt([("dosa", 60), ("chai", 20)])
    dosa 60
    chai 20

    total 80
    """
    for item, price in lines:
        print(item, price)
    print()
    print("total", sum(price for _, price in lines))


def average_bill_rewritten(totals):
    """The same function, with the result rounded in the example.

    >>> round(average_bill_rewritten([250.1, 250.2, 250.3]), 2)
    250.2
    """
    return sum(totals) / len(totals)


def receipt_rewritten(lines):
    """The same function, with the blank line written as <BLANKLINE>.

    >>> receipt_rewritten([("dosa", 60), ("chai", 20)])
    dosa 60
    chai 20
    <BLANKLINE>
    total 80
    """
    receipt(lines)


def check(function):
    """Runs the examples of one docstring and prints, for a failure, the text doctest expected and the text it got."""
    [test] = doctest.DocTestFinder().find(function, function.__name__, globs=globals())
    runner = doctest.DocTestRunner()
    failures = []
    runner.report_failure = lambda out, test, example, got: failures.append((example.want, got))
    runner.run(test, out=lambda report: None)
    print(f"{function.__name__}: {'FAILED' if failures else 'ok'}")
    for want, got in failures:
        print(f"    expected {want!r}")
        print(f"    got      {got!r}")


for function in (average_bill, receipt, average_bill_rewritten, receipt_rewritten):
    check(function)

Output

average_bill: FAILED
    expected '250.2\n'
    got      '250.20000000000002\n'
receipt: FAILED
    expected 'dosa 60\nchai 20\n'
    got      'dosa 60\nchai 20\n\ntotal 80\n'
average_bill_rewritten: ok
receipt_rewritten: ok

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brittle.py

The average is right, but the float prints as 250.20000000000002, not the 250.2 a person writes down, and rounding inside the example fixes it. The receipt is right too, but its blank line ended the expected output, so doctest expected two lines and got four; <BLANKLINE> stands for an empty line without ending it. The common causes of such failures, each with its usual fix:

  • Sets print their items in an order that can change between runs of Python; sort them in the example.
  • Default reprs such as <Order object at 0x10e2f3a50> contain a memory address that changes every run.
  • Long output is tiresome to copy in full and easy to get wrong by one character.
  • Exception details can change: the module name in front of an exception class, or the wording of a message.

Three option flags cover most of the rest. ELLIPSIS lets ... in the expected output stand for any text. NORMALIZE_WHITESPACE treats every run of spaces and line breaks as one space. IGNORE_EXCEPTION_DETAIL compares only the exception’s type, without its module name or its message. A flag is turned on for one example with a directive comment after its code, such as # doctest: +ELLIPSIS, or for a whole run with -o on the command line or optionflags= in code.

Checkpoint

Check: Text that breaks an example

  1. Question 1 of 2 average_bill([250.1, 250.2, 250.3]) is right, and the docstring expects 250.2. What does doctest report?

    Choose one answer.

    Show the answer: Question 1 of 2

    Answer: A failure, because Python prints 250.20000000000002 and doctest compares text

    The code is right, but its float prints as 250.20000000000002, not the 250.2 a person writes down. Round the value in the example, round(average_bill(...), 2), and the text matches on every run.

  2. Question 2 of 2 receipt() prints two items, a blank line and the total. Which expected output passes?

    Choose one answer.

    Show the answer: Question 2 of 2

    Answer: dosa 60 chai 20 <BLANKLINE> total 80

    A blank line in the expected output ends it, so an empty line that the code prints is written <BLANKLINE>.

Check yourself

Practice that adapts to you

Practise this lesson

10 questions about 9 ideas of this lesson. Each answer is explained at once, and what you get right is kept in this browser.

  1. Question 1 of 10 In a doctest, which line must come right after the example when you expect an exception?

    Choose one answer.

    Show the answer: Question 1 of 10

    Answer: Traceback (most recent call last):

    doctest recognises an expected exception by the traceback header. It ignores the lines of the stack after it, usually written as ..., and compares the last line: the exception's type and message.

  2. Question 2 of 10 An example's statement does not fit on one line. How is its second line written?

    Choose one answer.

    Show the answer: Question 2 of 10

    Answer: It starts with ... in place of >>>

    Each example is a >>> line, plus ... lines when the statement continues, followed by the lines of output the shell would print.

  3. Question 3 of 10 Which example of split_bill's docstring checks its promise that the shares always add up to the total?

    Choose one answer.

    Show the answer: Question 3 of 10

    Answer: >>> sum(split_bill(100_00, 3)) with the expected line 10000

    An example can check any expression, not only a call: sum(split_bill(100_00, 3)) prints 10000, which states the function's promise in a way a reader can see.

  4. Question 4 of 10 What does run_doctest_cli.py print?

    What does this program print? Choose one answer.

    """Runs python -m doctest on inr.py, as you would in a terminal, and shows its exit status."""
    import subprocess
    import sys
    
    result = subprocess.run([sys.executable, "-m", "doctest", "inr.py"], capture_output=True, text=True)
    print(result.stdout, end="")
    print("exit status:", result.returncode)
    Show the answer: Question 4 of 10

    Answer: it prints

    **********************************************************************
    File "inr.py", line 4, in inr.inr
    Failed example:
        inr(1234567)
    Expected:
        '₹12,34,567'
    Got:
        '₹1,234,567'
    **********************************************************************
    1 item had failures:
       1 of   2 in inr.inr
    ***Test Failed*** 1 failure.
    exit status: 1

    Only the first example fails: 999 has no digits to group, so inr(999) still prints '₹999' and passes. The summary counts 1 failure out of the 2 examples in inr.inr, and python -m doctest exits with status 1, which is what makes a CI job stop.

  5. Question 5 of 10 Which call checks the examples written in a text file, such as a project's README?

    Choose one answer.

    Show the answer: Question 5 of 10

    Answer: doctest.testfile("README.txt")

    python -m doctest file.py and doctest.testmod() check docstrings; doctest.testfile() checks the examples of a text file such as a README.

  6. Question 6 of 10 A CI script ends with doctest.testmod() and always exits with status 0, even when an example fails. What is missing?

    Choose one answer.

    Show the answer: Question 6 of 10

    Answer: A check of the TestResults it returns, exiting with a non-zero status when failed is above 0

    python -m doctest exits with status 1 on a failure by itself. A script that calls testmod() gets TestResults back and must exit with a failure status itself, for example sys.exit(1 if result.failed else 0).

  7. Question 7 of 10 An example's expected output in the docstring is [1, 2, 3], with two spaces after the first comma. The code returns [1, 2, 3]. What happens?

    Choose one answer.

    Show the answer: Question 7 of 10

    Answer: The example fails, because doctest compares the printed text character by character.

    doctest never compares values: it compares the text the example prints, [1, 2, 3], with the text in the docstring, and one extra space is a difference. The NORMALIZE_WHITESPACE option would accept it.

  8. Question 8 of 10 What does brittle.py print?

    What does this program print? Choose one answer.

    """Two doctests that fail although the code is right, and the same examples written so that they pass."""
    import doctest
    
    
    def average_bill(totals):
        """Return the average of some bills, in rupees.
    
        >>> average_bill([250.1, 250.2, 250.3])
        250.2
        """
        return sum(totals) / len(totals)
    
    
    def receipt(lines):
        """Print each item and its price, a blank line, then the total.
    
        >>> receipt([("dosa", 60), ("chai", 20)])
        dosa 60
        chai 20
    
        total 80
        """
        for item, price in lines:
            print(item, price)
        print()
        print("total", sum(price for _, price in lines))
    
    
    def average_bill_rewritten(totals):
        """The same function, with the result rounded in the example.
    
        >>> round(average_bill_rewritten([250.1, 250.2, 250.3]), 2)
        250.2
        """
        return sum(totals) / len(totals)
    
    
    def receipt_rewritten(lines):
        """The same function, with the blank line written as <BLANKLINE>.
    
        >>> receipt_rewritten([("dosa", 60), ("chai", 20)])
        dosa 60
        chai 20
        <BLANKLINE>
        total 80
        """
        receipt(lines)
    
    
    def check(function):
        """Runs the examples of one docstring and prints, for a failure, the text doctest expected and the text it got."""
        [test] = doctest.DocTestFinder().find(function, function.__name__, globs=globals())
        runner = doctest.DocTestRunner()
        failures = []
        runner.report_failure = lambda out, test, example, got: failures.append((example.want, got))
        runner.run(test, out=lambda report: None)
        print(f"{function.__name__}: {'FAILED' if failures else 'ok'}")
        for want, got in failures:
            print(f"    expected {want!r}")
            print(f"    got      {got!r}")
    
    
    for function in (average_bill, receipt, average_bill_rewritten, receipt_rewritten):
        check(function)
    Show the answer: Question 8 of 10

    Answer: it prints

    average_bill: FAILED
        expected '250.2\n'
        got      '250.20000000000002\n'
    receipt: FAILED
        expected 'dosa 60\nchai 20\n'
        got      'dosa 60\nchai 20\n\ntotal 80\n'
    average_bill_rewritten: ok
    receipt_rewritten: ok

    The functions are right; the examples fail on text. The float prints a long tail, and the real blank line ended the expected output after two lines. round() in the example and <BLANKLINE> fix them.

  9. Question 9 of 10 Which of these are likely to print differently from one run of Python to another?

    Choose every answer that is right.

    Show the answer: Question 9 of 10

    Answer:

    • A set of strings.
    • The default repr of an object, such as <Order object at 0x...>.

    A set of strings prints in an order that can change between runs, and a default repr holds a memory address. A list keeps its order, and round(2.675, 2) prints 2.67 every time, because 2.675 is stored as a binary number slightly below it.

  10. Question 10 of 10 A function returns a set of tags, and its doctest shows the set as it printed on your computer. How should the example be written?

    Choose one answer.

    Show the answer: Question 10 of 10

    Answer: >>> sorted(diet_tags(dishes)) with the sorted list as the expected output

    doctest compares text, and a set's order can change between runs of Python. Sorting in the example makes the printed text the same on every run.

Output that changes between runs, made stable Pro: opens with a Pro, Premium or Ultimate pass

A doctest that passes on one run and fails on the next is worse than none, because people learn to ignore it. This part reproduces the three commonest causes in programs that run, measures one of them, and fixes each for good.

In this part:

  • Set order under 20 hash seeds, measured
  • Memory addresses and long output, matched with two option flags
  • Exception names that change with how a module is run

1 diagram · 3 runnable examples (Python, coupons.py, coupons_fixed.py, names.py, seeds.py, tags.py, tags_sorted.py) · about 8 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

doctest in a real project: suites, README files and limits Pro: opens with a Pro, Premium or Ultimate pass

doctest pays off most when it runs with the rest of a project’s tests and checks the examples people actually copy. This part adds doctests to a unittest run, checks a README file, and sets out where a doctest should give way to a unit test.

In this part:

  • Doctests and unit tests in one run, with one exit status
  • Examples in a README, checked with testfile()
  • When a doctest should become a unit test, as a trade-off table
  • Exercise: doctests that catch five bugs
    • Doctests for a temperature converter

1 diagram · 2 runnable examples (README.txt, check_readme.py, discounts.py, test_discounts.py) · 1 exercise with sample tests · about 9 minutes

Opening this part with your pass…Pro part. It opens with the same pass as the part above.

Interview questions

  1. Fresher · Warm-up

    What does doctest check, and how do you run the doctests of a module?

    doctest, a module of Python's standard library, looks through docstrings for examples written like a session in the interactive shell: a line starting with >>> that holds code, followed by the output the shell would print. It runs each example and compares the text it actually prints with the expected text, character for character; an expected exception is written as the Traceback header line followed by the exception's last line. You run a module's doctests with python -m doctest module.py, which prints nothing when every example passes and a report with Expected and Got when one fails, or by calling doctest.testmod() at the bottom of the module. Add -v to see every example; doctest.testfile() checks the examples in a text file such as a README. The examples document the code and test it at the same time.

  2. Fresher to mid

    A doctest of a function that returns a set of usernames passes on your laptop and fails in CI about half the time, with the same Python version. What is happening, and how do you fix both the example and the habit behind it?

    Model answer, Pro. Model answers open with any pass; prices are in the notice on this page. First step and follow-ups

  3. Mid to senior

    A teammate proposes replacing the project's unit tests with doctests "because they double as documentation". Where would you agree, and where would you push back?

    Model answer, Pro. First step and follow-ups

  4. Mid to senior

    A doctest that expects InvalidCoupon passes when you run python coupons.py but fails under python -m doctest coupons.py and under pytest --doctest-modules. Why, and what are two ways to write the example so that it passes everywhere?

    Model answer, Pro. First step and follow-ups

Key takeaways

  • doctest runs the >>> examples of docstrings and compares what they print, as text, with the lines that follow.
  • An expected exception is the Traceback header line, an optional ... and the exception’s last line.
  • python -m doctest file.py, doctest.testmod() and doctest.testfile() run doctests, and a failure from the command line gives exit status 1.
  • Any difference in the text fails an example, so round floats, write <BLANKLINE>, sort sets and use ELLIPSIS, NORMALIZE_WHITESPACE and IGNORE_EXCEPTION_DETAIL where they fit.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.