mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
Added NDIFF_DIFF option.
This commit is contained in:
parent
94607dd5ce
commit
c6cbab0db4
3 changed files with 68 additions and 10 deletions
|
@ -356,6 +356,15 @@ can also be used in doctest directives (see below).
|
||||||
actual outputs will be displayed using a context diff.
|
actual outputs will be displayed using a context diff.
|
||||||
\end{datadesc}
|
\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
|
A "doctest directive" is a trailing Python comment on a line of a doctest
|
||||||
example:
|
example:
|
||||||
|
@ -414,7 +423,8 @@ can be useful.
|
||||||
|
|
||||||
\versionchanged[Constants \constant{DONT_ACCEPT_BLANKLINE},
|
\versionchanged[Constants \constant{DONT_ACCEPT_BLANKLINE},
|
||||||
\constant{NORMALIZE_WHITESPACE}, \constant{ELLIPSIS},
|
\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
|
were added; by default \code{<BLANKLINE>} in expected output
|
||||||
matches an empty line in actual output; and doctest directives
|
matches an empty line in actual output; and doctest directives
|
||||||
were added]{2.4}
|
were added]{2.4}
|
||||||
|
|
|
@ -178,6 +178,7 @@ __all__ = [
|
||||||
'ELLIPSIS',
|
'ELLIPSIS',
|
||||||
'UNIFIED_DIFF',
|
'UNIFIED_DIFF',
|
||||||
'CONTEXT_DIFF',
|
'CONTEXT_DIFF',
|
||||||
|
'NDIFF_DIFF',
|
||||||
# 1. Utility Functions
|
# 1. Utility Functions
|
||||||
'is_private',
|
'is_private',
|
||||||
# 2. Example & DocTest
|
# 2. Example & DocTest
|
||||||
|
@ -253,6 +254,7 @@ NORMALIZE_WHITESPACE = register_optionflag('NORMALIZE_WHITESPACE')
|
||||||
ELLIPSIS = register_optionflag('ELLIPSIS')
|
ELLIPSIS = register_optionflag('ELLIPSIS')
|
||||||
UNIFIED_DIFF = register_optionflag('UNIFIED_DIFF')
|
UNIFIED_DIFF = register_optionflag('UNIFIED_DIFF')
|
||||||
CONTEXT_DIFF = register_optionflag('CONTEXT_DIFF')
|
CONTEXT_DIFF = register_optionflag('CONTEXT_DIFF')
|
||||||
|
NDIFF_DIFF = register_optionflag('NDIFF_DIFF')
|
||||||
|
|
||||||
# Special string markers for use in `want` strings:
|
# Special string markers for use in `want` strings:
|
||||||
BLANKLINE_MARKER = '<BLANKLINE>'
|
BLANKLINE_MARKER = '<BLANKLINE>'
|
||||||
|
@ -1569,6 +1571,24 @@ class OutputChecker:
|
||||||
# We didn't find any match; return false.
|
# We didn't find any match; return false.
|
||||||
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):
|
def output_difference(self, want, got, optionflags):
|
||||||
"""
|
"""
|
||||||
Return a string describing the differences between the
|
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
|
# Check if we should use diff. Don't use diff if the actual
|
||||||
# or expected outputs are too short, or if the expected output
|
# or expected outputs are too short, or if the expected output
|
||||||
# contains an ellipsis marker.
|
# contains an ellipsis marker.
|
||||||
if ((optionflags & (UNIFIED_DIFF | CONTEXT_DIFF)) and
|
if self._do_a_fancy_diff(want, got, optionflags):
|
||||||
want.count('\n') > 2 and got.count('\n') > 2 and
|
|
||||||
not (optionflags & ELLIPSIS and '...' in want)):
|
|
||||||
# Split want & got into lines.
|
# Split want & got into lines.
|
||||||
want_lines = [l+'\n' for l in want.split('\n')]
|
want_lines = [l+'\n' for l in want.split('\n')]
|
||||||
got_lines = [l+'\n' for l in got.split('\n')]
|
got_lines = [l+'\n' for l in got.split('\n')]
|
||||||
|
@ -1596,16 +1614,20 @@ class OutputChecker:
|
||||||
if optionflags & UNIFIED_DIFF:
|
if optionflags & UNIFIED_DIFF:
|
||||||
diff = difflib.unified_diff(want_lines, got_lines, n=2,
|
diff = difflib.unified_diff(want_lines, got_lines, n=2,
|
||||||
fromfile='Expected', tofile='Got')
|
fromfile='Expected', tofile='Got')
|
||||||
kind = 'unified'
|
kind = 'unified diff'
|
||||||
elif optionflags & CONTEXT_DIFF:
|
elif optionflags & CONTEXT_DIFF:
|
||||||
diff = difflib.context_diff(want_lines, got_lines, n=2,
|
diff = difflib.context_diff(want_lines, got_lines, n=2,
|
||||||
fromfile='Expected', tofile='Got')
|
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:
|
else:
|
||||||
assert 0, 'Bad diff option'
|
assert 0, 'Bad diff option'
|
||||||
# Remove trailing whitespace on diff output.
|
# Remove trailing whitespace on diff output.
|
||||||
diff = [line.rstrip() + '\n' for line in diff]
|
diff = [line.rstrip() + '\n' for line in diff]
|
||||||
return _tag_msg("Differences (" + kind + " diff)",
|
return _tag_msg("Differences (" + kind + ")",
|
||||||
''.join(diff))
|
''.join(diff))
|
||||||
|
|
||||||
# If we're not using diff, then simply list the expected
|
# If we're not using diff, then simply list the expected
|
||||||
|
|
|
@ -931,7 +931,33 @@ and actual outputs to be displayed using a context diff:
|
||||||
g
|
g
|
||||||
<BLANKLINE>
|
<BLANKLINE>
|
||||||
(1, 1)
|
(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"""
|
def option_directives(): r"""
|
||||||
Tests of `DocTestRunner`'s option directive mechanism.
|
Tests of `DocTestRunner`'s option directive mechanism.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue