test_saferepr.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. # -*- coding: utf-8 -*-
  2. from __future__ import absolute_import, unicode_literals
  3. import pytest
  4. import re
  5. import struct
  6. from case import skip
  7. from decimal import Decimal
  8. from pprint import pprint
  9. from celery.five import (
  10. items, long_t, python_2_unicode_compatible, text_t, values,
  11. )
  12. from celery.utils.saferepr import saferepr
  13. D_NUMBERS = {
  14. b'integer': 1,
  15. b'float': 1.3,
  16. b'decimal': Decimal('1.3'),
  17. b'long': long_t(4),
  18. b'complex': complex(13.3),
  19. }
  20. D_INT_KEYS = {v: k for k, v in items(D_NUMBERS)}
  21. QUICK_BROWN_FOX = 'The quick brown fox jumps over the lazy dog.'
  22. B_QUICK_BROWN_FOX = b'The quick brown fox jumps over the lazy dog.'
  23. D_TEXT = {
  24. b'foo': QUICK_BROWN_FOX,
  25. b'bar': B_QUICK_BROWN_FOX,
  26. b'baz': B_QUICK_BROWN_FOX,
  27. b'xuzzy': B_QUICK_BROWN_FOX,
  28. }
  29. L_NUMBERS = list(values(D_NUMBERS))
  30. D_TEXT_LARGE = {
  31. b'bazxuzzyfoobarlongverylonglong': QUICK_BROWN_FOX * 30,
  32. }
  33. D_ALL = {
  34. b'numbers': D_NUMBERS,
  35. b'intkeys': D_INT_KEYS,
  36. b'text': D_TEXT,
  37. b'largetext': D_TEXT_LARGE,
  38. }
  39. D_D_TEXT = {b'rest': D_TEXT}
  40. RE_OLD_SET_REPR = re.compile(r'(?<!frozen)set\([\[|\{](.+?)[\}\]]\)')
  41. RE_OLD_SET_REPR_REPLACE = r'{\1}'
  42. RE_OLD_SET_CUSTOM_REPR = re.compile(r'((?:frozen)?set\d?\()\[(.+?)\](\))')
  43. RE_OLD_SET_CUSTOM_REPR_REPLACE = r'\1{\2}\3'
  44. RE_EMPTY_SET_REPR = re.compile(r'((?:frozen)?set\d?)\(\[\]\)')
  45. RE_EMPTY_SET_REPR_REPLACE = r'\1()'
  46. RE_LONG_SUFFIX = re.compile(r'(\d)+L')
  47. def old_repr(s):
  48. return text_t(RE_LONG_SUFFIX.sub(
  49. r'\1',
  50. RE_EMPTY_SET_REPR.sub(
  51. RE_EMPTY_SET_REPR_REPLACE,
  52. RE_OLD_SET_REPR.sub(
  53. RE_OLD_SET_REPR_REPLACE,
  54. RE_OLD_SET_CUSTOM_REPR.sub(
  55. RE_OLD_SET_CUSTOM_REPR_REPLACE,
  56. repr(s).replace("u'", "'"),
  57. )
  58. ),
  59. ),
  60. )).replace('set([])', 'set()')
  61. class list2(list):
  62. pass
  63. @python_2_unicode_compatible
  64. class list3(list):
  65. def __repr__(self):
  66. return list.__repr__(self)
  67. class tuple2(tuple):
  68. pass
  69. @python_2_unicode_compatible
  70. class tuple3(tuple):
  71. def __repr__(self):
  72. return tuple.__repr__(self)
  73. class set2(set):
  74. pass
  75. @python_2_unicode_compatible
  76. class set3(set):
  77. def __repr__(self):
  78. return set.__repr__(self)
  79. class frozenset2(frozenset):
  80. pass
  81. @python_2_unicode_compatible
  82. class frozenset3(frozenset):
  83. def __repr__(self):
  84. return frozenset.__repr__(self)
  85. class dict2(dict):
  86. pass
  87. @python_2_unicode_compatible
  88. class dict3(dict):
  89. def __repr__(self):
  90. return dict.__repr__(self)
  91. class test_saferepr:
  92. @pytest.mark.parametrize('value', list(values(D_NUMBERS)))
  93. def test_safe_types(self, value):
  94. assert saferepr(value) == old_repr(value)
  95. def test_numbers_dict(self):
  96. assert saferepr(D_NUMBERS) == old_repr(D_NUMBERS)
  97. def test_numbers_list(self):
  98. assert saferepr(L_NUMBERS) == old_repr(L_NUMBERS)
  99. def test_numbers_keys(self):
  100. assert saferepr(D_INT_KEYS) == old_repr(D_INT_KEYS)
  101. def test_text(self):
  102. assert saferepr(D_TEXT) == old_repr(D_TEXT).replace("u'", "'")
  103. def test_text_maxlen(self):
  104. assert saferepr(D_D_TEXT, 100).endswith("...', ...}}")
  105. def test_maxlevels(self):
  106. saferepr(D_ALL, maxlevels=1)
  107. def test_recursion(self):
  108. d = {1: 2, 3: {4: 5}}
  109. d[3][6] = d
  110. res = saferepr(d)
  111. assert 'Recursion on' in res
  112. @pytest.mark.parametrize('value', [
  113. 0, 0, 0 + 0j, 0.0, '', b'',
  114. (), tuple2(), tuple3(),
  115. [], list2(), list3(),
  116. set(), set2(), set3(),
  117. frozenset(), frozenset2(), frozenset3(),
  118. {}, dict2(), dict3(),
  119. test_recursion, pprint,
  120. -6, -6, -6 - 6j, -1.5, 'x', b'x', (3,), [3], {3: 6},
  121. (1, 2), [3, 4], {5: 6},
  122. tuple2((1, 2)), tuple3((1, 2)), tuple3(range(100)),
  123. [3, 4], list2([3, 4]), list3([3, 4]), list3(range(100)),
  124. {7}, set2({7}), set3({7}),
  125. frozenset({8}), frozenset2({8}), frozenset3({8}),
  126. dict2({5: 6}), dict3({5: 6}),
  127. range(10, -11, -1)
  128. ])
  129. def test_same_as_repr(self, value):
  130. # Simple objects, small containers, and classes that overwrite __repr__
  131. # For those the result should be the same as repr().
  132. # Ahem. The docs don't say anything about that -- this appears to
  133. # be testing an implementation quirk. Starting in Python 2.5, it's
  134. # not true for dicts: pprint always sorts dicts by key now; before,
  135. # it sorted a dict display if and only if the display required
  136. # multiple lines. For that reason, dicts with more than one element
  137. # aren't tested here.
  138. native = old_repr(value)
  139. assert saferepr(value) == native
  140. @skip.if_python3()
  141. def test_bytes_with_unicode(self):
  142. class X(object):
  143. def __repr__(self):
  144. return 'æ e i a æ å'.encode(
  145. 'utf-8', errors='backslash replace')
  146. val = X()
  147. assert repr(val)
  148. assert saferepr(val)
  149. @skip.unless_python3()
  150. def test_unicode_bytes(self):
  151. val = 'øystein'.encode('utf-8')
  152. assert saferepr(val) == "b'øystein'"
  153. @skip.unless_python3()
  154. def test_unicode_bytes__long(self):
  155. val = 'øystein'.encode('utf-8') * 1024
  156. assert saferepr(val, maxlen=128).endswith("...'")
  157. @skip.unless_python3()
  158. def test_binary_bytes(self):
  159. val = struct.pack('>QQQ', 12223, 1234, 3123)
  160. if hasattr(bytes, 'hex'): # Python 3.5+
  161. assert '2fbf' in saferepr(val, maxlen=128)
  162. else: # Python 3.4
  163. assert saferepr(val, maxlen=128)
  164. @skip.unless_python3()
  165. def test_binary_bytes__long(self):
  166. val = struct.pack('>QQQ', 12223, 1234, 3123) * 1024
  167. result = saferepr(val, maxlen=128)
  168. if hasattr(bytes, 'hex'): # Python 3.5+
  169. assert '2fbf' in result
  170. assert result.endswith("...'")
  171. else: # Python 3.4
  172. assert result
  173. def test_repr_raises(self):
  174. class O(object):
  175. def __repr__(self):
  176. raise KeyError('foo')
  177. assert 'Unrepresentable' in saferepr(O())
  178. def test_bytes_with_unicode_py2_and_3(self):
  179. assert saferepr([b'foo', 'a®rgs'.encode('utf-8')])