aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Lib/doctest.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/doctest.py')
-rw-r--r--Lib/doctest.py353
1 files changed, 145 insertions, 208 deletions
diff --git a/Lib/doctest.py b/Lib/doctest.py
index 90bcca1fdbe..e189c8feba3 100644
--- a/Lib/doctest.py
+++ b/Lib/doctest.py
@@ -80,13 +80,11 @@ __all__ = [
'testmod',
'testfile',
'run_docstring_examples',
- # 7. Tester
- 'Tester',
- # 8. Unittest Support
+ # 7. Unittest Support
'DocTestSuite',
'DocFileSuite',
'set_unittest_reportflags',
- # 9. Debugging Support
+ # 8. Debugging Support
'script_from_examples',
'testsource',
'debug_src',
@@ -94,11 +92,16 @@ __all__ = [
]
import __future__
-
-import sys, traceback, inspect, linecache, os, re
-import unittest, difflib, pdb, tempfile
-import warnings
-from StringIO import StringIO
+import difflib
+import inspect
+import linecache
+import os
+import pdb
+import re
+import sys
+import traceback
+import unittest
+from io import StringIO
from collections import namedtuple
TestResults = namedtuple('TestResults', 'failed attempted')
@@ -166,10 +169,9 @@ ELLIPSIS_MARKER = '...'
# 4. DocTest Finder -- extracts test cases from objects
# 5. DocTest Runner -- runs test cases
# 6. Test Functions -- convenient wrappers for testing
-# 7. Tester Class -- for backwards compatibility
-# 8. Unittest Support
-# 9. Debugging Support
-# 10. Example Usage
+# 7. Unittest Support
+# 8. Debugging Support
+# 9. Example Usage
######################################################################
## 1. Utility Functions
@@ -199,38 +201,32 @@ def _normalize_module(module, depth=2):
"""
if inspect.ismodule(module):
return module
- elif isinstance(module, (str, unicode)):
+ elif isinstance(module, str):
return __import__(module, globals(), locals(), ["*"])
elif module is None:
return sys.modules[sys._getframe(depth).f_globals['__name__']]
else:
raise TypeError("Expected a module, string, or None")
-def _load_testfile(filename, package, module_relative):
+def _load_testfile(filename, package, module_relative, encoding):
if module_relative:
package = _normalize_module(package, 3)
filename = _module_relative_path(package, filename)
if hasattr(package, '__loader__'):
if hasattr(package.__loader__, 'get_data'):
file_contents = package.__loader__.get_data(filename)
+ file_contents = file_contents.decode(encoding)
# get_data() opens files as 'rb', so one must do the equivalent
# conversion as universal newlines would do.
return file_contents.replace(os.linesep, '\n'), filename
- with open(filename) as f:
+ with open(filename, encoding=encoding) as f:
return f.read(), filename
-# Use sys.stdout encoding for ouput.
-_encoding = getattr(sys.__stdout__, 'encoding', None) or 'utf-8'
-
def _indent(s, indent=4):
"""
Add the given number of space characters to the beginning of
every non-blank line in `s`, and return the result.
- If the string `s` is Unicode, it is encoded using the stdout
- encoding and the `backslashreplace` error handler.
"""
- if isinstance(s, unicode):
- s = s.encode(_encoding, 'backslashreplace')
# This regexp matches the start of non-blank lines:
return re.sub('(?m)^(?!$)', indent*' ', s)
@@ -254,19 +250,11 @@ class _SpoofOut(StringIO):
# that a trailing newline is missing.
if result and not result.endswith("\n"):
result += "\n"
- # Prevent softspace from screwing up the next test case, in
- # case they used print with a trailing comma in an example.
- if hasattr(self, "softspace"):
- del self.softspace
return result
- def truncate(self, size=None):
- StringIO.truncate(self, size)
- if hasattr(self, "softspace"):
- del self.softspace
- if not self.buf:
- # Reset it to an empty string, to make sure it's not unicode.
- self.buf = ''
+ def truncate(self, size=None):
+ self.seek(size)
+ StringIO.truncate(self)
# Worst-case linear-time ellipsis matching.
def _ellipsis_match(want, got):
@@ -335,7 +323,8 @@ class _OutputRedirectingPdb(pdb.Pdb):
def __init__(self, out):
self.__out = out
self.__debugger_used = False
- pdb.Pdb.__init__(self, stdout=out)
+ # do not play signal games in the pdb
+ pdb.Pdb.__init__(self, stdout=out, nosigint=True)
# still use input() to get user input
self.use_rawinput = 1
@@ -364,9 +353,9 @@ class _OutputRedirectingPdb(pdb.Pdb):
# [XX] Normalize with respect to os.path.pardir?
def _module_relative_path(module, path):
if not inspect.ismodule(module):
- raise TypeError, 'Expected a module: %r' % module
+ raise TypeError('Expected a module: %r' % module)
if path.startswith('/'):
- raise ValueError, 'Module-relative files may not have absolute paths'
+ raise ValueError('Module-relative files may not have absolute paths')
# Find the base directory for the path.
if hasattr(module, '__file__'):
@@ -499,7 +488,7 @@ class DocTest:
Create a new DocTest containing the given examples. The
DocTest's globals are initialized with a copy of `globs`.
"""
- assert not isinstance(examples, basestring), \
+ assert not isinstance(examples, str), \
"DocTest no longer accepts str; use DocTestParser instead"
self.examples = examples
self.docstring = docstring
@@ -536,11 +525,12 @@ class DocTest:
return hash((self.docstring, self.name, self.filename, self.lineno))
# This lets us sort tests by name:
- def __cmp__(self, other):
+ def __lt__(self, other):
if not isinstance(other, DocTest):
- return -1
- return cmp((self.name, self.filename, self.lineno, id(self)),
- (other.name, other.filename, other.lineno, id(other)))
+ return NotImplemented
+ return ((self.name, self.filename, self.lineno, id(self))
+ <
+ (other.name, other.filename, other.lineno, id(other)))
######################################################################
## 3. DocTestParser
@@ -867,20 +857,29 @@ class DocTestFinder:
# DocTestFinder._find_lineno to find the line number for a
# given object's docstring.
try:
- file = inspect.getsourcefile(obj) or inspect.getfile(obj)
- if module is not None:
- # Supply the module globals in case the module was
- # originally loaded via a PEP 302 loader and
- # file is not a valid filesystem path
- source_lines = linecache.getlines(file, module.__dict__)
- else:
- # No access to a loader, so assume it's a normal
- # filesystem path
- source_lines = linecache.getlines(file)
- if not source_lines:
- source_lines = None
+ file = inspect.getsourcefile(obj)
except TypeError:
source_lines = None
+ else:
+ if not file:
+ # Check to see if it's one of our special internal "files"
+ # (see __patched_linecache_getlines).
+ file = inspect.getfile(obj)
+ if not file[0]+file[-2:] == '<]>': file = None
+ if file is None:
+ source_lines = None
+ else:
+ if module is not None:
+ # Supply the module globals in case the module was
+ # originally loaded via a PEP 302 loader and
+ # file is not a valid filesystem path
+ source_lines = linecache.getlines(file, module.__dict__)
+ else:
+ # No access to a loader, so assume it's a normal
+ # filesystem path
+ source_lines = linecache.getlines(file)
+ if not source_lines:
+ source_lines = None
# Initialize globals, and merge in extraglobs.
if globs is None:
@@ -915,7 +914,7 @@ class DocTestFinder:
elif inspect.getmodule(object) is not None:
return module is inspect.getmodule(object)
elif inspect.isfunction(object):
- return module.__dict__ is object.func_globals
+ return module.__dict__ is object.__globals__
elif inspect.isclass(object):
return module.__name__ == object.__module__
elif hasattr(object, '__module__'):
@@ -931,7 +930,7 @@ class DocTestFinder:
add them to `tests`.
"""
if self._verbose:
- print 'Finding tests in %s' % name
+ print('Finding tests in %s' % name)
# If we've already processed this object, then ignore it.
if id(obj) in seen:
@@ -956,13 +955,13 @@ class DocTestFinder:
# Look for tests in a module's __test__ dictionary.
if inspect.ismodule(obj) and self._recurse:
for valname, val in getattr(obj, '__test__', {}).items():
- if not isinstance(valname, basestring):
+ if not isinstance(valname, str):
raise ValueError("DocTestFinder.find: __test__ keys "
"must be strings: %r" %
(type(valname),))
if not (inspect.isfunction(val) or inspect.isclass(val) or
inspect.ismethod(val) or inspect.ismodule(val) or
- isinstance(val, basestring)):
+ isinstance(val, str)):
raise ValueError("DocTestFinder.find: __test__ values "
"must be strings, functions, methods, "
"classes, or modules: %r" %
@@ -978,7 +977,7 @@ class DocTestFinder:
if isinstance(val, staticmethod):
val = getattr(obj, valname)
if isinstance(val, classmethod):
- val = getattr(obj, valname).im_func
+ val = getattr(obj, valname).__func__
# Recurse to methods, properties, and nested classes.
if ((inspect.isfunction(val) or inspect.isclass(val) or
@@ -995,7 +994,7 @@ class DocTestFinder:
"""
# Extract the object's docstring. If it doesn't have one,
# then return None (no test for this object).
- if isinstance(obj, basestring):
+ if isinstance(obj, str):
docstring = obj
else:
try:
@@ -1003,7 +1002,7 @@ class DocTestFinder:
docstring = ''
else:
docstring = obj.__doc__
- if not isinstance(docstring, basestring):
+ if not isinstance(docstring, str):
docstring = str(docstring)
except (TypeError, AttributeError):
docstring = ''
@@ -1050,8 +1049,8 @@ class DocTestFinder:
break
# Find the line number for functions & methods.
- if inspect.ismethod(obj): obj = obj.im_func
- if inspect.isfunction(obj): obj = obj.func_code
+ if inspect.ismethod(obj): obj = obj.__func__
+ if inspect.isfunction(obj): obj = obj.__code__
if inspect.istraceback(obj): obj = obj.tb_frame
if inspect.isframe(obj): obj = obj.f_code
if inspect.iscode(obj):
@@ -1088,7 +1087,7 @@ class DocTestRunner:
>>> runner = DocTestRunner(verbose=False)
>>> tests.sort(key = lambda test: test.name)
>>> for test in tests:
- ... print test.name, '->', runner.run(test)
+ ... print(test.name, '->', runner.run(test))
_TestClass -> TestResults(failed=0, attempted=2)
_TestClass.__init__ -> TestResults(failed=0, attempted=2)
_TestClass.get -> TestResults(failed=0, attempted=2)
@@ -1285,8 +1284,8 @@ class DocTestRunner:
# keyboard interrupts.)
try:
# Don't blink! This is where the user's code gets run.
- exec compile(example.source, filename, "single",
- compileflags, 1) in test.globs
+ exec(compile(example.source, filename, "single",
+ compileflags, 1), test.globs)
self.debugger.set_continue() # ==== Example Finished ====
exception = None
except KeyboardInterrupt:
@@ -1307,10 +1306,9 @@ class DocTestRunner:
# The example raised an exception: check if it was expected.
else:
- exc_info = sys.exc_info()
- exc_msg = traceback.format_exception_only(*exc_info[:2])[-1]
+ exc_msg = traceback.format_exception_only(*exception[:2])[-1]
if not quiet:
- got += _exception_traceback(exc_info)
+ got += _exception_traceback(exception)
# If `example.exc_msg` is None, then we weren't expecting
# an exception.
@@ -1340,7 +1338,7 @@ class DocTestRunner:
elif outcome is BOOM:
if not quiet:
self.report_unexpected_exception(out, test, example,
- exc_info)
+ exception)
failures += 1
else:
assert False, ("unknown outcome", outcome)
@@ -1369,10 +1367,7 @@ class DocTestRunner:
m = self.__LINECACHE_FILENAME_RE.match(filename)
if m and m.group('name') == self.test.name:
example = self.test.examples[int(m.group('examplenum'))]
- source = example.source
- if isinstance(source, unicode):
- source = source.encode('ascii', 'backslashreplace')
- return source.splitlines(True)
+ return example.source.splitlines(True)
else:
return self.save_linecache_getlines(filename, module_globals)
@@ -1403,7 +1398,14 @@ class DocTestRunner:
save_stdout = sys.stdout
if out is None:
- out = save_stdout.write
+ encoding = save_stdout.encoding
+ if encoding is None or encoding.lower() == 'utf-8':
+ out = save_stdout.write
+ else:
+ # Use backslashreplace error handling on write
+ def out(s):
+ s = str(s.encode(encoding, 'backslashreplace'), encoding)
+ save_stdout.write(s)
sys.stdout = self._fakeout
# Patch pdb.set_trace to restore sys.stdout during interactive
@@ -1434,6 +1436,8 @@ class DocTestRunner:
sys.displayhook = save_displayhook
if clear_globs:
test.globs.clear()
+ import builtins
+ builtins._ = None
#/////////////////////////////////////////////////////////////////
# Summarization
@@ -1468,28 +1472,28 @@ class DocTestRunner:
failed.append(x)
if verbose:
if notests:
- print len(notests), "items had no tests:"
+ print(len(notests), "items had no tests:")
notests.sort()
for thing in notests:
- print " ", thing
+ print(" ", thing)
if passed:
- print len(passed), "items passed all tests:"
+ print(len(passed), "items passed all tests:")
passed.sort()
for thing, count in passed:
- print " %3d tests in %s" % (count, thing)
+ print(" %3d tests in %s" % (count, thing))
if failed:
- print self.DIVIDER
- print len(failed), "items had failures:"
+ print(self.DIVIDER)
+ print(len(failed), "items had failures:")
failed.sort()
for thing, (f, t) in failed:
- print " %3d of %3d in %s" % (f, t, thing)
+ print(" %3d of %3d in %s" % (f, t, thing))
if verbose:
- print totalt, "tests in", len(self._name2ft), "items."
- print totalt - totalf, "passed and", totalf, "failed."
+ print(totalt, "tests in", len(self._name2ft), "items.")
+ print(totalt - totalf, "passed and", totalf, "failed.")
if totalf:
- print "***Test Failed***", totalf, "failures."
+ print("***Test Failed***", totalf, "failures.")
elif verbose:
- print "Test passed."
+ print("Test passed.")
return TestResults(totalf, totalt)
#/////////////////////////////////////////////////////////////////
@@ -1501,8 +1505,8 @@ class DocTestRunner:
if name in d:
# Don't print here by default, since doing
# so breaks some of the buildbots
- #print "*** DocTestRunner.merge: '" + name + "' in both" \
- # " testers; summing outcomes."
+ #print("*** DocTestRunner.merge: '" + name + "' in both" \
+ # " testers; summing outcomes.")
f2, t2 = d[name]
f = f + f2
t = t + t2
@@ -1516,6 +1520,12 @@ class OutputChecker:
and returns true if they match; and `output_difference`, which
returns a string describing the differences between two outputs.
"""
+ def _toAscii(self, s):
+ """
+ Convert string to hex-escaped ASCII string.
+ """
+ return str(s.encode('ASCII', 'backslashreplace'), "ASCII")
+
def check_output(self, want, got, optionflags):
"""
Return True iff the actual output from an example (`got`)
@@ -1526,6 +1536,15 @@ class OutputChecker:
documentation for `TestRunner` for more information about
option flags.
"""
+
+ # If `want` contains hex-escaped character such as "\u1234",
+ # then `want` is a string of six characters(e.g. [\,u,1,2,3,4]).
+ # On the other hand, `got` could be an another sequence of
+ # characters such as [\u1234], so `want` and `got` should
+ # be folded to hex-escaped ASCII string to compare.
+ got = self._toAscii(got)
+ want = self._toAscii(want)
+
# Handle the common case first, for efficiency:
# if they're string-identical, always return true.
if got == want:
@@ -1690,8 +1709,8 @@ class DebugRunner(DocTestRunner):
... {}, 'foo', 'foo.py', 0)
>>> try:
... runner.run(test)
- ... except UnexpectedException, failure:
- ... pass
+ ... except UnexpectedException as f:
+ ... failure = f
>>> failure.test is test
True
@@ -1700,7 +1719,7 @@ class DebugRunner(DocTestRunner):
'42\n'
>>> exc_info = failure.exc_info
- >>> raise exc_info[0], exc_info[1], exc_info[2]
+ >>> raise exc_info[1] # Already has the traceback
Traceback (most recent call last):
...
KeyError
@@ -1718,8 +1737,8 @@ class DebugRunner(DocTestRunner):
>>> try:
... runner.run(test)
- ... except DocTestFailure, failure:
- ... pass
+ ... except DocTestFailure as f:
+ ... failure = f
DocTestFailure objects provide access to the test:
@@ -1750,7 +1769,7 @@ class DebugRunner(DocTestRunner):
>>> runner.run(test)
Traceback (most recent call last):
...
- UnexpectedException: <DocTest foo from foo.py:0 (2 examples)>
+ doctest.UnexpectedException: <DocTest foo from foo.py:0 (2 examples)>
>>> del test.globs['__builtins__']
>>> test.globs
@@ -1982,7 +2001,8 @@ def testfile(filename, module_relative=True, name=None, package=None,
"relative paths.")
# Relativize the path
- text, filename = _load_testfile(filename, package, module_relative)
+ text, filename = _load_testfile(filename, package, module_relative,
+ encoding or "utf-8")
# If no name was given, then use the file's name.
if name is None:
@@ -2003,9 +2023,6 @@ def testfile(filename, module_relative=True, name=None, package=None,
else:
runner = DocTestRunner(verbose=verbose, optionflags=optionflags)
- if encoding is not None:
- text = text.decode(encoding)
-
# Read the file, convert it to a test, and run it.
test = parser.get_doctest(text, globs, name, filename, 0)
runner.run(test)
@@ -2044,72 +2061,7 @@ def run_docstring_examples(f, globs, verbose=False, name="NoName",
runner.run(test, compileflags=compileflags)
######################################################################
-## 7. Tester
-######################################################################
-# This is provided only for backwards compatibility. It's not
-# actually used in any way.
-
-class Tester:
- def __init__(self, mod=None, globs=None, verbose=None, optionflags=0):
-
- warnings.warn("class Tester is deprecated; "
- "use class doctest.DocTestRunner instead",
- DeprecationWarning, stacklevel=2)
- if mod is None and globs is None:
- raise TypeError("Tester.__init__: must specify mod or globs")
- if mod is not None and not inspect.ismodule(mod):
- raise TypeError("Tester.__init__: mod must be a module; %r" %
- (mod,))
- if globs is None:
- globs = mod.__dict__
- self.globs = globs
-
- self.verbose = verbose
- self.optionflags = optionflags
- self.testfinder = DocTestFinder()
- self.testrunner = DocTestRunner(verbose=verbose,
- optionflags=optionflags)
-
- def runstring(self, s, name):
- test = DocTestParser().get_doctest(s, self.globs, name, None, None)
- if self.verbose:
- print "Running string", name
- (f,t) = self.testrunner.run(test)
- if self.verbose:
- print f, "of", t, "examples failed in string", name
- return TestResults(f,t)
-
- def rundoc(self, object, name=None, module=None):
- f = t = 0
- tests = self.testfinder.find(object, name, module=module,
- globs=self.globs)
- for test in tests:
- (f2, t2) = self.testrunner.run(test)
- (f,t) = (f+f2, t+t2)
- return TestResults(f,t)
-
- def rundict(self, d, name, module=None):
- import types
- m = types.ModuleType(name)
- m.__dict__.update(d)
- if module is None:
- module = False
- return self.rundoc(m, name, module)
-
- def run__test__(self, d, name):
- import types
- m = types.ModuleType(name)
- m.__test__ = d
- return self.rundoc(m, name)
-
- def summarize(self, verbose=None):
- return self.testrunner.summarize(verbose)
-
- def merge(self, other):
- self.testrunner.merge(other.testrunner)
-
-######################################################################
-## 8. Unittest Support
+## 7. Unittest Support
######################################################################
_unittest_reportflags = 0
@@ -2229,8 +2181,8 @@ class DocTestCase(unittest.TestCase):
>>> case = DocTestCase(test)
>>> try:
... case.debug()
- ... except UnexpectedException, failure:
- ... pass
+ ... except UnexpectedException as f:
+ ... failure = f
The UnexpectedException contains the test, the example, and
the original exception:
@@ -2242,7 +2194,7 @@ class DocTestCase(unittest.TestCase):
'42\n'
>>> exc_info = failure.exc_info
- >>> raise exc_info[0], exc_info[1], exc_info[2]
+ >>> raise exc_info[1] # Already has the traceback
Traceback (most recent call last):
...
KeyError
@@ -2258,8 +2210,8 @@ class DocTestCase(unittest.TestCase):
>>> try:
... case.debug()
- ... except DocTestFailure, failure:
- ... pass
+ ... except DocTestFailure as f:
+ ... failure = f
DocTestFailure objects provide access to the test:
@@ -2430,7 +2382,8 @@ def DocFileTest(path, module_relative=True, package=None,
"relative paths.")
# Relativize the path.
- doc, path = _load_testfile(path, package, module_relative)
+ doc, path = _load_testfile(path, package, module_relative,
+ encoding or "utf-8")
if "__file__" not in globs:
globs["__file__"] = path
@@ -2438,10 +2391,6 @@ def DocFileTest(path, module_relative=True, package=None,
# Find the file and read it.
name = os.path.basename(path)
- # If an encoding is specified, use it to convert the file to unicode
- if encoding is not None:
- doc = doc.decode(encoding)
-
# Convert it to a test, and wrap it in a DocFileCase.
test = parser.get_doctest(doc, globs, name, path, 0)
return DocFileCase(test, **options)
@@ -2516,7 +2465,7 @@ def DocFileSuite(*paths, **kw):
return suite
######################################################################
-## 9. Debugging Support
+## 8. Debugging Support
######################################################################
def script_from_examples(s):
@@ -2551,7 +2500,7 @@ def script_from_examples(s):
... Ho hum
... '''
- >>> print script_from_examples(text)
+ >>> print(script_from_examples(text))
# Here are examples of simple math.
#
# Python has super accurate integer addition
@@ -2626,33 +2575,21 @@ def debug_script(src, pm=False, globs=None):
"Debug a test script. `src` is the script, as a string."
import pdb
- # Note that tempfile.NameTemporaryFile() cannot be used. As the
- # docs say, a file so created cannot be opened by name a second time
- # on modern Windows boxes, and execfile() needs to open it.
- srcfilename = tempfile.mktemp(".py", "doctestdebug")
- f = open(srcfilename, 'w')
- f.write(src)
- f.close()
-
- try:
- if globs:
- globs = globs.copy()
- else:
- globs = {}
-
- if pm:
- try:
- execfile(srcfilename, globs, globs)
- except:
- print sys.exc_info()[1]
- pdb.post_mortem(sys.exc_info()[2])
- else:
- # Note that %r is vital here. '%s' instead can, e.g., cause
- # backslashes to get treated as metacharacters on Windows.
- pdb.run("execfile(%r)" % srcfilename, globs, globs)
+ if globs:
+ globs = globs.copy()
+ else:
+ globs = {}
- finally:
- os.remove(srcfilename)
+ if pm:
+ try:
+ exec(src, globs, globs)
+ except:
+ print(sys.exc_info()[1])
+ p = pdb.Pdb(nosigint=True)
+ p.reset()
+ p.interaction(None, sys.exc_info()[2])
+ else:
+ pdb.Pdb(nosigint=True).run("exec(%r)" % src, globs, globs)
def debug(module, name, pm=False):
"""Debug a single doctest docstring.
@@ -2666,7 +2603,7 @@ def debug(module, name, pm=False):
debug_script(testsrc, pm, module.__dict__)
######################################################################
-## 10. Example Usage
+## 9. Example Usage
######################################################################
class _TestClass:
"""
@@ -2686,7 +2623,7 @@ class _TestClass:
"""val -> _TestClass object with associated value val.
>>> t = _TestClass(123)
- >>> print t.get()
+ >>> print(t.get())
123
"""
@@ -2706,7 +2643,7 @@ class _TestClass:
"""get() -> return TestClass's associated value.
>>> x = _TestClass(-42)
- >>> print x.get()
+ >>> print(x.get())
-42
"""
@@ -2738,7 +2675,7 @@ __test__ = {"_TestClass": _TestClass,
"blank lines": r"""
Blank lines can be marked with <BLANKLINE>:
- >>> print 'foo\n\nbar\n'
+ >>> print('foo\n\nbar\n')
foo
<BLANKLINE>
bar
@@ -2748,14 +2685,14 @@ __test__ = {"_TestClass": _TestClass,
"ellipsis": r"""
If the ellipsis flag is used, then '...' can be used to
elide substrings in the desired output:
- >>> print range(1000) #doctest: +ELLIPSIS
+ >>> print(list(range(1000))) #doctest: +ELLIPSIS
[0, 1, 2, ..., 999]
""",
"whitespace normalization": r"""
If the whitespace normalization flag is used, then
differences in whitespace are ignored.
- >>> print range(30) #doctest: +NORMALIZE_WHITESPACE
+ >>> print(list(range(30))) #doctest: +NORMALIZE_WHITESPACE
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
27, 28, 29]