summaryrefslogtreecommitdiff
path: root/Lib/doctest.py
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-06-27 20:48:05 +0000
committerTim Peters <tim.peters@gmail.com>2003-06-27 20:48:05 +0000
commit6ebe61fa807d250ccab419473abd8d746a932e75 (patch)
tree18350da8265076dbebafc9fca16fe1b5506f6206 /Lib/doctest.py
parent6cf26195c6e206cba1bb3ebe554e82ab52304bd5 (diff)
downloadcpython-git-6ebe61fa807d250ccab419473abd8d746a932e75.tar.gz
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.
Diffstat (limited to 'Lib/doctest.py')
-rw-r--r--Lib/doctest.py75
1 files changed, 58 insertions, 17 deletions
diff --git a/Lib/doctest.py b/Lib/doctest.py
index c01606dca6..8b379cdf22 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -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():