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