[Python-checkins] python/dist/src/Lib doctest.py,1.46,1.47
edloper at users.sourceforge.net
edloper at users.sourceforge.net
Mon Aug 9 04:45:43 CEST 2004
Update of /cvsroot/python/python/dist/src/Lib
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv4376/dist/src/Lib
Modified Files:
doctest.py
Log Message:
- Split DocTestRunner's check_output and output_difference methods off
into their own class, OutputChecker.
- Added optional OutputChecker arguments to DocTestRunner,
DocTestCase, DocTestSuite.
Index: doctest.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/doctest.py,v
retrieving revision 1.46
retrieving revision 1.47
diff -C2 -d -r1.46 -r1.47
*** doctest.py 9 Aug 2004 02:06:06 -0000 1.46
--- doctest.py 9 Aug 2004 02:45:41 -0000 1.47
***************
*** 1063,1069 ****
######################################################################
- # [XX] Should overridable methods (eg DocTestRunner.check_output) be
- # named with a leading underscore?
-
class DocTestRunner:
"""
--- 1063,1066 ----
***************
*** 1106,1115 ****
The comparison between expected outputs and actual outputs is done
! by the `check_output` method. This comparison may be customized
! with a number of option flags; see the documentation for `testmod`
! for more information. If the option flags are insufficient, then
! the comparison may also be customized by subclassing
! DocTestRunner, and overriding the methods `check_output` and
! `output_difference`.
The test runner's display output can be controlled in two ways.
--- 1103,1111 ----
The comparison between expected outputs and actual outputs is done
! by an `OutputChecker`. This comparison may be customized with a
! number of option flags; see the documentation for `testmod` for
! more information. If the option flags are insufficient, then the
! comparison may also be customized by passing a subclass of
! `OutputChecker` to the constructor.
The test runner's display output can be controlled in two ways.
***************
*** 1126,1133 ****
DIVIDER = "*" * 70
! def __init__(self, verbose=None, optionflags=0):
"""
Create a new test runner.
Optional keyword arg 'verbose' prints lots of stuff if true,
only failures if false; by default, it's true iff '-v' is in
--- 1122,1133 ----
DIVIDER = "*" * 70
! def __init__(self, checker=None, verbose=None, optionflags=0):
"""
Create a new test runner.
+ Optional keyword arg `checker` is the `OutputChecker` that
+ should be used to compare the expected outputs and actual
+ outputs of doctest examples.
+
Optional keyword arg 'verbose' prints lots of stuff if true,
only failures if false; by default, it's true iff '-v' is in
***************
*** 1139,1142 ****
--- 1139,1143 ----
more information.
"""
+ self._checker = checker or OutputChecker()
if verbose is None:
verbose = '-v' in sys.argv
***************
*** 1153,1264 ****
#/////////////////////////////////////////////////////////////////
- # Output verification methods
- #/////////////////////////////////////////////////////////////////
- # These two methods should be updated together, since the
- # output_difference method needs to know what should be considered
- # to match by check_output.
-
- def check_output(self, want, got):
- """
- Return True iff the actual output (`got`) matches the expected
- output (`want`). These strings are always considered to match
- if they are identical; but depending on what option flags the
- test runner is using, several non-exact match types are also
- possible. See the documentation for `TestRunner` for more
- information about option flags.
- """
- # Handle the common case first, for efficiency:
- # if they're string-identical, always return true.
- if got == want:
- return True
-
- # The values True and False replaced 1 and 0 as the return
- # value for boolean comparisons in Python 2.3.
- if not (self.optionflags & DONT_ACCEPT_TRUE_FOR_1):
- if (got,want) == ("True\n", "1\n"):
- return True
- if (got,want) == ("False\n", "0\n"):
- return True
-
- # <BLANKLINE> can be used as a special sequence to signify a
- # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used.
- if not (self.optionflags & DONT_ACCEPT_BLANKLINE):
- # Replace <BLANKLINE> in want with a blank line.
- want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER),
- '', want)
- # If a line in got contains only spaces, then remove the
- # spaces.
- got = re.sub('(?m)^\s*?$', '', got)
- if got == want:
- return True
-
- # This flag causes doctest to ignore any differences in the
- # contents of whitespace strings. Note that this can be used
- # in conjunction with the ELLISPIS flag.
- if (self.optionflags & NORMALIZE_WHITESPACE):
- got = ' '.join(got.split())
- want = ' '.join(want.split())
- if got == want:
- return True
-
- # The ELLIPSIS flag says to let the sequence "..." in `want`
- # match any substring in `got`. We implement this by
- # transforming `want` into a regular expression.
- if (self.optionflags & ELLIPSIS):
- # Escape any special regexp characters
- want_re = re.escape(want)
- # Replace ellipsis markers ('...') with .*
- want_re = want_re.replace(re.escape(ELLIPSIS_MARKER), '.*')
- # Require that it matches the entire string; and set the
- # re.DOTALL flag (with '(?s)').
- want_re = '(?s)^%s$' % want_re
- # Check if the `want_re` regexp matches got.
- if re.match(want_re, got):
- return True
-
- # We didn't find any match; return false.
- return False
-
- def output_difference(self, want, got):
- """
- Return a string describing the differences between the
- expected output (`want`) and the actual output (`got`).
- """
- # If <BLANKLINE>s are being used, then replace <BLANKLINE>
- # with blank lines in the expected output string.
- if not (self.optionflags & DONT_ACCEPT_BLANKLINE):
- want = re.sub('(?m)^%s$' % re.escape(BLANKLINE_MARKER), '', want)
-
- # Check if we should use diff. Don't use diff if the actual
- # or expected outputs are too short, or if the expected output
- # contains an ellipsis marker.
- if ((self.optionflags & (UNIFIED_DIFF | CONTEXT_DIFF)) and
- want.count('\n') > 2 and got.count('\n') > 2 and
- not (self.optionflags & ELLIPSIS and '...' in want)):
- # Split want & got into lines.
- want_lines = [l+'\n' for l in want.split('\n')]
- got_lines = [l+'\n' for l in got.split('\n')]
- # Use difflib to find their differences.
- if self.optionflags & UNIFIED_DIFF:
- diff = difflib.unified_diff(want_lines, got_lines, n=2,
- fromfile='Expected', tofile='Got')
- kind = 'unified'
- elif self.optionflags & CONTEXT_DIFF:
- diff = difflib.context_diff(want_lines, got_lines, n=2,
- fromfile='Expected', tofile='Got')
- kind = 'context'
- else:
- assert 0, 'Bad diff option'
- # Remove trailing whitespace on diff output.
- diff = [line.rstrip() + '\n' for line in diff]
- return _tag_msg("Differences (" + kind + " diff)",
- ''.join(diff))
-
- # If we're not using diff, then simply list the expected
- # output followed by the actual output.
- return (_tag_msg("Expected", want or "Nothing") +
- _tag_msg("Got", got))
-
- #/////////////////////////////////////////////////////////////////
# Reporting methods
#/////////////////////////////////////////////////////////////////
--- 1154,1157 ----
***************
*** 1287,1291 ****
# Print an error message.
out(self.__failure_header(test, example) +
! self.output_difference(example.want, got))
def report_unexpected_exception(self, out, test, example, exc_info):
--- 1180,1185 ----
# Print an error message.
out(self.__failure_header(test, example) +
! self._checker.output_difference(example.want, got,
! self.optionflags))
def report_unexpected_exception(self, out, test, example, exc_info):
***************
*** 1413,1417 ****
# then verify its output and report its outcome.
if exception is None:
! if self.check_output(example.want, got):
self.report_success(out, test, example, got)
else:
--- 1307,1312 ----
# then verify its output and report its outcome.
if exception is None:
! if self._checker.check_output(example.want, got,
! self.optionflags):
self.report_success(out, test, example, got)
else:
***************
*** 1437,1442 ****
# the exception description match the values given
# in `want`.
! if (self.check_output(m.group('out'), got) and
! self.check_output(m.group('exc'), exc_msg)):
# Is +exc_msg the right thing here??
self.report_success(out, test, example,
--- 1332,1339 ----
# the exception description match the values given
# in `want`.
! if (self._checker.check_output(m.group('out'), got,
! self.optionflags) and
! self._checker.check_output(m.group('exc'), exc_msg,
! self.optionflags)):
# Is +exc_msg the right thing here??
self.report_success(out, test, example,
***************
*** 1555,1558 ****
--- 1452,1564 ----
return totalf, totalt
+ class OutputChecker:
+ """
+ A class used to check the whether the actual output from a doctest
+ example matches the expected output. `OutputChecker` defines two
+ methods: `check_output`, which compares a given pair of outputs,
+ and returns true if they match; and `output_difference`, which
+ returns a string describing the differences between two outputs.
+ """
+ def check_output(self, want, got, optionflags):
+ """
+ Return True iff the actual output (`got`) matches the expected
+ output (`want`). These strings are always considered to match
+ if they are identical; but depending on what option flags the
+ test runner is using, several non-exact match types are also
+ possible. See the documentation for `TestRunner` for more
+ information about option flags.
+ """
+ # Handle the common case first, for efficiency:
+ # if they're string-identical, always return true.
+ if got == want:
+ return True
+
+ # The values True and False replaced 1 and 0 as the return
+ # value for boolean comparisons in Python 2.3.
+ if not (optionflags & DONT_ACCEPT_TRUE_FOR_1):
+ if (got,want) == ("True\n", "1\n"):
+ return True
+ if (got,want) == ("False\n", "0\n"):
+ return True
+
+ # <BLANKLINE> can be used as a special sequence to signify a
+ # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used.
+ if not (optionflags & DONT_ACCEPT_BLANKLINE):
+ # Replace <BLANKLINE> in want with a blank line.
+ want = re.sub('(?m)^%s\s*?$' % re.escape(BLANKLINE_MARKER),
+ '', want)
+ # If a line in got contains only spaces, then remove the
+ # spaces.
+ got = re.sub('(?m)^\s*?$', '', got)
+ if got == want:
+ return True
+
+ # This flag causes doctest to ignore any differences in the
+ # contents of whitespace strings. Note that this can be used
+ # in conjunction with the ELLISPIS flag.
+ if (optionflags & NORMALIZE_WHITESPACE):
+ got = ' '.join(got.split())
+ want = ' '.join(want.split())
+ if got == want:
+ return True
+
+ # The ELLIPSIS flag says to let the sequence "..." in `want`
+ # match any substring in `got`. We implement this by
+ # transforming `want` into a regular expression.
+ if (optionflags & ELLIPSIS):
+ # Escape any special regexp characters
+ want_re = re.escape(want)
+ # Replace ellipsis markers ('...') with .*
+ want_re = want_re.replace(re.escape(ELLIPSIS_MARKER), '.*')
+ # Require that it matches the entire string; and set the
+ # re.DOTALL flag (with '(?s)').
+ want_re = '(?s)^%s$' % want_re
+ # Check if the `want_re` regexp matches got.
+ if re.match(want_re, got):
+ return True
+
+ # We didn't find any match; return false.
+ return False
+
+ def output_difference(self, want, got, optionflags):
+ """
+ Return a string describing the differences between the
+ expected output (`want`) and the actual output (`got`).
+ """
+ # If <BLANKLINE>s are being used, then replace <BLANKLINE>
+ # with blank lines in the expected output string.
+ if not (optionflags & DONT_ACCEPT_BLANKLINE):
+ want = re.sub('(?m)^%s$' % re.escape(BLANKLINE_MARKER), '', want)
+
+ # Check if we should use diff. Don't use diff if the actual
+ # or expected outputs are too short, or if the expected output
+ # contains an ellipsis marker.
+ if ((optionflags & (UNIFIED_DIFF | CONTEXT_DIFF)) and
+ want.count('\n') > 2 and got.count('\n') > 2 and
+ not (optionflags & ELLIPSIS and '...' in want)):
+ # Split want & got into lines.
+ want_lines = [l+'\n' for l in want.split('\n')]
+ got_lines = [l+'\n' for l in got.split('\n')]
+ # Use difflib to find their differences.
+ if optionflags & UNIFIED_DIFF:
+ diff = difflib.unified_diff(want_lines, got_lines, n=2,
+ fromfile='Expected', tofile='Got')
+ kind = 'unified'
+ elif optionflags & CONTEXT_DIFF:
+ diff = difflib.context_diff(want_lines, got_lines, n=2,
+ fromfile='Expected', tofile='Got')
+ kind = 'context'
+ else:
+ assert 0, 'Bad diff option'
+ # Remove trailing whitespace on diff output.
+ diff = [line.rstrip() + '\n' for line in diff]
+ return _tag_msg("Differences (" + kind + " diff)",
+ ''.join(diff))
+
+ # If we're not using diff, then simply list the expected
+ # output followed by the actual output.
+ return (_tag_msg("Expected", want or "Nothing") +
+ _tag_msg("Got", got))
+
class DocTestFailure(Exception):
"""A DocTest example has failed in debugging mode.
***************
*** 1938,1944 ****
class DocTestCase(unittest.TestCase):
! def __init__(self, test, optionflags=0, setUp=None, tearDown=None):
unittest.TestCase.__init__(self)
self._dt_optionflags = optionflags
self._dt_test = test
self._dt_setUp = setUp
--- 1944,1952 ----
class DocTestCase(unittest.TestCase):
! def __init__(self, test, optionflags=0, setUp=None, tearDown=None,
! checker=None):
unittest.TestCase.__init__(self)
self._dt_optionflags = optionflags
+ self._dt_checker = checker
self._dt_test = test
self._dt_setUp = setUp
***************
*** 1957,1961 ****
old = sys.stdout
new = StringIO()
! runner = DocTestRunner(optionflags=self._dt_optionflags, verbose=False)
try:
--- 1965,1970 ----
old = sys.stdout
new = StringIO()
! runner = DocTestRunner(optionflags=self._dt_optionflags,
! checker=self._dt_checker, verbose=False)
try:
***************
*** 2046,2050 ****
"""
! runner = DebugRunner(verbose = False, optionflags=self._dt_optionflags)
runner.run(self._dt_test, out=nooutput)
--- 2055,2060 ----
"""
! runner = DebugRunner(optionflags=self._dt_optionflags,
! checker=self._dt_checker, verbose=False)
runner.run(self._dt_test, out=nooutput)
***************
*** 2066,2070 ****
def DocTestSuite(module=None, globs=None, extraglobs=None,
optionflags=0, test_finder=None,
! setUp=lambda: None, tearDown=lambda: None):
"""
Convert doctest tests for a mudule to a unittest test suite.
--- 2076,2081 ----
def DocTestSuite(module=None, globs=None, extraglobs=None,
optionflags=0, test_finder=None,
! setUp=lambda: None, tearDown=lambda: None,
! checker=None):
"""
Convert doctest tests for a mudule to a unittest test suite.
***************
*** 2104,2108 ****
filename = filename[:-1]
test.filename = filename
! suite.addTest(DocTestCase(test, optionflags, setUp, tearDown))
return suite
--- 2115,2120 ----
filename = filename[:-1]
test.filename = filename
! suite.addTest(DocTestCase(test, optionflags, setUp, tearDown,
! checker))
return suite
More information about the Python-checkins
mailing list