| 
									
										
										
										
											2009-07-19 21:01:52 +00:00
										 |  |  | """Various utility functions.""" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-24 13:19:58 +05:30
										 |  |  | from collections import namedtuple, Counter | 
					
						
							| 
									
										
										
										
											2013-09-23 23: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 10:02:22 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-22 00:15:53 +00:00
										 |  |  | __unittest = True | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-06-05 13:14:43 +00:00
										 |  |  | _MAX_LENGTH = 80 | 
					
						
							| 
									
										
										
										
											2013-09-23 23: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 13:14:43 +00: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 15:04:17 +00:00
										 |  |  |     try: | 
					
						
							| 
									
										
										
										
											2010-06-05 13:14:43 +00: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 15:04:17 +00:00
										 |  |  |     except Exception: | 
					
						
							| 
									
										
										
										
											2010-06-05 13:14:43 +00:00
										 |  |  |         result = object.__repr__(obj) | 
					
						
							|  |  |  |     if not short or len(result) < _MAX_LENGTH: | 
					
						
							|  |  |  |         return result | 
					
						
							|  |  |  |     return result[:_MAX_LENGTH] + ' [truncated]...' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-07-19 21:01:52 +00:00
										 |  |  | def strclass(cls): | 
					
						
							| 
									
										
										
										
											2014-07-22 15:00:37 +03:00
										 |  |  |     return "%s.%s" % (cls.__module__, cls.__qualname__) | 
					
						
							| 
									
										
										
										
											2009-07-19 21:01:52 +00: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 10:02:22 +00: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 13:19:58 +05:30
										 |  |  |     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 10:02:22 +00:00
										 |  |  |     result = [] | 
					
						
							|  |  |  |     for elem, cnt_s in s.items(): | 
					
						
							| 
									
										
										
										
											2010-12-24 11:20:30 +00: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 10:02:22 +00: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 |