##// END OF EJS Templates
back to decorator skip
Ben Greiner -
Show More
@@ -1,473 +1,476 b''
1 1 # coding: utf-8
2 2 """Tests for IPython.lib.pretty."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from collections import Counter, defaultdict, deque, OrderedDict
9 9 import os
10 import pytest
11 10 import types
12 11 import string
13 12 import sys
14 13 import unittest
15 14
16 15 import nose.tools as nt
17 16
18 17 from IPython.lib import pretty
18 from IPython.testing.decorators import skip_without
19 19
20 20 from io import StringIO
21 21
22 22
23 23 class MyList(object):
24 24 def __init__(self, content):
25 25 self.content = content
26 26 def _repr_pretty_(self, p, cycle):
27 27 if cycle:
28 28 p.text("MyList(...)")
29 29 else:
30 30 with p.group(3, "MyList(", ")"):
31 31 for (i, child) in enumerate(self.content):
32 32 if i:
33 33 p.text(",")
34 34 p.breakable()
35 35 else:
36 36 p.breakable("")
37 37 p.pretty(child)
38 38
39 39
40 40 class MyDict(dict):
41 41 def _repr_pretty_(self, p, cycle):
42 42 p.text("MyDict(...)")
43 43
44 44 class MyObj(object):
45 45 def somemethod(self):
46 46 pass
47 47
48 48
49 49 class Dummy1(object):
50 50 def _repr_pretty_(self, p, cycle):
51 51 p.text("Dummy1(...)")
52 52
53 53 class Dummy2(Dummy1):
54 54 _repr_pretty_ = None
55 55
56 56 class NoModule(object):
57 57 pass
58 58
59 59 NoModule.__module__ = None
60 60
61 61 class Breaking(object):
62 62 def _repr_pretty_(self, p, cycle):
63 63 with p.group(4,"TG: ",":"):
64 64 p.text("Breaking(")
65 65 p.break_()
66 66 p.text(")")
67 67
68 68 class BreakingRepr(object):
69 69 def __repr__(self):
70 70 return "Breaking(\n)"
71 71
72 72 class BadRepr(object):
73 73
74 74 def __repr__(self):
75 75 return 1/0
76 76
77 77
78 78 def test_indentation():
79 79 """Test correct indentation in groups"""
80 80 count = 40
81 81 gotoutput = pretty.pretty(MyList(range(count)))
82 82 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
83 83
84 84 nt.assert_equal(gotoutput, expectedoutput)
85 85
86 86
87 87 def test_dispatch():
88 88 """
89 89 Test correct dispatching: The _repr_pretty_ method for MyDict
90 90 must be found before the registered printer for dict.
91 91 """
92 92 gotoutput = pretty.pretty(MyDict())
93 93 expectedoutput = "MyDict(...)"
94 94
95 95 nt.assert_equal(gotoutput, expectedoutput)
96 96
97 97
98 98 def test_callability_checking():
99 99 """
100 100 Test that the _repr_pretty_ method is tested for callability and skipped if
101 101 not.
102 102 """
103 103 gotoutput = pretty.pretty(Dummy2())
104 104 expectedoutput = "Dummy1(...)"
105 105
106 106 nt.assert_equal(gotoutput, expectedoutput)
107 107
108 108
109 109 def test_sets():
110 110 """
111 111 Test that set and frozenset use Python 3 formatting.
112 112 """
113 113 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
114 114 frozenset([1, 2]), set([-1, -2, -3])]
115 115 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
116 116 'frozenset({1, 2})', '{-3, -2, -1}']
117 117 for obj, expected_output in zip(objects, expected):
118 118 got_output = pretty.pretty(obj)
119 119 yield nt.assert_equal, got_output, expected_output
120 120
121 121
122 @skip_without("xxlimited" if sys.version_info < (3, 10) else "xxlimited_35")
122 123 def test_pprint_heap_allocated_type():
123 124 """
124 125 Test that pprint works for heap allocated types.
125 126 """
126 module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35"
127 xxlimited = pytest.importorskip(module_name)
127 if sys.version_info < (3, 10):
128 import xxlimited
129 else:
130 import xxlimited_35
128 131 output = pretty.pretty(xxlimited.Null)
129 132 nt.assert_equal(output, 'xxlimited.Null')
130 133
131 134 def test_pprint_nomod():
132 135 """
133 136 Test that pprint works for classes with no __module__.
134 137 """
135 138 output = pretty.pretty(NoModule)
136 139 nt.assert_equal(output, 'NoModule')
137 140
138 141 def test_pprint_break():
139 142 """
140 143 Test that p.break_ produces expected output
141 144 """
142 145 output = pretty.pretty(Breaking())
143 146 expected = "TG: Breaking(\n ):"
144 147 nt.assert_equal(output, expected)
145 148
146 149 def test_pprint_break_repr():
147 150 """
148 151 Test that p.break_ is used in repr
149 152 """
150 153 output = pretty.pretty([[BreakingRepr()]])
151 154 expected = "[[Breaking(\n )]]"
152 155 nt.assert_equal(output, expected)
153 156
154 157 output = pretty.pretty([[BreakingRepr()]*2])
155 158 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
156 159 nt.assert_equal(output, expected)
157 160
158 161 def test_bad_repr():
159 162 """Don't catch bad repr errors"""
160 163 with nt.assert_raises(ZeroDivisionError):
161 164 pretty.pretty(BadRepr())
162 165
163 166 class BadException(Exception):
164 167 def __str__(self):
165 168 return -1
166 169
167 170 class ReallyBadRepr(object):
168 171 __module__ = 1
169 172 @property
170 173 def __class__(self):
171 174 raise ValueError("I am horrible")
172 175
173 176 def __repr__(self):
174 177 raise BadException()
175 178
176 179 def test_really_bad_repr():
177 180 with nt.assert_raises(BadException):
178 181 pretty.pretty(ReallyBadRepr())
179 182
180 183
181 184 class SA(object):
182 185 pass
183 186
184 187 class SB(SA):
185 188 pass
186 189
187 190 class TestsPretty(unittest.TestCase):
188 191
189 192 def test_super_repr(self):
190 193 # "<super: module_name.SA, None>"
191 194 output = pretty.pretty(super(SA))
192 195 self.assertRegex(output, r"<super: \S+.SA, None>")
193 196
194 197 # "<super: module_name.SA, <module_name.SB at 0x...>>"
195 198 sb = SB()
196 199 output = pretty.pretty(super(SA, sb))
197 200 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
198 201
199 202
200 203 def test_long_list(self):
201 204 lis = list(range(10000))
202 205 p = pretty.pretty(lis)
203 206 last2 = p.rsplit('\n', 2)[-2:]
204 207 self.assertEqual(last2, [' 999,', ' ...]'])
205 208
206 209 def test_long_set(self):
207 210 s = set(range(10000))
208 211 p = pretty.pretty(s)
209 212 last2 = p.rsplit('\n', 2)[-2:]
210 213 self.assertEqual(last2, [' 999,', ' ...}'])
211 214
212 215 def test_long_tuple(self):
213 216 tup = tuple(range(10000))
214 217 p = pretty.pretty(tup)
215 218 last2 = p.rsplit('\n', 2)[-2:]
216 219 self.assertEqual(last2, [' 999,', ' ...)'])
217 220
218 221 def test_long_dict(self):
219 222 d = { n:n for n in range(10000) }
220 223 p = pretty.pretty(d)
221 224 last2 = p.rsplit('\n', 2)[-2:]
222 225 self.assertEqual(last2, [' 999: 999,', ' ...}'])
223 226
224 227 def test_unbound_method(self):
225 228 output = pretty.pretty(MyObj.somemethod)
226 229 self.assertIn('MyObj.somemethod', output)
227 230
228 231
229 232 class MetaClass(type):
230 233 def __new__(cls, name):
231 234 return type.__new__(cls, name, (object,), {'name': name})
232 235
233 236 def __repr__(self):
234 237 return "[CUSTOM REPR FOR CLASS %s]" % self.name
235 238
236 239
237 240 ClassWithMeta = MetaClass('ClassWithMeta')
238 241
239 242
240 243 def test_metaclass_repr():
241 244 output = pretty.pretty(ClassWithMeta)
242 245 nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
243 246
244 247
245 248 def test_unicode_repr():
246 249 u = u"üniçodé"
247 250 ustr = u
248 251
249 252 class C(object):
250 253 def __repr__(self):
251 254 return ustr
252 255
253 256 c = C()
254 257 p = pretty.pretty(c)
255 258 nt.assert_equal(p, u)
256 259 p = pretty.pretty([c])
257 260 nt.assert_equal(p, u'[%s]' % u)
258 261
259 262
260 263 def test_basic_class():
261 264 def type_pprint_wrapper(obj, p, cycle):
262 265 if obj is MyObj:
263 266 type_pprint_wrapper.called = True
264 267 return pretty._type_pprint(obj, p, cycle)
265 268 type_pprint_wrapper.called = False
266 269
267 270 stream = StringIO()
268 271 printer = pretty.RepresentationPrinter(stream)
269 272 printer.type_pprinters[type] = type_pprint_wrapper
270 273 printer.pretty(MyObj)
271 274 printer.flush()
272 275 output = stream.getvalue()
273 276
274 277 nt.assert_equal(output, '%s.MyObj' % __name__)
275 278 nt.assert_true(type_pprint_wrapper.called)
276 279
277 280
278 281 def test_collections_defaultdict():
279 282 # Create defaultdicts with cycles
280 283 a = defaultdict()
281 284 a.default_factory = a
282 285 b = defaultdict(list)
283 286 b['key'] = b
284 287
285 288 # Dictionary order cannot be relied on, test against single keys.
286 289 cases = [
287 290 (defaultdict(list), 'defaultdict(list, {})'),
288 291 (defaultdict(list, {'key': '-' * 50}),
289 292 "defaultdict(list,\n"
290 293 " {'key': '--------------------------------------------------'})"),
291 294 (a, 'defaultdict(defaultdict(...), {})'),
292 295 (b, "defaultdict(list, {'key': defaultdict(...)})"),
293 296 ]
294 297 for obj, expected in cases:
295 298 nt.assert_equal(pretty.pretty(obj), expected)
296 299
297 300
298 301 def test_collections_ordereddict():
299 302 # Create OrderedDict with cycle
300 303 a = OrderedDict()
301 304 a['key'] = a
302 305
303 306 cases = [
304 307 (OrderedDict(), 'OrderedDict()'),
305 308 (OrderedDict((i, i) for i in range(1000, 1010)),
306 309 'OrderedDict([(1000, 1000),\n'
307 310 ' (1001, 1001),\n'
308 311 ' (1002, 1002),\n'
309 312 ' (1003, 1003),\n'
310 313 ' (1004, 1004),\n'
311 314 ' (1005, 1005),\n'
312 315 ' (1006, 1006),\n'
313 316 ' (1007, 1007),\n'
314 317 ' (1008, 1008),\n'
315 318 ' (1009, 1009)])'),
316 319 (a, "OrderedDict([('key', OrderedDict(...))])"),
317 320 ]
318 321 for obj, expected in cases:
319 322 nt.assert_equal(pretty.pretty(obj), expected)
320 323
321 324
322 325 def test_collections_deque():
323 326 # Create deque with cycle
324 327 a = deque()
325 328 a.append(a)
326 329
327 330 cases = [
328 331 (deque(), 'deque([])'),
329 332 (deque(i for i in range(1000, 1020)),
330 333 'deque([1000,\n'
331 334 ' 1001,\n'
332 335 ' 1002,\n'
333 336 ' 1003,\n'
334 337 ' 1004,\n'
335 338 ' 1005,\n'
336 339 ' 1006,\n'
337 340 ' 1007,\n'
338 341 ' 1008,\n'
339 342 ' 1009,\n'
340 343 ' 1010,\n'
341 344 ' 1011,\n'
342 345 ' 1012,\n'
343 346 ' 1013,\n'
344 347 ' 1014,\n'
345 348 ' 1015,\n'
346 349 ' 1016,\n'
347 350 ' 1017,\n'
348 351 ' 1018,\n'
349 352 ' 1019])'),
350 353 (a, 'deque([deque(...)])'),
351 354 ]
352 355 for obj, expected in cases:
353 356 nt.assert_equal(pretty.pretty(obj), expected)
354 357
355 358 def test_collections_counter():
356 359 class MyCounter(Counter):
357 360 pass
358 361 cases = [
359 362 (Counter(), 'Counter()'),
360 363 (Counter(a=1), "Counter({'a': 1})"),
361 364 (MyCounter(a=1), "MyCounter({'a': 1})"),
362 365 ]
363 366 for obj, expected in cases:
364 367 nt.assert_equal(pretty.pretty(obj), expected)
365 368
366 369 def test_mappingproxy():
367 370 MP = types.MappingProxyType
368 371 underlying_dict = {}
369 372 mp_recursive = MP(underlying_dict)
370 373 underlying_dict[2] = mp_recursive
371 374 underlying_dict[3] = underlying_dict
372 375
373 376 cases = [
374 377 (MP({}), "mappingproxy({})"),
375 378 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
376 379 (MP({k: k.upper() for k in string.ascii_lowercase}),
377 380 "mappingproxy({'a': 'A',\n"
378 381 " 'b': 'B',\n"
379 382 " 'c': 'C',\n"
380 383 " 'd': 'D',\n"
381 384 " 'e': 'E',\n"
382 385 " 'f': 'F',\n"
383 386 " 'g': 'G',\n"
384 387 " 'h': 'H',\n"
385 388 " 'i': 'I',\n"
386 389 " 'j': 'J',\n"
387 390 " 'k': 'K',\n"
388 391 " 'l': 'L',\n"
389 392 " 'm': 'M',\n"
390 393 " 'n': 'N',\n"
391 394 " 'o': 'O',\n"
392 395 " 'p': 'P',\n"
393 396 " 'q': 'Q',\n"
394 397 " 'r': 'R',\n"
395 398 " 's': 'S',\n"
396 399 " 't': 'T',\n"
397 400 " 'u': 'U',\n"
398 401 " 'v': 'V',\n"
399 402 " 'w': 'W',\n"
400 403 " 'x': 'X',\n"
401 404 " 'y': 'Y',\n"
402 405 " 'z': 'Z'})"),
403 406 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
404 407 (underlying_dict,
405 408 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
406 409 ]
407 410 for obj, expected in cases:
408 411 nt.assert_equal(pretty.pretty(obj), expected)
409 412
410 413
411 414 def test_simplenamespace():
412 415 SN = types.SimpleNamespace
413 416
414 417 sn_recursive = SN()
415 418 sn_recursive.first = sn_recursive
416 419 sn_recursive.second = sn_recursive
417 420 cases = [
418 421 (SN(), "namespace()"),
419 422 (SN(x=SN()), "namespace(x=namespace())"),
420 423 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
421 424 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
422 425 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
423 426 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
424 427 " a_short_name=None)"),
425 428 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
426 429 ]
427 430 for obj, expected in cases:
428 431 nt.assert_equal(pretty.pretty(obj), expected)
429 432
430 433
431 434 def test_pretty_environ():
432 435 dict_repr = pretty.pretty(dict(os.environ))
433 436 # reindent to align with 'environ' prefix
434 437 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
435 438 env_repr = pretty.pretty(os.environ)
436 439 nt.assert_equal(env_repr, 'environ' + dict_indented)
437 440
438 441
439 442 def test_function_pretty():
440 443 "Test pretty print of function"
441 444 # posixpath is a pure python module, its interface is consistent
442 445 # across Python distributions
443 446 import posixpath
444 447 nt.assert_equal(pretty.pretty(posixpath.join), '<function posixpath.join(a, *p)>')
445 448
446 449 # custom function
447 450 def meaning_of_life(question=None):
448 451 if question:
449 452 return 42
450 453 return "Don't panic"
451 454
452 455 nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life))
453 456
454 457
455 458 class OrderedCounter(Counter, OrderedDict):
456 459 'Counter that remembers the order elements are first encountered'
457 460
458 461 def __repr__(self):
459 462 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
460 463
461 464 def __reduce__(self):
462 465 return self.__class__, (OrderedDict(self),)
463 466
464 467 class MySet(set): # Override repr of a basic type
465 468 def __repr__(self):
466 469 return 'mine'
467 470
468 471 def test_custom_repr():
469 472 """A custom repr should override a pretty printer for a parent type"""
470 473 oc = OrderedCounter("abracadabra")
471 474 nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc))
472 475
473 476 nt.assert_equal(pretty.pretty(MySet()), 'mine')
General Comments 0
You need to be logged in to leave comments. Login now