Only recognize the expected output as an exception if it *starts* with

a traceback message.  I.e., examples that raise exceptions may no
longer generate pre-exception output.  This restores the behavior of
doctest in python 2.3.  The ability to check pre-exception output is
being removed because it makes the documentation simpler; and because
there are very few use cases for it.
This commit is contained in:
Edward Loper 2004-08-25 23:07:03 +00:00
parent d2afee47b1
commit 19b1958730
3 changed files with 55 additions and 54 deletions

View File

@ -235,57 +235,57 @@ Traceback (most recent call last):
ValueError: list.remove(x): x not in list
\end{verbatim}
That doctest succeeds if, and only if, \exception{ValueError} is raised,
with the \samp{list.remove(x): x not in list} detail as shown.
That doctest succeeds if \exception{ValueError} is raised, with the
\samp{list.remove(x): x not in list} detail as shown.\footnote{The
doctest also succeeds if it prints the exact text of the traceback
message; otherwise, it fails.}
The expected output for an exception is divided into four parts.
First, an example may produce some normal output before an exception
is raised, although that's unusual. The "normal output" is taken to
be everything until the first "Traceback" line, and is usually an
empty string. Next, the traceback line must be one of these two, and
indented the same as the first line in the example:
The expected output for an exception must start with a traceback
header, which may be either of the following two lines, indented the
same as the first line of the example:
\begin{verbatim}
Traceback (most recent call last):
Traceback (innermost last):
\end{verbatim}
The most interesting part is the last part: the line(s) starting with the
exception type and detail. This is usually the last line of a traceback,
but can extend across any number of lines. After the "Traceback" line,
doctest simply ignores everything until the first line indented the same as
the first line of the example, \emph{and} starting with an alphanumeric
character. This example illustrates the complexities that are possible:
The traceback header is followed by an optional traceback stack, whose
contents are ignored by doctest. Each line of the traceback stack
must be indented further than the first line of the example, \emph{or}
start with a non-alphanumeric character. Typically, the traceback
stack is either omitted or copied verbatim from an interactive
session.
The traceback stack is followed by the most interesting part: the
line(s) containing the exception type and detail. This is usually the
last line of a traceback, but can extend across multiple lines if the
exception has a multi-line detail, as illustrated in the following
example:
\begin{verbatim}
>>> print 1, 2; raise ValueError('printed 1\nand 2\n but not 3')
1 2
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
... indented the same, but doesn't start with an alphanumeric
not indented the same, so ignored too
File "/Python23/lib/doctest.py", line 442, in _run_examples_inner
compileflags, 1) in globs
File "<string>", line 1, in ? # and all these are ignored
ValueError: printed 1
and 2
but not 3
File "<stdin>", line 1, in ?
ValueError: multi
line
detail
\end{verbatim}
The first (\samp{1 2}) and last three (starting with
\exception{ValueError}) lines are compared, and the rest are ignored.
The last three (starting with \exception{ValueError}) lines are
compared against the exception's type and detail, and the rest are
ignored.
Best practice is to omit the ``File'' lines, unless they add
Best practice is to omit the traceback stack, unless it adds
significant documentation value to the example. So the example above
is probably better as:
\begin{verbatim}
>>> print 1, 2; raise ValueError('printed 1\nand 2\n but not 3')
1 2
>>> raise ValueError('multi\n line\ndetail')
Traceback (most recent call last):
...
ValueError: printed 1
and 2
but not 3
ValueError: multi
line
detail
\end{verbatim}
Note the tracebacks are treated very specially. In particular, in the
@ -293,11 +293,6 @@ rewritten example, the use of \samp{...} is independent of doctest's
\constant{ELLIPSIS} option. The ellipsis in that example could
be left out, or could just as well be three (or three hundred) commas.
\versionchanged[The abilities to check both normal output and an
exception in a single example, and to have a multi-line
exception detail, were added]{2.4}
\subsection{Option Flags and Directives\label{doctest-options}}
A number of option flags control various aspects of doctest's comparison
@ -634,7 +629,7 @@ Backslashes in a raw docstring: m\n
\end{verbatim}
Otherwise, the backslash will be interpreted as part of the string.
E.g., the "\textbackslash" above would be interpreted as a newline
E.g., the "{\textbackslash}" above would be interpreted as a newline
character. Alternatively, you can double each backslash in the
doctest version (and not use a raw string):

View File

@ -1281,15 +1281,14 @@ class DocTestRunner:
# A regular expression for handling `want` strings that contain
# expected exceptions. It divides `want` into three pieces:
# - the pre-exception output (`want`)
# - the traceback header line (`hdr`)
# - the traceback stack (`stack`)
# - the exception message (`msg`), as generated by
# traceback.format_exception_only()
# `msg` may have multiple lines. We assume/require that the
# exception message is the first non-indented line starting with a word
# character following the traceback header line.
_EXCEPTION_RE = re.compile(r"""
(?P<want> .*?) # suck up everything until traceback header
# Grab the traceback header. Different versions of Python have
# said different things on the first traceback line.
^(?P<hdr> Traceback\ \(
@ -1297,9 +1296,9 @@ class DocTestRunner:
| innermost\ last
) \) :
)
\s* $ # toss trailing whitespace on traceback header
.*? # don't blink: absorb stuff until a line *starts* with \w
^ (?P<msg> \w+ .*)
\s* $ # toss trailing whitespace on the header.
(?P<stack> .*?) # don't blink: absorb stuff until...
^ (?P<msg> \w+ .*) # a line *starts* with alphanum.
""", re.VERBOSE | re.MULTILINE | re.DOTALL)
def __run(self, test, compileflags, out):
@ -1374,13 +1373,10 @@ class DocTestRunner:
exc_info)
failures += 1
else:
e_want, e_msg = m.group('want', 'msg')
# The test passes iff the pre-exception output and
# the exception description match the values given
# in `want`.
if (self._checker.check_output(e_want, got,
self.optionflags) and
self._checker.check_output(e_msg, exc_msg,
# The test passes iff the expected exception
# message (`m.group('msg')`) matches the actual
# exception message (`exc_msg`).
if (self._checker.check_output(m.group('msg'), exc_msg,
self.optionflags)):
self.report_success(out, test, example,
got + _exception_traceback(exc_info))

View File

@ -623,8 +623,10 @@ replaced with any other string:
>>> doctest.DocTestRunner(verbose=False).run(test)
(0, 2)
An example may generate output before it raises an exception; if it
does, then the output must match the expected output:
An example may not generate output before it raises an exception; if
it does, then the traceback message will not be recognized as
signaling an expected exception, so the example will be reported as an
unexpected exception:
>>> def f(x):
... '''
@ -636,7 +638,15 @@ does, then the output must match the expected output:
... '''
>>> test = doctest.DocTestFinder().find(f)[0]
>>> doctest.DocTestRunner(verbose=False).run(test)
(0, 2)
... # doctest: +ELLIPSIS
**********************************************************************
Line 3, in f
Failed example:
print 'pre-exception output', x/0
Exception raised:
...
ZeroDivisionError: integer division or modulo by zero
(1, 2)
Exception messages may contain newlines: