A hack to ease compatibility with pre-2.3 Pythons: by default, doctest
now accepts "True" when a test expects "1", and similarly for "False" versus "0". This is un-doctest-like, but on balance makes it much more pleasant to write doctests that pass under 2.2 and 2.3. I expect it to go away again, when 2.2 is forgotten. In the meantime, there's a new doctest module constant that can be passed to a new optional argument, if you want to turn this behavior off. Note that this substitution is very simple-minded: the expected and actual outputs have to consist of single tokens. No attempt is made, e.g., to accept [True, False] when a test expects [1, 0]. This is a simple hack for simple tests, and I intend to keep it that way.
This commit is contained in:
parent
6cf26195c6
commit
6ebe61fa80
|
@ -398,6 +398,23 @@ def _test():
|
|||
import doctest, sys
|
||||
doctest.testmod()
|
||||
\end{verbatim}
|
||||
|
||||
\item WYSIWYG isn't always the case, starting in Python 2.3. The
|
||||
string form of boolean results changed from \code{"0"} and
|
||||
\code{"1"} to \code{"False"} and \code{"True"} in Python 2.3.
|
||||
This makes it clumsy to write a doctest showing boolean results that
|
||||
passes under multiple versions of Python. In Python 2.3, by default,
|
||||
and as a special case, if an expected output block consists solely
|
||||
of \code{"0"} and the actual output block consists solely of
|
||||
\code{"False"}, that's accepted as an exact match, and similarly for
|
||||
\code{"1"} versus \code{"True"}. This behavior can be turned off by
|
||||
passing the new (in 2.3) module constant
|
||||
\constant{DONT_ACCEPT_TRUE_FOR_1} as the value of \function{testmod()}'s
|
||||
new (in 2.3) optional \var{optionflags} argument. Some years after
|
||||
the integer spellings of booleans are history, this hack will
|
||||
probably be removed again.
|
||||
|
||||
|
||||
\end{enumerate}
|
||||
|
||||
|
||||
|
|
|
@ -297,6 +297,9 @@ from inspect import isfunction as _isfunction
|
|||
from inspect import ismodule as _ismodule
|
||||
from inspect import classify_class_attrs as _classify_class_attrs
|
||||
|
||||
# Option constants.
|
||||
DONT_ACCEPT_TRUE_FOR_1 = 1 << 0
|
||||
|
||||
# Extract interactive examples from a string. Return a list of triples,
|
||||
# (source, outcome, lineno). "source" is the source code, and ends
|
||||
# with a newline iff the source spans more than one line. "outcome" is
|
||||
|
@ -414,7 +417,7 @@ def _tag_out(printer, *tag_msg_pairs):
|
|||
# that captures the examples' std output. Return (#failures, #tries).
|
||||
|
||||
def _run_examples_inner(out, fakeout, examples, globs, verbose, name,
|
||||
compileflags):
|
||||
compileflags, optionflags):
|
||||
import sys, traceback
|
||||
OK, BOOM, FAIL = range(3)
|
||||
NADA = "nothing"
|
||||
|
@ -449,7 +452,11 @@ def _run_examples_inner(out, fakeout, examples, globs, verbose, name,
|
|||
state = BOOM
|
||||
|
||||
if state == OK:
|
||||
if got == want:
|
||||
if (got == want or
|
||||
(not (optionflags & DONT_ACCEPT_TRUE_FOR_1) and
|
||||
(got, want) in (("True\n", "1\n"), ("False\n", "0\n"))
|
||||
)
|
||||
):
|
||||
if verbose:
|
||||
out("ok\n")
|
||||
continue
|
||||
|
@ -482,14 +489,16 @@ def _extract_future_flags(globs):
|
|||
# Run list of examples, in a shallow copy of context (dict) globs.
|
||||
# Return (#failures, #tries).
|
||||
|
||||
def _run_examples(examples, globs, verbose, name, compileflags):
|
||||
def _run_examples(examples, globs, verbose, name, compileflags,
|
||||
optionflags):
|
||||
import sys
|
||||
saveout = sys.stdout
|
||||
globs = globs.copy()
|
||||
try:
|
||||
sys.stdout = fakeout = _SpoofOut()
|
||||
x = _run_examples_inner(saveout.write, fakeout, examples,
|
||||
globs, verbose, name, compileflags)
|
||||
globs, verbose, name, compileflags,
|
||||
optionflags)
|
||||
finally:
|
||||
sys.stdout = saveout
|
||||
# While Python gc can clean up most cycles on its own, it doesn't
|
||||
|
@ -504,7 +513,7 @@ def _run_examples(examples, globs, verbose, name, compileflags):
|
|||
return x
|
||||
|
||||
def run_docstring_examples(f, globs, verbose=0, name="NoName",
|
||||
compileflags=None):
|
||||
compileflags=None, optionflags=0):
|
||||
"""f, globs, verbose=0, name="NoName" -> run examples from f.__doc__.
|
||||
|
||||
Use (a shallow copy of) dict globs as the globals for execution.
|
||||
|
@ -533,7 +542,7 @@ def run_docstring_examples(f, globs, verbose=0, name="NoName",
|
|||
return 0, 0
|
||||
if compileflags is None:
|
||||
compileflags = _extract_future_flags(globs)
|
||||
return _run_examples(e, globs, verbose, name, compileflags)
|
||||
return _run_examples(e, globs, verbose, name, compileflags, optionflags)
|
||||
|
||||
def is_private(prefix, base):
|
||||
"""prefix, base -> true iff name prefix + "." + base is "private".
|
||||
|
@ -637,8 +646,9 @@ Got: 84
|
|||
"""
|
||||
|
||||
def __init__(self, mod=None, globs=None, verbose=None,
|
||||
isprivate=None):
|
||||
"""mod=None, globs=None, verbose=None, isprivate=None
|
||||
isprivate=None, optionflags=0):
|
||||
"""mod=None, globs=None, verbose=None, isprivate=None,
|
||||
optionflags=0
|
||||
|
||||
See doctest.__doc__ for an overview.
|
||||
|
||||
|
@ -658,6 +668,8 @@ failures if false; by default, it's true iff "-v" is in sys.argv.
|
|||
Optional keyword arg "isprivate" specifies a function used to determine
|
||||
whether a name is private. The default function is doctest.is_private;
|
||||
see its docs for details.
|
||||
|
||||
See doctest.testmod docs for the meaning of optionflags.
|
||||
"""
|
||||
|
||||
if mod is None and globs is None:
|
||||
|
@ -678,6 +690,8 @@ see its docs for details.
|
|||
isprivate = is_private
|
||||
self.isprivate = isprivate
|
||||
|
||||
self.optionflags = optionflags
|
||||
|
||||
self.name2ft = {} # map name to (#failures, #trials) pair
|
||||
|
||||
self.compileflags = _extract_future_flags(globs)
|
||||
|
@ -714,7 +728,7 @@ see its docs for details.
|
|||
e = _extract_examples(s)
|
||||
if e:
|
||||
f, t = _run_examples(e, self.globs, self.verbose, name,
|
||||
self.compileflags)
|
||||
self.compileflags, self.optionflags)
|
||||
if self.verbose:
|
||||
print f, "of", t, "examples failed in string", name
|
||||
self.__record_outcome(name, f, t)
|
||||
|
@ -1045,8 +1059,9 @@ see its docs for details.
|
|||
master = None
|
||||
|
||||
def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
|
||||
report=1):
|
||||
"""m=None, name=None, globs=None, verbose=None, isprivate=None, report=1
|
||||
report=True, optionflags=0):
|
||||
"""m=None, name=None, globs=None, verbose=None, isprivate=None,
|
||||
report=True, optionflags=0
|
||||
|
||||
Test examples in docstrings in functions and classes reachable
|
||||
from module m (or the current module if m is not supplied), starting
|
||||
|
@ -1080,6 +1095,16 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
|
|||
else prints nothing at the end. In verbose mode, the summary is
|
||||
detailed, else very brief (in fact, empty if all tests passed).
|
||||
|
||||
Optional keyword arg "optionflags" or's together module constants,
|
||||
and defaults to 0. This is new in 2.3. Possible values:
|
||||
|
||||
DONT_ACCEPT_TRUE_FOR_1
|
||||
By default, if an expected output block contains just "1",
|
||||
an actual output block containing just "True" is considered
|
||||
to be a match, and similarly for "0" versus "False". When
|
||||
DONT_ACCEPT_TRUE_FOR_1 is specified, neither substitution
|
||||
is allowed.
|
||||
|
||||
Advanced tomfoolery: testmod runs methods of a local instance of
|
||||
class doctest.Tester, then merges the results into (or creates)
|
||||
global Tester instance doctest.master. Methods of doctest.master
|
||||
|
@ -1102,11 +1127,12 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
|
|||
raise TypeError("testmod: module required; " + `m`)
|
||||
if name is None:
|
||||
name = m.__name__
|
||||
tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate)
|
||||
tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate,
|
||||
optionflags=optionflags)
|
||||
failures, tries = tester.rundoc(m, name)
|
||||
f, t = tester.rundict(m.__dict__, name, m)
|
||||
failures = failures + f
|
||||
tries = tries + t
|
||||
failures += f
|
||||
tries += t
|
||||
if hasattr(m, "__test__"):
|
||||
testdict = m.__test__
|
||||
if testdict:
|
||||
|
@ -1114,8 +1140,8 @@ def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
|
|||
raise TypeError("testmod: module.__test__ must support "
|
||||
".items(); " + `testdict`)
|
||||
f, t = tester.run__test__(testdict, name + ".__test__")
|
||||
failures = failures + f
|
||||
tries = tries + t
|
||||
failures += f
|
||||
tries += t
|
||||
if report:
|
||||
tester.summarize()
|
||||
if master is None:
|
||||
|
@ -1174,7 +1200,22 @@ __test__ = {"_TestClass": _TestClass,
|
|||
>>> x = 1; y = 2
|
||||
>>> x + y, x * y
|
||||
(3, 2)
|
||||
"""
|
||||
""",
|
||||
"bool-int equivalence": r"""
|
||||
In 2.2, boolean expressions displayed
|
||||
0 or 1. By default, we still accept
|
||||
them. This can be disabled by passing
|
||||
DONT_ACCEPT_TRUE_FOR_1 to the new
|
||||
optionflags argument.
|
||||
>>> 4 == 4
|
||||
1
|
||||
>>> 4 == 4
|
||||
True
|
||||
>>> 4 > 4
|
||||
0
|
||||
>>> 4 > 4
|
||||
False
|
||||
""",
|
||||
}
|
||||
|
||||
def _test():
|
||||
|
|
|
@ -83,6 +83,14 @@ Extension modules
|
|||
Library
|
||||
-------
|
||||
|
||||
- For compatibility with doctests created before 2.3, if an expected
|
||||
output block consists solely of "1" and the actual output block
|
||||
consists solely of "True", it's accepted as a match; similarly
|
||||
for "0" and "False". This is quite un-doctest-like, but is practical.
|
||||
The behavior can be disabled by passing the new doctest module
|
||||
constant DONT_ACCEPT_TRUE_FOR_1 to the new optionflags optional
|
||||
argument.
|
||||
|
||||
- The cgitb module has been extended to support plain text display (SF patch
|
||||
569574).
|
||||
|
||||
|
|
Loading…
Reference in New Issue