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