mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			170 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			170 lines
		
	
	
	
		
			5.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""Various utility functions."""
 | 
						|
 | 
						|
from collections import namedtuple, Counter
 | 
						|
from os.path import commonprefix
 | 
						|
 | 
						|
__unittest = True
 | 
						|
 | 
						|
_MAX_LENGTH = 80
 | 
						|
_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)
 | 
						|
 | 
						|
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.__qualname__)
 | 
						|
 | 
						|
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 _count_diff_hashable(actual, expected):
 | 
						|
    'Returns list of (cnt_act, cnt_exp, elem) triples where the counts differ'
 | 
						|
    # elements must be hashable
 | 
						|
    s, t = Counter(actual), Counter(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
 |