2009-07-19 18:01:52 -03:00
|
|
|
"""Various utility functions."""
|
|
|
|
|
2018-01-24 03:49:58 -04:00
|
|
|
from collections import namedtuple, Counter
|
2013-09-23 17:07:00 -03:00
|
|
|
from os.path import commonprefix
|
Improve diff for assertCountEqual() to actually show the differing counts.
New output looks like this:
Traceback (most recent call last):
File "test.py", line 5, in test_ce
self.assertCountEqual('abracadabra xx', 'simsalabim xx')
AssertionError: Element counts were not equal:
Expected 5, got 2: 'a'
Expected 2, got 1: 'b'
Expected 0, got 2: 'i'
Expected 0, got 2: 'm'
Expected 0, got 1: 'l'
Expected 0, got 2: 's'
Expected 1, got 0: 'c'
Expected 1, got 0: 'd'
Expected 2, got 0: 'r'
2010-12-24 06:02:22 -04:00
|
|
|
|
2010-03-21 21:15:53 -03:00
|
|
|
__unittest = True
|
|
|
|
|
2010-06-05 10:14:43 -03:00
|
|
|
_MAX_LENGTH = 80
|
2013-09-23 17:07:00 -03:00
|
|
|
_PLACEHOLDER_LEN = 12
|
|
|
|
_MIN_BEGIN_LEN = 5
|
|
|
|
_MIN_END_LEN = 5
|
|
|
|
_MIN_COMMON_LEN = 5
|
|
|
|
_MIN_DIFF_LEN = _MAX_LENGTH - \
|
|
|
|
(_MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN +
|
|
|
|
_PLACEHOLDER_LEN + _MIN_END_LEN)
|
|
|
|
assert _MIN_DIFF_LEN >= 0
|
|
|
|
|
|
|
|
def _shorten(s, prefixlen, suffixlen):
|
|
|
|
skip = len(s) - prefixlen - suffixlen
|
|
|
|
if skip > _PLACEHOLDER_LEN:
|
|
|
|
s = '%s[%d chars]%s' % (s[:prefixlen], skip, s[len(s) - suffixlen:])
|
|
|
|
return s
|
|
|
|
|
|
|
|
def _common_shorten_repr(*args):
|
|
|
|
args = tuple(map(safe_repr, args))
|
|
|
|
maxlen = max(map(len, args))
|
|
|
|
if maxlen <= _MAX_LENGTH:
|
|
|
|
return args
|
|
|
|
|
|
|
|
prefix = commonprefix(args)
|
|
|
|
prefixlen = len(prefix)
|
|
|
|
|
|
|
|
common_len = _MAX_LENGTH - \
|
|
|
|
(maxlen - prefixlen + _MIN_BEGIN_LEN + _PLACEHOLDER_LEN)
|
|
|
|
if common_len > _MIN_COMMON_LEN:
|
|
|
|
assert _MIN_BEGIN_LEN + _PLACEHOLDER_LEN + _MIN_COMMON_LEN + \
|
|
|
|
(maxlen - prefixlen) < _MAX_LENGTH
|
|
|
|
prefix = _shorten(prefix, _MIN_BEGIN_LEN, common_len)
|
|
|
|
return tuple(prefix + s[prefixlen:] for s in args)
|
|
|
|
|
|
|
|
prefix = _shorten(prefix, _MIN_BEGIN_LEN, _MIN_COMMON_LEN)
|
|
|
|
return tuple(prefix + _shorten(s[prefixlen:], _MIN_DIFF_LEN, _MIN_END_LEN)
|
|
|
|
for s in args)
|
|
|
|
|
2010-06-05 10:14:43 -03:00
|
|
|
def safe_repr(obj, short=False):
|
Merged revisions 78227,78229,78288,78348,78377,78770,78774-78776,78810 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r78227 | michael.foord | 2010-02-18 14:30:09 -0600 (Thu, 18 Feb 2010) | 1 line
unittest.TestCase uses safe_repr for producing failure messages. Partial fix for issue 7956
........
r78229 | michael.foord | 2010-02-18 15:37:07 -0600 (Thu, 18 Feb 2010) | 1 line
Fix unittest.TestCase.assertDictContainsSubset so it can't die with unicode issues when constructing failure messages. Issue 7956
........
r78288 | michael.foord | 2010-02-21 08:48:59 -0600 (Sun, 21 Feb 2010) | 1 line
Silence UnicodeWarning in crazy unittest test.
........
r78348 | michael.foord | 2010-02-22 17:28:32 -0600 (Mon, 22 Feb 2010) | 1 line
Support for old TestResult object (unittest) with warnings when using unsupported features.
........
r78377 | michael.foord | 2010-02-23 11:00:53 -0600 (Tue, 23 Feb 2010) | 1 line
unittest.TestResult can now be used with the TextTestRunner. TextTestRunner compatible with old TestResult objects.
........
r78770 | michael.foord | 2010-03-07 14:22:12 -0600 (Sun, 07 Mar 2010) | 1 line
Fix for potentials errors in constructing unittest failure messages. Plus skipped test methods no longer run setUp and tearDown (Issue 8059)
........
r78774 | michael.foord | 2010-03-07 16:04:55 -0600 (Sun, 07 Mar 2010) | 1 line
Addition of setUpClass and setUpModule shared fixtures to unittest.
........
r78775 | michael.foord | 2010-03-07 17:10:36 -0600 (Sun, 07 Mar 2010) | 1 line
Fix accidental name rebinding in unittest py3k warning filtering.
........
r78776 | michael.foord | 2010-03-07 17:16:20 -0600 (Sun, 07 Mar 2010) | 1 line
Remove accidental print statement from last commit.
........
r78810 | raymond.hettinger | 2010-03-09 02:44:18 -0600 (Tue, 09 Mar 2010) | 5 lines
Improve the basic example.
* Show both the decorator and regular form for assertRaises()
* Use assertTrue() instead of assertIn() to teach useful minimal subset of the API
........
2010-03-14 12:04:17 -03:00
|
|
|
try:
|
2010-06-05 10:14:43 -03:00
|
|
|
result = repr(obj)
|
Merged revisions 78227,78229,78288,78348,78377,78770,78774-78776,78810 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r78227 | michael.foord | 2010-02-18 14:30:09 -0600 (Thu, 18 Feb 2010) | 1 line
unittest.TestCase uses safe_repr for producing failure messages. Partial fix for issue 7956
........
r78229 | michael.foord | 2010-02-18 15:37:07 -0600 (Thu, 18 Feb 2010) | 1 line
Fix unittest.TestCase.assertDictContainsSubset so it can't die with unicode issues when constructing failure messages. Issue 7956
........
r78288 | michael.foord | 2010-02-21 08:48:59 -0600 (Sun, 21 Feb 2010) | 1 line
Silence UnicodeWarning in crazy unittest test.
........
r78348 | michael.foord | 2010-02-22 17:28:32 -0600 (Mon, 22 Feb 2010) | 1 line
Support for old TestResult object (unittest) with warnings when using unsupported features.
........
r78377 | michael.foord | 2010-02-23 11:00:53 -0600 (Tue, 23 Feb 2010) | 1 line
unittest.TestResult can now be used with the TextTestRunner. TextTestRunner compatible with old TestResult objects.
........
r78770 | michael.foord | 2010-03-07 14:22:12 -0600 (Sun, 07 Mar 2010) | 1 line
Fix for potentials errors in constructing unittest failure messages. Plus skipped test methods no longer run setUp and tearDown (Issue 8059)
........
r78774 | michael.foord | 2010-03-07 16:04:55 -0600 (Sun, 07 Mar 2010) | 1 line
Addition of setUpClass and setUpModule shared fixtures to unittest.
........
r78775 | michael.foord | 2010-03-07 17:10:36 -0600 (Sun, 07 Mar 2010) | 1 line
Fix accidental name rebinding in unittest py3k warning filtering.
........
r78776 | michael.foord | 2010-03-07 17:16:20 -0600 (Sun, 07 Mar 2010) | 1 line
Remove accidental print statement from last commit.
........
r78810 | raymond.hettinger | 2010-03-09 02:44:18 -0600 (Tue, 09 Mar 2010) | 5 lines
Improve the basic example.
* Show both the decorator and regular form for assertRaises()
* Use assertTrue() instead of assertIn() to teach useful minimal subset of the API
........
2010-03-14 12:04:17 -03:00
|
|
|
except Exception:
|
2010-06-05 10:14:43 -03:00
|
|
|
result = object.__repr__(obj)
|
|
|
|
if not short or len(result) < _MAX_LENGTH:
|
|
|
|
return result
|
|
|
|
return result[:_MAX_LENGTH] + ' [truncated]...'
|
|
|
|
|
2009-07-19 18:01:52 -03:00
|
|
|
def strclass(cls):
|
2014-07-22 09:00:37 -03:00
|
|
|
return "%s.%s" % (cls.__module__, cls.__qualname__)
|
2009-07-19 18:01:52 -03:00
|
|
|
|
|
|
|
def sorted_list_difference(expected, actual):
|
|
|
|
"""Finds elements in only one or the other of two, sorted input lists.
|
|
|
|
|
|
|
|
Returns a two-element tuple of lists. The first list contains those
|
|
|
|
elements in the "expected" list but not in the "actual" list, and the
|
|
|
|
second contains those elements in the "actual" list but not in the
|
|
|
|
"expected" list. Duplicate elements in either input list are ignored.
|
|
|
|
"""
|
|
|
|
i = j = 0
|
|
|
|
missing = []
|
|
|
|
unexpected = []
|
|
|
|
while True:
|
|
|
|
try:
|
|
|
|
e = expected[i]
|
|
|
|
a = actual[j]
|
|
|
|
if e < a:
|
|
|
|
missing.append(e)
|
|
|
|
i += 1
|
|
|
|
while expected[i] == e:
|
|
|
|
i += 1
|
|
|
|
elif e > a:
|
|
|
|
unexpected.append(a)
|
|
|
|
j += 1
|
|
|
|
while actual[j] == a:
|
|
|
|
j += 1
|
|
|
|
else:
|
|
|
|
i += 1
|
|
|
|
try:
|
|
|
|
while expected[i] == e:
|
|
|
|
i += 1
|
|
|
|
finally:
|
|
|
|
j += 1
|
|
|
|
while actual[j] == a:
|
|
|
|
j += 1
|
|
|
|
except IndexError:
|
|
|
|
missing.extend(expected[i:])
|
|
|
|
unexpected.extend(actual[j:])
|
|
|
|
break
|
|
|
|
return missing, unexpected
|
|
|
|
|
|
|
|
|
|
|
|
def unorderable_list_difference(expected, actual):
|
|
|
|
"""Same behavior as sorted_list_difference but
|
|
|
|
for lists of unorderable items (like dicts).
|
|
|
|
|
|
|
|
As it does a linear search per item (remove) it
|
|
|
|
has O(n*n) performance."""
|
|
|
|
missing = []
|
|
|
|
while expected:
|
|
|
|
item = expected.pop()
|
|
|
|
try:
|
|
|
|
actual.remove(item)
|
|
|
|
except ValueError:
|
|
|
|
missing.append(item)
|
|
|
|
|
|
|
|
# anything left in actual is unexpected
|
|
|
|
return missing, actual
|
|
|
|
|
|
|
|
def three_way_cmp(x, y):
|
|
|
|
"""Return -1 if x < y, 0 if x == y and 1 if x > y"""
|
|
|
|
return (x > y) - (x < y)
|
Improve diff for assertCountEqual() to actually show the differing counts.
New output looks like this:
Traceback (most recent call last):
File "test.py", line 5, in test_ce
self.assertCountEqual('abracadabra xx', 'simsalabim xx')
AssertionError: Element counts were not equal:
Expected 5, got 2: 'a'
Expected 2, got 1: 'b'
Expected 0, got 2: 'i'
Expected 0, got 2: 'm'
Expected 0, got 1: 'l'
Expected 0, got 2: 's'
Expected 1, got 0: 'c'
Expected 1, got 0: 'd'
Expected 2, got 0: 'r'
2010-12-24 06:02:22 -04:00
|
|
|
|
|
|
|
_Mismatch = namedtuple('Mismatch', 'actual expected value')
|
|
|
|
|
|
|
|
def _count_diff_all_purpose(actual, expected):
|
|
|
|
'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
|
|
|
|
# elements need not be hashable
|
|
|
|
s, t = list(actual), list(expected)
|
|
|
|
m, n = len(s), len(t)
|
|
|
|
NULL = object()
|
|
|
|
result = []
|
|
|
|
for i, elem in enumerate(s):
|
|
|
|
if elem is NULL:
|
|
|
|
continue
|
|
|
|
cnt_s = cnt_t = 0
|
|
|
|
for j in range(i, m):
|
|
|
|
if s[j] == elem:
|
|
|
|
cnt_s += 1
|
|
|
|
s[j] = NULL
|
|
|
|
for j, other_elem in enumerate(t):
|
|
|
|
if other_elem == elem:
|
|
|
|
cnt_t += 1
|
|
|
|
t[j] = NULL
|
|
|
|
if cnt_s != cnt_t:
|
|
|
|
diff = _Mismatch(cnt_s, cnt_t, elem)
|
|
|
|
result.append(diff)
|
|
|
|
|
|
|
|
for i, elem in enumerate(t):
|
|
|
|
if elem is NULL:
|
|
|
|
continue
|
|
|
|
cnt_t = 0
|
|
|
|
for j in range(i, n):
|
|
|
|
if t[j] == elem:
|
|
|
|
cnt_t += 1
|
|
|
|
t[j] = NULL
|
|
|
|
diff = _Mismatch(0, cnt_t, elem)
|
|
|
|
result.append(diff)
|
|
|
|
return result
|
|
|
|
|
|
|
|
def _count_diff_hashable(actual, expected):
|
|
|
|
'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
|
|
|
|
# elements must be hashable
|
2018-01-24 03:49:58 -04:00
|
|
|
s, t = Counter(actual), Counter(expected)
|
Improve diff for assertCountEqual() to actually show the differing counts.
New output looks like this:
Traceback (most recent call last):
File "test.py", line 5, in test_ce
self.assertCountEqual('abracadabra xx', 'simsalabim xx')
AssertionError: Element counts were not equal:
Expected 5, got 2: 'a'
Expected 2, got 1: 'b'
Expected 0, got 2: 'i'
Expected 0, got 2: 'm'
Expected 0, got 1: 'l'
Expected 0, got 2: 's'
Expected 1, got 0: 'c'
Expected 1, got 0: 'd'
Expected 2, got 0: 'r'
2010-12-24 06:02:22 -04:00
|
|
|
result = []
|
|
|
|
for elem, cnt_s in s.items():
|
2010-12-24 07:20:30 -04:00
|
|
|
cnt_t = t.get(elem, 0)
|
Improve diff for assertCountEqual() to actually show the differing counts.
New output looks like this:
Traceback (most recent call last):
File "test.py", line 5, in test_ce
self.assertCountEqual('abracadabra xx', 'simsalabim xx')
AssertionError: Element counts were not equal:
Expected 5, got 2: 'a'
Expected 2, got 1: 'b'
Expected 0, got 2: 'i'
Expected 0, got 2: 'm'
Expected 0, got 1: 'l'
Expected 0, got 2: 's'
Expected 1, got 0: 'c'
Expected 1, got 0: 'd'
Expected 2, got 0: 'r'
2010-12-24 06:02:22 -04:00
|
|
|
if cnt_s != cnt_t:
|
|
|
|
diff = _Mismatch(cnt_s, cnt_t, elem)
|
|
|
|
result.append(diff)
|
|
|
|
for elem, cnt_t in t.items():
|
|
|
|
if elem not in s:
|
|
|
|
diff = _Mismatch(0, cnt_t, elem)
|
|
|
|
result.append(diff)
|
|
|
|
return result
|