Doctest 1.36 Implementation Summary
==================================================
doctest.py: Implementation Summary (revision 1.36)
==================================================
This section gives a summary of the current design. I wrote it while
reading through the code, to make sure I understood what all the
pieces did (and to give me a reference to check back with); but it
might be a useful guide to anyone who's trying to familiarize
themselves more with the current code.
Entry points
============
Doctest cases are run by either `run_doctest_examples()` or
`Tester.runstring()`. (There are other entry points, such as
`Tester.rundoc()`, but they all call into either `run_doctest_examples()`
or `Tester.runstring()`; see below for more info on other entry points.)
Each of these routines calls `_extract_examples()` to pull examples
out of the docstring, and then calls `_run_examples()` to run them.
They both return a tuple `(num_failures, num_doctest_cases)` (which
they get as the return value from `_run_examples()`).
`Tester.runstring()` also keeps a running total of `num_failures` and
`num_doctest_cases` in instance variables.
Since `run_doctest_examples()` is pulls the docstring out of an
object, it needs to do a little more work. In particular, it checks
for errors & casts to str while pulling out the docstring (is this
unicode-unfriendly?); and it gets compiler flags by checking
__future__ flags from globals.
_extract_examples
=================
`_extract_examples(s)` takes a string containing a doctest case, and
returns a list of those examples. Each doctest case is encoded as a
tripple `(source, outcome, lineno)`, where:
- `source` is the source code string. It ends with a newline iff
`source` spans multiple lines.
- `outcome` is the expected output, if any, or an empty string if no
output is expected. `outcome` ends in a newline iff output is
expected
- `lineno` is the line number of the first line of the doctest case
within the input string. This line number is zero-based.
`_extract_examples()` is basically implemented as an ad-hoc parser that
loops through the lines of the docstring.
_run_examples
=============
`_run_examples()` is basically a wrapper for
`_run_examples_inner()`. Here's what it does:
- Redirect stdout to a dummy object (`_SpoofOut`) that captures
output.
- Make a shallow copy of the gloals.
- Call `_run_examples_inner()` to do the real work.
After `_run_examples_inner()` returns, `_run_examples()` restores
`sys.stdout`; clears the copy of globals (for gc reasons); and returns
what `_run_examples_inner()` returned (i.e., a tuple `(num_failures,
num_doctest_cases)`).
_run_examples_inner
===================
This is where the real work happens. It takes a bunch of parameters:
- `out`: A function for writing output. Currently, this is set
to `sys.stdout.write` by `_run_examples()`.
- `fakeout`: The dummy output object (`_SpoofOut`), used to capture
the output of each doctest case.
- `examples`: A list of `(source, outcome, lineno)` tripples, as
returned by `_extract_examples()`.
- `globs`: The set of globals used as an environment to evaluate
doctest cases.
- `verbose`: If true, then print a message to `out` before running
each example, indicating what example is being run and what the
expected output is.
- `name`: The "name" of the collection of examples (typically the name
of the object that `_extract_examples()` was run on). This is used
in the output to `out`.
- `compileflags`: A set of compiler flags for the builtin `compile()`
function. This is used to correctly handle `__future__` imports.
- `optionflags`: A set of flags for options to doctest itself.
Currently, only one flag is supported: `DONT_ACCEPT_TRUE_FOR_1`.
`_run_examples_inner()` loops through each doctest example, compiles
it, and runs it (with output directed to `fakeout`). It then extracts
the output, and comparse it to the expected output. If they differ,
it calls `out` with an error message.
Exceptions are handled separately: if an exception is raised, then the
expected output is compared against a traceback template; if they
match, and the exception type/message match, then the test passes;
otherwise, it fails.
All examples are evaluated in the same globals environment, so
variables can be shared between the doctest cases in `examples` (e.g.,
one doctest case can create a variable, and a later doctest case can
use it).
Once all examples have been run, `_run_examples_inner()` returns a
tuple `(num_failures, num_doctest_cases)`.
Other Entry Points
==================
The `Tester` class defines a number of entry points: `Tester.rundoc()`,
`Tester.rundict()`, and `Tester.run__test__()`. Also, the function
`testmod` creates a `Tester` class and uses it to test every object
in a module. Finally, there are some entry points to make it easier
to interface with the `unittest` module.
Tester.rundoc()
---------------
`Tester.rundoc(obj)` calls `run_doctest_examples` to extract and
process the doctest cases in the given object's docstring.
If `obj` is a class, then `Tester.rundoc` puts together a dictionary
mapping each attributes name to an object with the right docstrings.
(It needs to do some acrobatics to get the right objects when wrappers
such as `staticmethod` and `classmethod` are used.) It then calls
`Tester.run__test__()` on the dictionary, and merges the return value
into the return value from `run_doctest_examples` (both return a
`(num_failures, num_doctest_cases)` tuple).
Note that running `Tester.rundoc()` on a class will recurse into
contained objects; but calling it on a module will *not* recurse into
contained objects.
Tester.rundict() and Tester.run__test__()
-----------------------------------------
Both of these functions basically take a dictionary from names to
objects, and calls `rundoc` and/or `runstring` on those objects.
There are a number of annoying and useless differences between the two
(eg one uses the variable `thisname` for the dictionary key; the other
uses `thisname` for the dictionary key *plus* a given prefix). But
there are also a couple of real differences:
- `rundict` uses `isprivate` to ignore anything with a "private"
name; but `run__test__` looks at every dictionary item.
- `rundict` excludes any object that is not defined in a given
module. (This is to avoid running doctests on imported objects.)
- `rundict` ignores everything but functions and classes; but
`run__test__` also processes strings. Also, if you give
`run__test__` anything *other* than a function, class, or
string, then it raises an exception.
I don't see any reason why these two have to duplicate code (and do
things differently); I think they could be folded into a single
function pretty easily, which would reduce the number of places for
bugs to hide.
testmod
-------
`testmod()` is one of the more common entry points for doctest. It
basically just creates a Tester object and uses it to run the tests
in every docstring in a given module.
It takes the following arguments:
- `m`: The module to test (use sys.modules['__main__'] if not
specified).
- `name`: The name of the module (use `m.__name__` if not
specified).
- `globs`: The set of globals to use (use `m.__dict__` if not
specified).
- `verbose`: Verbosity level for the `Tester` object.
- `isprivate`: Private-detection function for the `Tester` object.
- `report`: If true, then print a report at the end.
- `optionflags`: flags for the `Tester` object (passed through to
`_run_examples_inner`).
It calls `Tester.rundict` on the module's `__dict__`; and if the
module defines a `__test__` attribute, then it `Tester.run__test__`
on it.
It also creates a global "master" trainer, which it uses to keep
track of the total number of errors that have been generated across
multiple calls to `testmod()`.
Like most of the other entry points, it returns a tuple
`(num_failures, num_doctest_cases)`.
Utility Functions and Classes
=============================
_SpoofOut
---------
:Used by: `_run_examples()` and `_run_examples_inner()` (to replace
`sys.stdout` and as a `writer` for `traceback.print_exc`).
This is a fairly streight-forward object that acts like a file open
for writing, and captures any output into a string. It's used to
capture output when running doctest cases, so it can be compared
against the expected output. If the captured output doesn't already
end with a newline, then `_SpoofOut.get()` adds one.
_tag_out
--------
:Used by: `_run_examples_inner()`.
A simple utility function to print one or more `(tag, message)`
pairs. E.g.:
>>> _tag_out(sys.stdout.write, ('tag', 'message'))
tag: message
>>> _tag_out(sys.stdout.write, ('tag', 'multiline\nmessage\n'))
tag:
multiline
message
It distinguishes single-line messages from multiline messages by
checking whether the last charater is a newline.
_extract_future_flags
---------------------
:Used by: `run_docstring_examples()` and `Tester.__init__()`
This function checks what `__future__` features are used in a single
set of globals, and returns a corresponding set of compiler flags
(suitable for use with the `compile()` builtin).
_is_private
-----------
:Used by: `Tester.__init__()`, as a default value for the `isprivate`
parameter to `Tester.__init__` (`isprivate` is used by
`Tester.rundict()`).
A very simple function that returns true iff a given name is private,
according to python's naming conventions.
_from_module
------------
:Used by: `Tester.rundict()`
Given a function or class, return true iff it was defined in a given
module.
Tester
======
The tester class is a basic test manager, that provides a wrapper for
running tests, and keeps track of overall statistics. Most of its
methods function as "entry points" for running tests, and were
discussed above. It also defines a few other methods:
- `Tester.summarize()` prints a summary of the results of the tests
that have been run by the tester object. It's based off of
the `name2ft` instance variable, which maps names to tuples of
`(num_failed, num_doctest_cases)`.
- `Tester.__record_outcome()` is called by `Tester.rundoc()` and
`Tester.runstring()`, and is responsible for updating `name2ft`
- `Tester.merge()` updates `name2ft` by merging the items from
another `Tester` object's `name2ft` dictionary.
- `Tester.__runone()` is called by `Tester.rundict()`, and is
responsible for filtering out private names. For public names,
it just calls `Tester.rundoc()`.
DocTestSuite (unittest support)
===============================
`DocTestSuite` returns a unittest test suite object that runs all the
doctest cases in a given module. The given module can be a module
object, a string, or `None` (meaning that the current module should be
tested).
[I haven't had a chance to go through this in detail yet]
Debugger
========
The debugger will run a specified object's docstring, and then enter
the debugger (with `pdb.post_mortem()`).
[I haven't had a chance to go through this in detail yet]