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:
parent
d2afee47b1
commit
19b1958730
|
@ -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):
|
||||
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
Loading…
Reference in New Issue