Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6ebe61f

Browse files
committed
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.
1 parent 6cf2619 commit 6ebe61f

3 files changed

Lines changed: 83 additions & 17 deletions

File tree

Doc/lib/libdoctest.tex

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,23 @@ \subsection{Warnings}
398398
import doctest, sys
399399
doctest.testmod()
400400
\end{verbatim}
401+
402+
\item WYSIWYG isn't always the case, starting in Python 2.3. The
403+
string form of boolean results changed from \code{"0"} and
404+
\code{"1"} to \code{"False"} and \code{"True"} in Python 2.3.
405+
This makes it clumsy to write a doctest showing boolean results that
406+
passes under multiple versions of Python. In Python 2.3, by default,
407+
and as a special case, if an expected output block consists solely
408+
of \code{"0"} and the actual output block consists solely of
409+
\code{"False"}, that's accepted as an exact match, and similarly for
410+
\code{"1"} versus \code{"True"}. This behavior can be turned off by
411+
passing the new (in 2.3) module constant
412+
\constant{DONT_ACCEPT_TRUE_FOR_1} as the value of \function{testmod()}'s
413+
new (in 2.3) optional \var{optionflags} argument. Some years after
414+
the integer spellings of booleans are history, this hack will
415+
probably be removed again.
416+
417+
401418
\end{enumerate}
402419

403420

Lib/doctest.py

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,9 @@ def _test():
297297
from inspect import ismodule as _ismodule
298298
from inspect import classify_class_attrs as _classify_class_attrs
299299

300+
# Option constants.
301+
DONT_ACCEPT_TRUE_FOR_1 = 1 << 0
302+
300303
# Extract interactive examples from a string. Return a list of triples,
301304
# (source, outcome, lineno). "source" is the source code, and ends
302305
# with a newline iff the source spans more than one line. "outcome" is
@@ -414,7 +417,7 @@ def _tag_out(printer, *tag_msg_pairs):
414417
# that captures the examples' std output. Return (#failures, #tries).
415418

416419
def _run_examples_inner(out, fakeout, examples, globs, verbose, name,
417-
compileflags):
420+
compileflags, optionflags):
418421
import sys, traceback
419422
OK, BOOM, FAIL = range(3)
420423
NADA = "nothing"
@@ -449,7 +452,11 @@ def _run_examples_inner(out, fakeout, examples, globs, verbose, name,
449452
state = BOOM
450453

451454
if state == OK:
452-
if got == want:
455+
if (got == want or
456+
(not (optionflags & DONT_ACCEPT_TRUE_FOR_1) and
457+
(got, want) in (("True\n", "1\n"), ("False\n", "0\n"))
458+
)
459+
):
453460
if verbose:
454461
out("ok\n")
455462
continue
@@ -482,14 +489,16 @@ def _extract_future_flags(globs):
482489
# Run list of examples, in a shallow copy of context (dict) globs.
483490
# Return (#failures, #tries).
484491

485-
def _run_examples(examples, globs, verbose, name, compileflags):
492+
def _run_examples(examples, globs, verbose, name, compileflags,
493+
optionflags):
486494
import sys
487495
saveout = sys.stdout
488496
globs = globs.copy()
489497
try:
490498
sys.stdout = fakeout = _SpoofOut()
491499
x = _run_examples_inner(saveout.write, fakeout, examples,
492-
globs, verbose, name, compileflags)
500+
globs, verbose, name, compileflags,
501+
optionflags)
493502
finally:
494503
sys.stdout = saveout
495504
# 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):
504513
return x
505514

506515
def run_docstring_examples(f, globs, verbose=0, name="NoName",
507-
compileflags=None):
516+
compileflags=None, optionflags=0):
508517
"""f, globs, verbose=0, name="NoName" -> run examples from f.__doc__.
509518
510519
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",
533542
return 0, 0
534543
if compileflags is None:
535544
compileflags = _extract_future_flags(globs)
536-
return _run_examples(e, globs, verbose, name, compileflags)
545+
return _run_examples(e, globs, verbose, name, compileflags, optionflags)
537546

538547
def is_private(prefix, base):
539548
"""prefix, base -> true iff name prefix + "." + base is "private".
@@ -637,8 +646,9 @@ class Tester:
637646
"""
638647

639648
def __init__(self, mod=None, globs=None, verbose=None,
640-
isprivate=None):
641-
"""mod=None, globs=None, verbose=None, isprivate=None
649+
isprivate=None, optionflags=0):
650+
"""mod=None, globs=None, verbose=None, isprivate=None,
651+
optionflags=0
642652
643653
See doctest.__doc__ for an overview.
644654
@@ -658,6 +668,8 @@ def __init__(self, mod=None, globs=None, verbose=None,
658668
Optional keyword arg "isprivate" specifies a function used to determine
659669
whether a name is private. The default function is doctest.is_private;
660670
see its docs for details.
671+
672+
See doctest.testmod docs for the meaning of optionflags.
661673
"""
662674

