1"""Various utility functions.""" 2 3__unittest = True 4 5 6_MAX_LENGTH = 80 7 8 9def safe_repr(obj, short=False): 10 try: 11 result = repr(obj) 12 except Exception: 13 result = object.__repr__(obj) 14 if not short or len(result) < _MAX_LENGTH: 15 return result 16 return result[:_MAX_LENGTH] + ' [truncated]...' 17 18 19def safe_str(obj): 20 try: 21 return str(obj) 22 except Exception: 23 return object.__str__(obj) 24 25 26def strclass(cls): 27 return "%s.%s" % (cls.__module__, cls.__name__) 28 29 30def sorted_list_difference(expected, actual): 31 """Finds elements in only one or the other of two, sorted input lists. 32 33 Returns a two-element tuple of lists. The first list contains those 34 elements in the "expected" list but not in the "actual" list, and the 35 second contains those elements in the "actual" list but not in the 36 "expected" list. Duplicate elements in either input list are ignored. 37 """ 38 i = j = 0 39 missing = [] 40 unexpected = [] 41 while True: 42 try: 43 e = expected[i] 44 a = actual[j] 45 if e < a: 46 missing.append(e) 47 i += 1 48 while expected[i] == e: 49 i += 1 50 elif e > a: 51 unexpected.append(a) 52 j += 1 53 while actual[j] == a: 54 j += 1 55 else: 56 i += 1 57 try: 58 while expected[i] == e: 59 i += 1 60 finally: 61 j += 1 62 while actual[j] == a: 63 j += 1 64 except IndexError: 65 missing.extend(expected[i:]) 66 unexpected.extend(actual[j:]) 67 break 68 return missing, unexpected 69 70 71def unorderable_list_difference(expected, actual, ignore_duplicate=False): 72 """Same behavior as sorted_list_difference but 73 for lists of unorderable items (like dicts). 74 75 As it does a linear search per item (remove) it 76 has O(n*n) performance. 77 """ 78 missing = [] 79 unexpected = [] 80 while expected: 81 item = expected.pop() 82 try: 83 actual.remove(item) 84 except ValueError: 85 missing.append(item) 86 if ignore_duplicate: 87 for lst in expected, actual: 88 try: 89 while True: 90 lst.remove(item) 91 except ValueError: 92 pass 93 if ignore_duplicate: 94 while actual: 95 item = actual.pop() 96 unexpected.append(item) 97 try: 98 while True: 99 actual.remove(item) 100 except ValueError: 101 pass 102 return missing, unexpected 103 104 # anything left in actual is unexpected 105 return missing, actual 106