mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 03:44:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			140 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			140 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Various utility functions."""
 | 
						|
 | 
						|
from collections import namedtuple, OrderedDict
 | 
						|
 | 
						|
__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 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):
 | 
						|
    """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)
 | 
						|
 | 
						|
_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 _ordered_count(iterable):
 | 
						|
    'Return dict of element counts, in the order they were first seen'
 | 
						|
    c = OrderedDict()
 | 
						|
    for elem in iterable:
 | 
						|
        c[elem] = c.get(elem, 0) + 1
 | 
						|
    return c
 | 
						|
 | 
						|
def _count_diff_hashable(actual, expected):
 | 
						|
    'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
 | 
						|
    # elements must be hashable
 | 
						|
    s, t = _ordered_count(actual), _ordered_count(expected)
 | 
						|
    result = []
 | 
						|
    for elem, cnt_s in s.items():
 | 
						|
        cnt_t = t.get(elem, 0)
 | 
						|
        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
 |