663675
if mod is None and globs is None:
@@ -678,6 +690,8 @@ def __init__(self, mod=None, globs=None, verbose=None,
678690
isprivate = is_private
679691
self.isprivate = isprivate
680692

693+
self.optionflags = optionflags
694+
681695
self.name2ft = {} # map name to (#failures, #trials) pair
682696

683697
self.compileflags = _extract_future_flags(globs)
@@ -714,7 +728,7 @@ def runstring(self, s, name):
714728
e = _extract_examples(s)
715729
if e:
716730
f, t = _run_examples(e, self.globs, self.verbose, name,
717-
self.compileflags)
731+
self.compileflags, self.optionflags)
718732
if self.verbose:
719733
print f, "of", t, "examples failed in string", name
720734
self.__record_outcome(name, f, t)
@@ -1045,8 +1059,9 @@ def __runone(self, target, name):
10451059
master = None
10461060

10471061
def testmod(m=None, name=None, globs=None, verbose=None, isprivate=None,
1048-
report=1):
1049-
"""m=None, name=None, globs=None, verbose=None, isprivate=None, report=1
1062+
report=True, optionflags=0):
1063+
"""m=None, name=None, globs=None, verbose=None, isprivate=None,
1064+
report=True, optionflags=0
10501065
10511066
Test examples in docstrings in functions and classes reachable
10521067
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,
10801095
else prints nothing at the end. In verbose mode, the summary is
10811096
detailed, else very brief (in fact, empty if all tests passed).
10821097
1098+
Optional keyword arg "optionflags" or's together module constants,
1099+
and defaults to 0. This is new in 2.3. Possible values:
1100+
1101+
DONT_ACCEPT_TRUE_FOR_1
1102+
By default, if an expected output block contains just "1",
1103+
an actual output block containing just "True" is considered
1104+
to be a match, and similarly for "0" versus "False". When
1105+
DONT_ACCEPT_TRUE_FOR_1 is specified, neither substitution
1106+
is allowed.
1107+
10831108
Advanced tomfoolery: testmod runs methods of a local instance of
10841109
class doctest.Tester, then merges the results into (or creates)
10851110
global Tester instance doctest.master. Methods of doctest.master
@@ -1102,20 +1127,21 @@ class doctest.Tester, then merges the results into (or creates)
11021127
raise TypeError("testmod: module required; " + `m`)
11031128
if name is None:
11041129
name = m.__name__
1105-
tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate)
1130+
tester = Tester(m, globs=globs, verbose=verbose, isprivate=isprivate,
1131+
optionflags=optionflags)
11061132
failures, tries = tester.rundoc(m, name)
11071133
f, t = tester.rundict(m.__dict__, name, m)
1108-
failures = failures + f
1109-
tries = tries + t
1134+
failures += f
1135+
tries += t
11101136
if hasattr(m, "__test__"):
11111137
testdict = m.__test__
11121138
if testdict:
11131139
if not hasattr(testdict, "items"):
11141140
raise TypeError("testmod: module.__test__ must support "
11151141
".items(); " + `testdict`)
11161142
f, t = tester.run__test__(testdict, name + ".__test__")
1117-
failures = failures + f
1118-
tries = tries + t
1143+
failures += f
1144+
tries += t
11191145
if report:
11201146
tester.summarize()
11211147
if master is None:
@@ -1174,7 +1200,22 @@ def get(self):
11741200
>>> x = 1; y = 2
11751201
>>> x + y, x * y
11761202
(3, 2)
1177-
"""
1203+
""",
1204+
"bool-int equivalence": r"""
1205+
In 2.2, boolean expressions displayed
1206+
0 or 1. By default, we still accept
1207+
them. This can be disabled by passing
1208+
DONT_ACCEPT_TRUE_FOR_1 to the new
1209+
optionflags argument.
1210+
>>> 4 == 4
1211+
1
1212+
>>> 4 == 4
1213+
True
1214+
>>> 4 > 4
1215+
0
1216+
>>> 4 > 4
1217+
False
1218+
""",
11781219
}
11791220

11801221
def _test():

Misc/NEWS

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,14 @@ Extension modules
8383
Library
8484
-------
8585

86+
- For compatibility with doctests created before 2.3, if an expected
87+
output block consists solely of "1" and the actual output block
88+
consists solely of "True", it's accepted as a match; similarly
89+
for "0" and "False". This is quite un-doctest-like, but is practical.
90+
The behavior can be disabled by passing the new doctest module
91+
constant DONT_ACCEPT_TRUE_FOR_1 to the new optionflags optional
92+
argument.
93+
8694
- The cgitb module has been extended to support plain text display (SF patch
8795
569574).
8896

0 commit comments

Comments
 (0)