100 lines
2.8 KiB
Python
100 lines
2.8 KiB
Python
|
"""Various utility functions."""
|
||
|
|
||
|
__unittest = True
|
||
|
|
||
|
|
||
|
_MAX_LENGTH = 80
|
||
|
def safe_repr(obj, short=False):
|
||
|
try:
|
||
|
result = repr(obj)
|
||
|
except Exception:
|
||
|
result = object.__repr__(obj)
|
||
|
if not short or len(result) < _MAX_LENGTH:
|
||
|
return result
|
||
|
return result[:_MAX_LENGTH] + ' [truncated]...'
|
||
|
|
||
|
def safe_str(obj):
|
||
|
try:
|
||
|
return str(obj)
|
||
|
except Exception:
|
||
|
return object.__str__(obj)
|
||
|
|
||
|
def strclass(cls):
|
||
|
return "%s.%s" % (cls.__module__, cls.__name__)
|
||
|
|
||
|
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, ignore_duplicate=False):
|
||
|
"""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 = []
|
||
|
unexpected = []
|
||
|
while expected:
|
||
|
item = expected.pop()
|
||
|
try:
|
||
|
actual.remove(item)
|
||
|
except ValueError:
|
||
|
missing.append(item)
|
||
|
if ignore_duplicate:
|
||
|
for lst in expected, actual:
|
||
|
try:
|
||
|
while True:
|
||
|
lst.remove(item)
|
||
|
except ValueError:
|
||
|
pass
|
||
|
if ignore_duplicate:
|
||
|
while actual:
|
||
|
item = actual.pop()
|
||
|
unexpected.append(item)
|
||
|
try:
|
||
|
while True:
|
||
|
actual.remove(item)
|
||
|
except ValueError:
|
||
|
pass
|
||
|
return missing, unexpected
|
||
|
|
||
|
# anything left in actual is unexpected
|
||
|
return missing, actual
|