reprlib.py 5.2 KB

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