test_saferepr.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  1. from __future__ import absolute_import, unicode_literals
  2. import re
  3. from decimal import Decimal
  4. from pprint import pprint
  5. from celery.five import (
  6. items, long_t, python_2_unicode_compatible, text_t, values,
  7. )
  8. from celery.utils.saferepr import saferepr
  9. from celery.tests.case import Case
  10. D_NUMBERS = {
  11. b'integer': 1,
  12. b'float': 1.3,
  13. b'decimal': Decimal('1.3'),
  14. b'long': long_t(4),
  15. b'complex': complex(13.3),
  16. }
  17. D_INT_KEYS = {v: k for k, v in items(D_NUMBERS)}
  18. QUICK_BROWN_FOX = 'The quick brown fox jumps over the lazy dog.'
  19. B_QUICK_BROWN_FOX = b'The quick brown fox jumps over the lazy dog.'
  20. D_TEXT = {
  21. b'foo': QUICK_BROWN_FOX,
  22. b'bar': B_QUICK_BROWN_FOX,
  23. b'baz': B_QUICK_BROWN_FOX,
  24. b'xuzzy': B_QUICK_BROWN_FOX,
  25. }
  26. L_NUMBERS = list(values(D_NUMBERS))
  27. D_TEXT_LARGE = {
  28. b'bazxuzzyfoobarlongverylonglong': QUICK_BROWN_FOX * 30,
  29. }
  30. D_ALL = {
  31. b'numbers': D_NUMBERS,
  32. b'intkeys': D_INT_KEYS,
  33. b'text': D_TEXT,
  34. b'largetext': D_TEXT_LARGE,
  35. }
  36. D_D_TEXT = {b'rest': D_TEXT}
  37. RE_OLD_SET_REPR = re.compile(r'(?<!frozen)set\([\[|\{](.+?)[\}\]]\)')
  38. RE_OLD_SET_REPR_REPLACE = r'{\1}'
  39. RE_OLD_SET_CUSTOM_REPR = re.compile(r'((?:frozen)?set\d?\()\[(.+?)\](\))')
  40. RE_OLD_SET_CUSTOM_REPR_REPLACE = r'\1{\2}\3'
  41. RE_EMPTY_SET_REPR = re.compile(r'((?:frozen)?set\d?)\(\[\]\)')
  42. RE_EMPTY_SET_REPR_REPLACE = r'\1()'
  43. RE_LONG_SUFFIX = re.compile(r'(\d)+L')
  44. def old_repr(s):
  45. return text_t(RE_LONG_SUFFIX.sub(
  46. r'\1',
  47. RE_EMPTY_SET_REPR.sub(
  48. RE_EMPTY_SET_REPR_REPLACE,
  49. RE_OLD_SET_REPR.sub(
  50. RE_OLD_SET_REPR_REPLACE,
  51. RE_OLD_SET_CUSTOM_REPR.sub(
  52. RE_OLD_SET_CUSTOM_REPR_REPLACE, repr(s).replace("u'", "'"))
  53. ),
  54. ),
  55. ),
  56. ).replace('set([])', 'set()')
  57. class list2(list):
  58. pass
  59. @python_2_unicode_compatible
  60. class list3(list):
  61. def __repr__(self):
  62. return list.__repr__(self)
  63. class tuple2(tuple):
  64. pass
  65. @python_2_unicode_compatible
  66. class tuple3(tuple):
  67. def __repr__(self):
  68. return tuple.__repr__(self)
  69. class set2(set):
  70. pass
  71. @python_2_unicode_compatible
  72. class set3(set):
  73. def __repr__(self):
  74. return set.__repr__(self)
  75. class frozenset2(frozenset):
  76. pass
  77. @python_2_unicode_compatible
  78. class frozenset3(frozenset):
  79. def __repr__(self):
  80. return frozenset.__repr__(self)
  81. class dict2(dict):
  82. pass
  83. @python_2_unicode_compatible
  84. class dict3(dict):
  85. def __repr__(self):
  86. return dict.__repr__(self)
  87. @python_2_unicode_compatible
  88. class Unorderable:
  89. def __repr__(self):
  90. return str(id(self))
  91. class test_saferepr(Case):
  92. def test_safe_types(self):
  93. for value in values(D_NUMBERS):
  94. self.assertEqual(saferepr(value), old_repr(value))
  95. def test_numbers_dict(self):
  96. self.assertEqual(saferepr(D_NUMBERS), old_repr(D_NUMBERS))
  97. def test_numbers_list(self):
  98. self.assertEqual(saferepr(L_NUMBERS), old_repr(L_NUMBERS))
  99. def test_numbers_keys(self):
  100. self.assertEqual(saferepr(D_INT_KEYS), old_repr(D_INT_KEYS))
  101. def test_text(self):
  102. self.assertEqual(saferepr(D_TEXT), old_repr(D_TEXT).replace("u'", "'"))
  103. def test_text_maxlen(self):
  104. self.assertTrue(
  105. saferepr(D_D_TEXT, 100).endswith("...', ...}}")
  106. )
  107. def test_maxlevels(self):
  108. saferepr(D_ALL, maxlevels=1)
  109. def test_recursion(self):
  110. d = {1: 2, 3: {4: 5}}
  111. d[3][6] = d
  112. res = saferepr(d)
  113. self.assertIn('Recursion on', res)
  114. def test_same_as_repr(self):
  115. # Simple objects, small containers and classes that overwrite __repr__
  116. # For those the result should be the same as repr().
  117. # Ahem. The docs don't say anything about that -- this appears to
  118. # be testing an implementation quirk. Starting in Python 2.5, it's
  119. # not true for dicts: pprint always sorts dicts by key now; before,
  120. # it sorted a dict display if and only if the display required
  121. # multiple lines. For that reason, dicts with more than one element
  122. # aren't tested here.
  123. types = (
  124. 0, 0, 0+0j, 0.0, '', b'',
  125. (), tuple2(), tuple3(),
  126. [], list2(), list3(),
  127. set(), set2(), set3(),
  128. frozenset(), frozenset2(), frozenset3(),
  129. {}, dict2(), dict3(),
  130. self.assertTrue, pprint,
  131. -6, -6, -6-6j, -1.5, 'x', b'x', (3,), [3], {3: 6},
  132. (1, 2), [3, 4], {5: 6},
  133. tuple2((1, 2)), tuple3((1, 2)), tuple3(range(100)),
  134. [3, 4], list2([3, 4]), list3([3, 4]), list3(range(100)),
  135. {7}, set2({7}), set3({7}),
  136. frozenset({8}), frozenset2({8}), frozenset3({8}),
  137. dict2({5: 6}), dict3({5: 6}),
  138. range(10, -11, -1)
  139. )
  140. for simple in types:
  141. native = old_repr(simple)
  142. self.assertEqual(saferepr(simple), native)