Added NDIFF_DIFF option.
This commit is contained in:
parent
94607dd5ce
commit
c6cbab0db4
|
@ -356,6 +356,15 @@ can also be used in doctest directives (see below).
|
|||
actual outputs will be displayed using a context diff.
|
||||
\end{datadesc}
|
||||
|
||||
\begin{datadesc}{NDIFF_DIFF}
|
||||
When specified, differences are computed by \code{difflib.Differ},
|
||||
using the same algorithm as the popular \file{ndiff.py} utility.
|
||||
This is the only method that marks differences within lines as
|
||||
well as across lines. For example, if a line of expected output
|
||||
contains digit \code{1} where actual output contains letter \code{l},
|
||||
a line is inserted with a caret marking the mismatching column
|
||||
positions.
|
||||
\end{datadesc}
|
||||
|
||||
A "doctest directive" is a trailing Python comment on a line of a doctest
|
||||
example:
|
||||
|
@ -414,7 +423,8 @@ can be useful.
|
|||
|
||||
\versionchanged[Constants \constant{DONT_ACCEPT_BLANKLINE},
|
||||
\constant{NORMALIZE_WHITESPACE}, \constant{ELLIPSIS},
|
||||
\constant{UNIFIED_DIFF}, and \constant{CONTEXT_DIFF}
|
||||
\constant{UNIFIED_DIFF}, \constant{CONTEXT_DIFF}, and
|
||||
\constant{NDIFF_DIFF}
|
||||
were added; by default \code{<BLANKLINE>} in expected output
|
||||
matches an empty line in actual output; and doctest directives
|
||||
were added]{2.4}
|
||||
|
|
|
@ -178,6 +178,7 @@ __all__ = [
|
|||
'ELLIPSIS',
|
||||
'UNIFIED_DIFF',
|
||||
'CONTEXT_DIFF',
|
||||
'NDIFF_DIFF',
|
||||
# 1. Utility Functions
|
||||
'is_private',
|
||||
# 2. Example & DocTest
|
||||
|
@ -253,6 +254,7 @@ NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE')
|
|||
ELLIPSIS = register_optionflag('ELLIPSIS')
|
||||
UNIFIED_DIFF = register_optionflag('UNIFIED_DIFF')
|
||||
CONTEXT_DIFF = register_optionflag('CONTEXT_DIFF')
|
||||
NDIFF_DIFF = register_optionflag('NDIFF_DIFF')
|
||||
|
||||
# Special string markers for use in `want` strings:
|
||||
BLANKLINE_MARKER = '<BLANKLINE>'
|
||||
|
@ -1569,6 +1571,24 @@ class OutputChecker:
|
|||
# We didn't find any match; return false.
|
||||
return False
|
||||
|
||||
# Should we do a fancy diff?
|
||||
def _do_a_fancy_diff(self, want, got, optionflags):
|
||||
# Not unless they asked for a fancy diff.
|
||||
if not optionflags & (UNIFIED_DIFF |
|
||||
CONTEXT_DIFF |
|
||||
NDIFF_DIFF):
|
||||
return False
|
||||
# If expected output uses ellipsis, a meaningful fancy diff is
|
||||
# too hard.
|
||||
if optionflags & ELLIPSIS and ELLIPSIS_MARKER in want:
|
||||
return False
|
||||
# ndiff does intraline difference marking, so can be useful even
|
||||
# for 1-line inputs.
|
||||
if optionflags & NDIFF_DIFF:
|
||||
return True
|
||||
# The other diff types need at least a few lines to be helpful.
|
||||
return want.count('\n') > 2 and got.count('\n') > 2
|
||||
|
||||
def output_difference(self, want, got, optionflags):
|
||||
"""
|
||||
Return a string describing the differences between the
|
||||
|
@ -1586,9 +1606,7 @@ class OutputChecker:
|
|||
# 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)):
|
||||
if self._do_a_fancy_diff(want, got, optionflags):
|
||||
# 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')]
|
||||
|
@ -1596,16 +1614,20 @@ class OutputChecker:
|
|||
if optionflags & UNIFIED_DIFF:
|
||||
diff = difflib.unified_diff(want_lines, got_lines, n=2,
|
||||
fromfile='Expected', tofile='Got')
|
||||
kind = 'unified'
|
||||
kind = 'unified diff'
|
||||
elif optionflags & CONTEXT_DIFF:
|
||||
diff = difflib.context_diff(want_lines, got_lines, n=2,
|
||||
fromfile='Expected', tofile='Got')
|
||||
kind = 'context'
|
||||
kind = 'context diff'
|
||||
elif optionflags & NDIFF_DIFF:
|
||||
engine = difflib.Differ(charjunk=difflib.IS_CHARACTER_JUNK)
|
||||
diff = list(engine.compare(want_lines, got_lines))
|
||||
kind = 'ndiff with -expected +actual'
|
||||
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)",
|
||||
return _tag_msg("Differences (" + kind + ")",
|
||||
''.join(diff))
|
||||
|
||||
# If we're not using diff, then simply list the expected
|
||||
|
|
|
@ -283,7 +283,7 @@ We'll simulate a __file__ attr that ends in pyc:
|
|||
'test_doctest.py'
|
||||
|
||||
>>> test.test_doctest.__file__ = old
|
||||
|
||||
|
||||
|
||||
>>> e = tests[0].examples[0]
|
||||
>>> (e.source, e.want, e.lineno)
|
||||
|
@ -931,7 +931,33 @@ and actual outputs to be displayed using a context diff:
|
|||
g
|
||||
<BLANKLINE>
|
||||
(1, 1)
|
||||
"""
|
||||
|
||||
|
||||
The NDIFF_DIFF flag causes failures to use the difflib.Differ algorithm
|
||||
used by the popular ndiff.py utility. This does intraline difference
|
||||
marking, as well as interline differences.
|
||||
|
||||
>>> def f(x):
|
||||
... r'''
|
||||
... >>> print "a b c d e f g h i j k l m"
|
||||
... a b c d e f g h i j k 1 m
|
||||
... '''
|
||||
>>> test = doctest.DocTestFinder().find(f)[0]
|
||||
>>> flags = doctest.NDIFF_DIFF
|
||||
>>> doctest.DocTestRunner(verbose=False, optionflags=flags).run(test)
|
||||
**********************************************************************
|
||||
Line 2, in f
|
||||
Failed example:
|
||||
print "a b c d e f g h i j k l m"
|
||||
Differences (ndiff with -expected +actual):
|
||||
- a b c d e f g h i j k 1 m
|
||||
? ^
|
||||
+ a b c d e f g h i j k l m
|
||||
? + ++ ^
|
||||
<BLANKLINE>
|
||||
(1, 1)
|
||||
"""
|
||||
|
||||
def option_directives(): r"""
|
||||
Tests of `DocTestRunner`'s option directive mechanism.
|
||||
|
||||
|
@ -1468,7 +1494,7 @@ def test_DocFileSuite():
|
|||
def test_trailing_space_in_test():
|
||||
"""
|
||||
Trailing spaces in expcted output are significant:
|
||||
|
||||
|
||||
>>> x, y = 'foo', ''
|
||||
>>> print x, y
|
||||
foo \n
|
||||
|
|
Loading…
Reference in New Issue