test_pretty.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. # coding: utf-8
  2. """Tests for IPython.lib.pretty."""
  3. # Copyright (c) IPython Development Team.
  4. # Distributed under the terms of the Modified BSD License.
  5. from __future__ import print_function
  6. from collections import Counter, defaultdict, deque, OrderedDict
  7. import types, string, ctypes
  8. import nose.tools as nt
  9. from IPython.lib import pretty
  10. from IPython.testing.decorators import (skip_without, py2_only, py3_only,
  11. cpython2_only)
  12. from IPython.utils.py3compat import PY3, unicode_to_str
  13. if PY3:
  14. from io import StringIO
  15. else:
  16. from StringIO import StringIO
  17. class MyList(object):
  18. def __init__(self, content):
  19. self.content = content
  20. def _repr_pretty_(self, p, cycle):
  21. if cycle:
  22. p.text("MyList(...)")
  23. else:
  24. with p.group(3, "MyList(", ")"):
  25. for (i, child) in enumerate(self.content):
  26. if i:
  27. p.text(",")
  28. p.breakable()
  29. else:
  30. p.breakable("")
  31. p.pretty(child)
  32. class MyDict(dict):
  33. def _repr_pretty_(self, p, cycle):
  34. p.text("MyDict(...)")
  35. class MyObj(object):
  36. def somemethod(self):
  37. pass
  38. class Dummy1(object):
  39. def _repr_pretty_(self, p, cycle):
  40. p.text("Dummy1(...)")
  41. class Dummy2(Dummy1):
  42. _repr_pretty_ = None
  43. class NoModule(object):
  44. pass
  45. NoModule.__module__ = None
  46. class Breaking(object):
  47. def _repr_pretty_(self, p, cycle):
  48. with p.group(4,"TG: ",":"):
  49. p.text("Breaking(")
  50. p.break_()
  51. p.text(")")
  52. class BreakingRepr(object):
  53. def __repr__(self):
  54. return "Breaking(\n)"
  55. class BreakingReprParent(object):
  56. def _repr_pretty_(self, p, cycle):
  57. with p.group(4,"TG: ",":"):
  58. p.pretty(BreakingRepr())
  59. class BadRepr(object):
  60. def __repr__(self):
  61. return 1/0
  62. def test_indentation():
  63. """Test correct indentation in groups"""
  64. count = 40
  65. gotoutput = pretty.pretty(MyList(range(count)))
  66. expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
  67. nt.assert_equal(gotoutput, expectedoutput)
  68. def test_dispatch():
  69. """
  70. Test correct dispatching: The _repr_pretty_ method for MyDict
  71. must be found before the registered printer for dict.
  72. """
  73. gotoutput = pretty.pretty(MyDict())
  74. expectedoutput = "MyDict(...)"
  75. nt.assert_equal(gotoutput, expectedoutput)
  76. def test_callability_checking():
  77. """
  78. Test that the _repr_pretty_ method is tested for callability and skipped if
  79. not.
  80. """
  81. gotoutput = pretty.pretty(Dummy2())
  82. expectedoutput = "Dummy1(...)"
  83. nt.assert_equal(gotoutput, expectedoutput)
  84. def test_sets():
  85. """
  86. Test that set and frozenset use Python 3 formatting.
  87. """
  88. objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
  89. frozenset([1, 2]), set([-1, -2, -3])]
  90. expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
  91. 'frozenset({1, 2})', '{-3, -2, -1}']
  92. for obj, expected_output in zip(objects, expected):
  93. got_output = pretty.pretty(obj)
  94. yield nt.assert_equal, got_output, expected_output
  95. @skip_without('xxlimited')
  96. def test_pprint_heap_allocated_type():
  97. """
  98. Test that pprint works for heap allocated types.
  99. """
  100. import xxlimited
  101. output = pretty.pretty(xxlimited.Null)
  102. nt.assert_equal(output, 'xxlimited.Null')
  103. def test_pprint_nomod():
  104. """
  105. Test that pprint works for classes with no __module__.
  106. """
  107. output = pretty.pretty(NoModule)
  108. nt.assert_equal(output, 'NoModule')
  109. def test_pprint_break():
  110. """
  111. Test that p.break_ produces expected output
  112. """
  113. output = pretty.pretty(Breaking())
  114. expected = "TG: Breaking(\n ):"
  115. nt.assert_equal(output, expected)
  116. def test_pprint_break_repr():
  117. """
  118. Test that p.break_ is used in repr
  119. """
  120. output = pretty.pretty(BreakingReprParent())
  121. expected = "TG: Breaking(\n ):"
  122. nt.assert_equal(output, expected)
  123. def test_bad_repr():
  124. """Don't catch bad repr errors"""
  125. with nt.assert_raises(ZeroDivisionError):
  126. output = pretty.pretty(BadRepr())
  127. class BadException(Exception):
  128. def __str__(self):
  129. return -1
  130. class ReallyBadRepr(object):
  131. __module__ = 1
  132. @property
  133. def __class__(self):
  134. raise ValueError("I am horrible")
  135. def __repr__(self):
  136. raise BadException()
  137. def test_really_bad_repr():
  138. with nt.assert_raises(BadException):
  139. output = pretty.pretty(ReallyBadRepr())
  140. class SA(object):
  141. pass
  142. class SB(SA):
  143. pass
  144. def test_super_repr():
  145. # "<super: module_name.SA, None>"
  146. output = pretty.pretty(super(SA))
  147. nt.assert_regexp_matches(output, r"<super: \S+.SA, None>")
  148. # "<super: module_name.SA, <module_name.SB at 0x...>>"
  149. sb = SB()
  150. output = pretty.pretty(super(SA, sb))
  151. nt.assert_regexp_matches(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
  152. def test_long_list():
  153. lis = list(range(10000))
  154. p = pretty.pretty(lis)
  155. last2 = p.rsplit('\n', 2)[-2:]
  156. nt.assert_equal(last2, [' 999,', ' ...]'])
  157. def test_long_set():
  158. s = set(range(10000))
  159. p = pretty.pretty(s)
  160. last2 = p.rsplit('\n', 2)[-2:]
  161. nt.assert_equal(last2, [' 999,', ' ...}'])
  162. def test_long_tuple():
  163. tup = tuple(range(10000))
  164. p = pretty.pretty(tup)
  165. last2 = p.rsplit('\n', 2)[-2:]
  166. nt.assert_equal(last2, [' 999,', ' ...)'])
  167. def test_long_dict():
  168. d = { n:n for n in range(10000) }
  169. p = pretty.pretty(d)
  170. last2 = p.rsplit('\n', 2)[-2:]
  171. nt.assert_equal(last2, [' 999: 999,', ' ...}'])
  172. def test_unbound_method():
  173. output = pretty.pretty(MyObj.somemethod)
  174. nt.assert_in('MyObj.somemethod', output)
  175. class MetaClass(type):
  176. def __new__(cls, name):
  177. return type.__new__(cls, name, (object,), {'name': name})
  178. def __repr__(self):
  179. return "[CUSTOM REPR FOR CLASS %s]" % self.name
  180. ClassWithMeta = MetaClass('ClassWithMeta')
  181. def test_metaclass_repr():
  182. output = pretty.pretty(ClassWithMeta)
  183. nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
  184. def test_unicode_repr():
  185. u = u"üniçodé"
  186. ustr = unicode_to_str(u)
  187. class C(object):
  188. def __repr__(self):
  189. return ustr
  190. c = C()
  191. p = pretty.pretty(c)
  192. nt.assert_equal(p, u)
  193. p = pretty.pretty([c])
  194. nt.assert_equal(p, u'[%s]' % u)
  195. def test_basic_class():
  196. def type_pprint_wrapper(obj, p, cycle):
  197. if obj is MyObj:
  198. type_pprint_wrapper.called = True
  199. return pretty._type_pprint(obj, p, cycle)
  200. type_pprint_wrapper.called = False
  201. stream = StringIO()
  202. printer = pretty.RepresentationPrinter(stream)
  203. printer.type_pprinters[type] = type_pprint_wrapper
  204. printer.pretty(MyObj)
  205. printer.flush()
  206. output = stream.getvalue()
  207. nt.assert_equal(output, '%s.MyObj' % __name__)
  208. nt.assert_true(type_pprint_wrapper.called)
  209. # This is only run on Python 2 because in Python 3 the language prevents you
  210. # from setting a non-unicode value for __qualname__ on a metaclass, and it
  211. # doesn't respect the descriptor protocol if you subclass unicode and implement
  212. # __get__.
  213. @py2_only
  214. def test_fallback_to__name__on_type():
  215. # Test that we correctly repr types that have non-string values for
  216. # __qualname__ by falling back to __name__
  217. class Type(object):
  218. __qualname__ = 5
  219. # Test repring of the type.
  220. stream = StringIO()
  221. printer = pretty.RepresentationPrinter(stream)
  222. printer.pretty(Type)
  223. printer.flush()
  224. output = stream.getvalue()
  225. # If __qualname__ is malformed, we should fall back to __name__.
  226. expected = '.'.join([__name__, Type.__name__])
  227. nt.assert_equal(output, expected)
  228. # Clear stream buffer.
  229. stream.buf = ''
  230. # Test repring of an instance of the type.
  231. instance = Type()
  232. printer.pretty(instance)
  233. printer.flush()
  234. output = stream.getvalue()
  235. # Should look like:
  236. # <IPython.lib.tests.test_pretty.Type at 0x7f7658ae07d0>
  237. prefix = '<' + '.'.join([__name__, Type.__name__]) + ' at 0x'
  238. nt.assert_true(output.startswith(prefix))
  239. @py2_only
  240. def test_fail_gracefully_on_bogus__qualname__and__name__():
  241. # Test that we correctly repr types that have non-string values for both
  242. # __qualname__ and __name__
  243. class Meta(type):
  244. __name__ = 5
  245. class Type(object):
  246. __metaclass__ = Meta
  247. __qualname__ = 5
  248. stream = StringIO()
  249. printer = pretty.RepresentationPrinter(stream)
  250. printer.pretty(Type)
  251. printer.flush()
  252. output = stream.getvalue()
  253. # If we can't find __name__ or __qualname__ just use a sentinel string.
  254. expected = '.'.join([__name__, '<unknown type>'])
  255. nt.assert_equal(output, expected)
  256. # Clear stream buffer.
  257. stream.buf = ''
  258. # Test repring of an instance of the type.
  259. instance = Type()
  260. printer.pretty(instance)
  261. printer.flush()
  262. output = stream.getvalue()
  263. # Should look like:
  264. # <IPython.lib.tests.test_pretty.<unknown type> at 0x7f7658ae07d0>
  265. prefix = '<' + '.'.join([__name__, '<unknown type>']) + ' at 0x'
  266. nt.assert_true(output.startswith(prefix))
  267. def test_collections_defaultdict():
  268. # Create defaultdicts with cycles
  269. a = defaultdict()
  270. a.default_factory = a
  271. b = defaultdict(list)
  272. b['key'] = b
  273. # Dictionary order cannot be relied on, test against single keys.
  274. cases = [
  275. (defaultdict(list), 'defaultdict(list, {})'),
  276. (defaultdict(list, {'key': '-' * 50}),
  277. "defaultdict(list,\n"
  278. " {'key': '--------------------------------------------------'})"),
  279. (a, 'defaultdict(defaultdict(...), {})'),
  280. (b, "defaultdict(list, {'key': defaultdict(...)})"),
  281. ]
  282. for obj, expected in cases:
  283. nt.assert_equal(pretty.pretty(obj), expected)
  284. def test_collections_ordereddict():
  285. # Create OrderedDict with cycle
  286. a = OrderedDict()
  287. a['key'] = a
  288. cases = [
  289. (OrderedDict(), 'OrderedDict()'),
  290. (OrderedDict((i, i) for i in range(1000, 1010)),
  291. 'OrderedDict([(1000, 1000),\n'
  292. ' (1001, 1001),\n'
  293. ' (1002, 1002),\n'
  294. ' (1003, 1003),\n'
  295. ' (1004, 1004),\n'
  296. ' (1005, 1005),\n'
  297. ' (1006, 1006),\n'
  298. ' (1007, 1007),\n'
  299. ' (1008, 1008),\n'
  300. ' (1009, 1009)])'),
  301. (a, "OrderedDict([('key', OrderedDict(...))])"),
  302. ]
  303. for obj, expected in cases:
  304. nt.assert_equal(pretty.pretty(obj), expected)
  305. def test_collections_deque():
  306. # Create deque with cycle
  307. a = deque()
  308. a.append(a)
  309. cases = [
  310. (deque(), 'deque([])'),
  311. (deque(i for i in range(1000, 1020)),
  312. 'deque([1000,\n'
  313. ' 1001,\n'
  314. ' 1002,\n'
  315. ' 1003,\n'
  316. ' 1004,\n'
  317. ' 1005,\n'
  318. ' 1006,\n'
  319. ' 1007,\n'
  320. ' 1008,\n'
  321. ' 1009,\n'
  322. ' 1010,\n'
  323. ' 1011,\n'
  324. ' 1012,\n'
  325. ' 1013,\n'
  326. ' 1014,\n'
  327. ' 1015,\n'
  328. ' 1016,\n'
  329. ' 1017,\n'
  330. ' 1018,\n'
  331. ' 1019])'),
  332. (a, 'deque([deque(...)])'),
  333. ]
  334. for obj, expected in cases:
  335. nt.assert_equal(pretty.pretty(obj), expected)
  336. def test_collections_counter():
  337. class MyCounter(Counter):
  338. pass
  339. cases = [
  340. (Counter(), 'Counter()'),
  341. (Counter(a=1), "Counter({'a': 1})"),
  342. (MyCounter(a=1), "MyCounter({'a': 1})"),
  343. ]
  344. for obj, expected in cases:
  345. nt.assert_equal(pretty.pretty(obj), expected)
  346. @py3_only
  347. def test_mappingproxy():
  348. MP = types.MappingProxyType
  349. underlying_dict = {}
  350. mp_recursive = MP(underlying_dict)
  351. underlying_dict[2] = mp_recursive
  352. underlying_dict[3] = underlying_dict
  353. cases = [
  354. (MP({}), "mappingproxy({})"),
  355. (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
  356. (MP({k: k.upper() for k in string.ascii_lowercase}),
  357. "mappingproxy({'a': 'A',\n"
  358. " 'b': 'B',\n"
  359. " 'c': 'C',\n"
  360. " 'd': 'D',\n"
  361. " 'e': 'E',\n"
  362. " 'f': 'F',\n"
  363. " 'g': 'G',\n"
  364. " 'h': 'H',\n"
  365. " 'i': 'I',\n"
  366. " 'j': 'J',\n"
  367. " 'k': 'K',\n"
  368. " 'l': 'L',\n"
  369. " 'm': 'M',\n"
  370. " 'n': 'N',\n"
  371. " 'o': 'O',\n"
  372. " 'p': 'P',\n"
  373. " 'q': 'Q',\n"
  374. " 'r': 'R',\n"
  375. " 's': 'S',\n"
  376. " 't': 'T',\n"
  377. " 'u': 'U',\n"
  378. " 'v': 'V',\n"
  379. " 'w': 'W',\n"
  380. " 'x': 'X',\n"
  381. " 'y': 'Y',\n"
  382. " 'z': 'Z'})"),
  383. (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
  384. (underlying_dict,
  385. "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
  386. ]
  387. for obj, expected in cases:
  388. nt.assert_equal(pretty.pretty(obj), expected)
  389. @cpython2_only # In PyPy, types.DictProxyType is dict
  390. def test_dictproxy():
  391. # This is the dictproxy constructor itself from the Python API,
  392. DP = ctypes.pythonapi.PyDictProxy_New
  393. DP.argtypes, DP.restype = (ctypes.py_object,), ctypes.py_object
  394. underlying_dict = {}
  395. mp_recursive = DP(underlying_dict)
  396. underlying_dict[0] = mp_recursive
  397. underlying_dict[-3] = underlying_dict
  398. cases = [
  399. (DP({}), "dict_proxy({})"),
  400. (DP({None: DP({})}), "dict_proxy({None: dict_proxy({})})"),
  401. (DP({k: k.lower() for k in string.ascii_uppercase}),
  402. "dict_proxy({'A': 'a',\n"
  403. " 'B': 'b',\n"
  404. " 'C': 'c',\n"
  405. " 'D': 'd',\n"
  406. " 'E': 'e',\n"
  407. " 'F': 'f',\n"
  408. " 'G': 'g',\n"
  409. " 'H': 'h',\n"
  410. " 'I': 'i',\n"
  411. " 'J': 'j',\n"
  412. " 'K': 'k',\n"
  413. " 'L': 'l',\n"
  414. " 'M': 'm',\n"
  415. " 'N': 'n',\n"
  416. " 'O': 'o',\n"
  417. " 'P': 'p',\n"
  418. " 'Q': 'q',\n"
  419. " 'R': 'r',\n"
  420. " 'S': 's',\n"
  421. " 'T': 't',\n"
  422. " 'U': 'u',\n"
  423. " 'V': 'v',\n"
  424. " 'W': 'w',\n"
  425. " 'X': 'x',\n"
  426. " 'Y': 'y',\n"
  427. " 'Z': 'z'})"),
  428. (mp_recursive, "dict_proxy({-3: {-3: {...}, 0: {...}}, 0: {...}})"),
  429. ]
  430. for obj, expected in cases:
  431. nt.assert_is_instance(obj, types.DictProxyType) # Meta-test
  432. nt.assert_equal(pretty.pretty(obj), expected)
  433. nt.assert_equal(pretty.pretty(underlying_dict),
  434. "{-3: {...}, 0: dict_proxy({-3: {...}, 0: {...}})}")