1"""Redo the builtin repr() (representation) but with limits on most sizes.""" 2 3__all__ = ["Repr", "repr", "recursive_repr"] 4 5import builtins 6from itertools import islice 7from _thread import get_ident 8 9def recursive_repr(fillvalue='...'): 10 'Decorator to make a repr function return fillvalue for a recursive call' 11 12 def decorating_function(user_function): 13 repr_running = set() 14 15 def wrapper(self): 16 key = id(self), get_ident() 17 if key in repr_running: 18 return fillvalue 19 repr_running.add(key) 20 try: 21 result = user_function(self) 22 finally: 23 repr_running.discard(key) 24 return result 25 26 # Can't use functools.wraps() here because of bootstrap issues 27 wrapper.__module__ = getattr(user_function, '__module__') 28 wrapper.__doc__ = getattr(user_function, '__doc__') 29 wrapper.__name__ = getattr(user_function, '__name__') 30 wrapper.__qualname__ = getattr(user_function, '__qualname__') 31 wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) 32 return wrapper 33 34 return decorating_function 35 36class Repr: 37 38 def __init__(self): 39 self.fillvalue = '...' 40 self.maxlevel = 6 41 self.maxtuple = 6 42 self.maxlist = 6 43 self.maxarray = 5 44 self.maxdict = 4 45 self.maxset = 6 46 self.maxfrozenset = 6 47 self.maxdeque = 6 48 self.maxstring = 30 49 self.maxlong = 40 50 self.maxother = 30 51 52 def repr(self, x): 53 return self.repr1(x, self.maxlevel) 54 55 def repr1(self, x, level): 56 typename = type(x).__name__ 57 if ' ' in typename: 58 parts = typename.split() 59 typename = '_'.join(parts) 60 if hasattr(self, 'repr_' + typename): 61 return getattr(self, 'repr_' + typename)(x, level) 62 else: 63 return self.repr_instance(x, level) 64 65 def _repr_iterable(self, x, level, left, right, maxiter, trail=''): 66 n = len(x) 67 if level <= 0 and n: 68 s = self.fillvalue 69 else: 70 newlevel = level - 1 71 repr1 = self.repr1 72 pieces = [repr1(elem, newlevel) for elem in islice(x, maxiter)] 73 if n > maxiter: 74 pieces.append(self.fillvalue) 75 s = ', '.join(pieces) 76 if n == 1 and trail: 77 right = trail + right 78 return '%s%s%s' % (left, s, right) 79 80 def repr_tuple(self, x, level): 81 return self._repr_iterable(x, level, '(', ')', self.maxtuple, ',') 82 83 def repr_list(self, x, level): 84 return self._repr_iterable(x, level, '[', ']', self.maxlist) 85 86 def repr_array(self, x, level): 87 if not x: 88 return "array('%s')" % x.typecode 89 header = "array('%s', [" % x.typecode 90 return self._repr_iterable(x, level, header, '])', self.maxarray) 91 92 def repr_set(self, x, level): 93 if not x: 94 return 'set()' 95 x = _possibly_sorted(x) 96 return self._repr_iterable(x, level, '{', '}', self.maxset) 97 98 def repr_frozenset(self, x, level): 99 if not x: 100 return 'frozenset()' 101 x = _possibly_sorted(x) 102 return self._repr_iterable(x, level, 'frozenset({', '})', 103 self.maxfrozenset) 104 105 def repr_deque(self, x, level): 106 return self._repr_iterable(x, level, 'deque([', '])', self.maxdeque) 107 108 def repr_dict(self, x, level): 109 n = len(x) 110 if n == 0: 111 return '{}' 112 if level <= 0: 113 return '{' + self.fillvalue + '}' 114 newlevel = level - 1 115 repr1 = self.repr1 116 pieces = [] 117 for key in islice(_possibly_sorted(x), self.maxdict): 118 keyrepr = repr1(key, newlevel) 119 valrepr = repr1(x[key], newlevel) 120 pieces.append('%s: %s' % (keyrepr, valrepr)) 121 if n > self.maxdict: 122 pieces.append(self.fillvalue) 123 s = ', '.join(pieces) 124 return '{%s}' % (s,) 125 126 def repr_str(self, x, level): 127 s = builtins.repr(x[:self.maxstring]) 128 if len(s) > self.maxstring: 129 i = max(0, (self.maxstring-3)//2) 130 j = max(0, self.maxstring-3-i) 131 s = builtins.repr(x[:i] + x[len(x)-j:]) 132 s = s[:i] + self.fillvalue + s[len(s)-j:] 133 return s 134 135 def repr_int(self, x, level): 136 s = builtins.repr(x) # XXX Hope this isn't too slow... 137 if len(s) > self.maxlong: 138 i = max(0, (self.maxlong-3)//2) 139 j = max(0, self.maxlong-3-i) 140 s = s[:i] + self.fillvalue + s[len(s)-j:] 141 return s 142 143 def repr_instance(self, x, level): 144 try: 145 s = builtins.repr(x) 146 # Bugs in x.__repr__() can cause arbitrary 147 # exceptions -- then make up something 148 except Exception: 149 return '<%s instance at %#x>' % (x.__class__.__name__, id(x)) 150 if len(s) > self.maxother: 151 i = max(0, (self.maxother-3)//2) 152 j = max(0, self.maxother-3-i) 153 s = s[:i] + self.fillvalue + s[len(s)-j:] 154 return s 155 156 157def _possibly_sorted(x): 158 # Since not all sequences of items can be sorted and comparison 159 # functions may raise arbitrary exceptions, return an unsorted 160 # sequence in that case. 161 try: 162 return sorted(x) 163 except Exception: 164 return list(x) 165 166aRepr = Repr() 167repr = aRepr.repr 168