##// END OF EJS Templates
Merge pull request #10959 from takluyver/i10950...
Min RK -
r24121:819efc48 merge
parent child Browse files
Show More
@@ -1,533 +1,533 b''
1 1 """Tests for the Formatters."""
2 2
3 3 import warnings
4 4 from math import pi
5 5
6 6 try:
7 7 import numpy
8 8 except:
9 9 numpy = None
10 10 import nose.tools as nt
11 11
12 12 from IPython import get_ipython
13 13 from traitlets.config import Config
14 14 from IPython.core.formatters import (
15 15 PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key,
16 16 DisplayFormatter, JSONFormatter,
17 17 )
18 18 from IPython.utils.io import capture_output
19 19
20 20 class A(object):
21 21 def __repr__(self):
22 22 return 'A()'
23 23
24 24 class B(A):
25 25 def __repr__(self):
26 26 return 'B()'
27 27
28 28 class C:
29 29 pass
30 30
31 31 class BadRepr(object):
32 32 def __repr__(self):
33 33 raise ValueError("bad repr")
34 34
35 35 class BadPretty(object):
36 36 _repr_pretty_ = None
37 37
38 38 class GoodPretty(object):
39 39 def _repr_pretty_(self, pp, cycle):
40 40 pp.text('foo')
41 41
42 42 def __repr__(self):
43 43 return 'GoodPretty()'
44 44
45 45 def foo_printer(obj, pp, cycle):
46 46 pp.text('foo')
47 47
48 48 def test_pretty():
49 49 f = PlainTextFormatter()
50 50 f.for_type(A, foo_printer)
51 51 nt.assert_equal(f(A()), 'foo')
52 nt.assert_equal(f(B()), 'foo')
52 nt.assert_equal(f(B()), 'B()')
53 53 nt.assert_equal(f(GoodPretty()), 'foo')
54 54 # Just don't raise an exception for the following:
55 55 f(BadPretty())
56 56
57 57 f.pprint = False
58 58 nt.assert_equal(f(A()), 'A()')
59 59 nt.assert_equal(f(B()), 'B()')
60 60 nt.assert_equal(f(GoodPretty()), 'GoodPretty()')
61 61
62 62
63 63 def test_deferred():
64 64 f = PlainTextFormatter()
65 65
66 66 def test_precision():
67 67 """test various values for float_precision."""
68 68 f = PlainTextFormatter()
69 69 nt.assert_equal(f(pi), repr(pi))
70 70 f.float_precision = 0
71 71 if numpy:
72 72 po = numpy.get_printoptions()
73 73 nt.assert_equal(po['precision'], 0)
74 74 nt.assert_equal(f(pi), '3')
75 75 f.float_precision = 2
76 76 if numpy:
77 77 po = numpy.get_printoptions()
78 78 nt.assert_equal(po['precision'], 2)
79 79 nt.assert_equal(f(pi), '3.14')
80 80 f.float_precision = '%g'
81 81 if numpy:
82 82 po = numpy.get_printoptions()
83 83 nt.assert_equal(po['precision'], 2)
84 84 nt.assert_equal(f(pi), '3.14159')
85 85 f.float_precision = '%e'
86 86 nt.assert_equal(f(pi), '3.141593e+00')
87 87 f.float_precision = ''
88 88 if numpy:
89 89 po = numpy.get_printoptions()
90 90 nt.assert_equal(po['precision'], 8)
91 91 nt.assert_equal(f(pi), repr(pi))
92 92
93 93 def test_bad_precision():
94 94 """test various invalid values for float_precision."""
95 95 f = PlainTextFormatter()
96 96 def set_fp(p):
97 97 f.float_precision=p
98 98 nt.assert_raises(ValueError, set_fp, '%')
99 99 nt.assert_raises(ValueError, set_fp, '%.3f%i')
100 100 nt.assert_raises(ValueError, set_fp, 'foo')
101 101 nt.assert_raises(ValueError, set_fp, -1)
102 102
103 103 def test_for_type():
104 104 f = PlainTextFormatter()
105 105
106 106 # initial return, None
107 107 nt.assert_is(f.for_type(C, foo_printer), None)
108 108 # no func queries
109 109 nt.assert_is(f.for_type(C), foo_printer)
110 110 # shouldn't change anything
111 111 nt.assert_is(f.for_type(C), foo_printer)
112 112 # None should do the same
113 113 nt.assert_is(f.for_type(C, None), foo_printer)
114 114 nt.assert_is(f.for_type(C, None), foo_printer)
115 115
116 116 def test_for_type_string():
117 117 f = PlainTextFormatter()
118 118
119 119 type_str = '%s.%s' % (C.__module__, 'C')
120 120
121 121 # initial return, None
122 122 nt.assert_is(f.for_type(type_str, foo_printer), None)
123 123 # no func queries
124 124 nt.assert_is(f.for_type(type_str), foo_printer)
125 125 nt.assert_in(_mod_name_key(C), f.deferred_printers)
126 126 nt.assert_is(f.for_type(C), foo_printer)
127 127 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
128 128 nt.assert_in(C, f.type_printers)
129 129
130 130 def test_for_type_by_name():
131 131 f = PlainTextFormatter()
132 132
133 133 mod = C.__module__
134 134
135 135 # initial return, None
136 136 nt.assert_is(f.for_type_by_name(mod, 'C', foo_printer), None)
137 137 # no func queries
138 138 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
139 139 # shouldn't change anything
140 140 nt.assert_is(f.for_type_by_name(mod, 'C'), foo_printer)
141 141 # None should do the same
142 142 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
143 143 nt.assert_is(f.for_type_by_name(mod, 'C', None), foo_printer)
144 144
145 145 def test_lookup():
146 146 f = PlainTextFormatter()
147 147
148 148 f.for_type(C, foo_printer)
149 149 nt.assert_is(f.lookup(C()), foo_printer)
150 150 with nt.assert_raises(KeyError):
151 151 f.lookup(A())
152 152
153 153 def test_lookup_string():
154 154 f = PlainTextFormatter()
155 155 type_str = '%s.%s' % (C.__module__, 'C')
156 156
157 157 f.for_type(type_str, foo_printer)
158 158 nt.assert_is(f.lookup(C()), foo_printer)
159 159 # should move from deferred to imported dict
160 160 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
161 161 nt.assert_in(C, f.type_printers)
162 162
163 163 def test_lookup_by_type():
164 164 f = PlainTextFormatter()
165 165 f.for_type(C, foo_printer)
166 166 nt.assert_is(f.lookup_by_type(C), foo_printer)
167 167 with nt.assert_raises(KeyError):
168 168 f.lookup_by_type(A)
169 169
170 170 def test_lookup_by_type_string():
171 171 f = PlainTextFormatter()
172 172 type_str = '%s.%s' % (C.__module__, 'C')
173 173 f.for_type(type_str, foo_printer)
174 174
175 175 # verify insertion
176 176 nt.assert_in(_mod_name_key(C), f.deferred_printers)
177 177 nt.assert_not_in(C, f.type_printers)
178 178
179 179 nt.assert_is(f.lookup_by_type(type_str), foo_printer)
180 180 # lookup by string doesn't cause import
181 181 nt.assert_in(_mod_name_key(C), f.deferred_printers)
182 182 nt.assert_not_in(C, f.type_printers)
183 183
184 184 nt.assert_is(f.lookup_by_type(C), foo_printer)
185 185 # should move from deferred to imported dict
186 186 nt.assert_not_in(_mod_name_key(C), f.deferred_printers)
187 187 nt.assert_in(C, f.type_printers)
188 188
189 189 def test_in_formatter():
190 190 f = PlainTextFormatter()
191 191 f.for_type(C, foo_printer)
192 192 type_str = '%s.%s' % (C.__module__, 'C')
193 193 nt.assert_in(C, f)
194 194 nt.assert_in(type_str, f)
195 195
196 196 def test_string_in_formatter():
197 197 f = PlainTextFormatter()
198 198 type_str = '%s.%s' % (C.__module__, 'C')
199 199 f.for_type(type_str, foo_printer)
200 200 nt.assert_in(type_str, f)
201 201 nt.assert_in(C, f)
202 202
203 203 def test_pop():
204 204 f = PlainTextFormatter()
205 205 f.for_type(C, foo_printer)
206 206 nt.assert_is(f.lookup_by_type(C), foo_printer)
207 207 nt.assert_is(f.pop(C, None), foo_printer)
208 208 f.for_type(C, foo_printer)
209 209 nt.assert_is(f.pop(C), foo_printer)
210 210 with nt.assert_raises(KeyError):
211 211 f.lookup_by_type(C)
212 212 with nt.assert_raises(KeyError):
213 213 f.pop(C)
214 214 with nt.assert_raises(KeyError):
215 215 f.pop(A)
216 216 nt.assert_is(f.pop(A, None), None)
217 217
218 218 def test_pop_string():
219 219 f = PlainTextFormatter()
220 220 type_str = '%s.%s' % (C.__module__, 'C')
221 221
222 222 with nt.assert_raises(KeyError):
223 223 f.pop(type_str)
224 224
225 225 f.for_type(type_str, foo_printer)
226 226 f.pop(type_str)
227 227 with nt.assert_raises(KeyError):
228 228 f.lookup_by_type(C)
229 229 with nt.assert_raises(KeyError):
230 230 f.pop(type_str)
231 231
232 232 f.for_type(C, foo_printer)
233 233 nt.assert_is(f.pop(type_str, None), foo_printer)
234 234 with nt.assert_raises(KeyError):
235 235 f.lookup_by_type(C)
236 236 with nt.assert_raises(KeyError):
237 237 f.pop(type_str)
238 238 nt.assert_is(f.pop(type_str, None), None)
239 239
240 240
241 241 def test_error_method():
242 242 f = HTMLFormatter()
243 243 class BadHTML(object):
244 244 def _repr_html_(self):
245 245 raise ValueError("Bad HTML")
246 246 bad = BadHTML()
247 247 with capture_output() as captured:
248 248 result = f(bad)
249 249 nt.assert_is(result, None)
250 250 nt.assert_in("Traceback", captured.stdout)
251 251 nt.assert_in("Bad HTML", captured.stdout)
252 252 nt.assert_in("_repr_html_", captured.stdout)
253 253
254 254 def test_nowarn_notimplemented():
255 255 f = HTMLFormatter()
256 256 class HTMLNotImplemented(object):
257 257 def _repr_html_(self):
258 258 raise NotImplementedError
259 259 h = HTMLNotImplemented()
260 260 with capture_output() as captured:
261 261 result = f(h)
262 262 nt.assert_is(result, None)
263 263 nt.assert_equal("", captured.stderr)
264 264 nt.assert_equal("", captured.stdout)
265 265
266 266 def test_warn_error_for_type():
267 267 f = HTMLFormatter()
268 268 f.for_type(int, lambda i: name_error)
269 269 with capture_output() as captured:
270 270 result = f(5)
271 271 nt.assert_is(result, None)
272 272 nt.assert_in("Traceback", captured.stdout)
273 273 nt.assert_in("NameError", captured.stdout)
274 274 nt.assert_in("name_error", captured.stdout)
275 275
276 276 def test_error_pretty_method():
277 277 f = PlainTextFormatter()
278 278 class BadPretty(object):
279 279 def _repr_pretty_(self):
280 280 return "hello"
281 281 bad = BadPretty()
282 282 with capture_output() as captured:
283 283 result = f(bad)
284 284 nt.assert_is(result, None)
285 285 nt.assert_in("Traceback", captured.stdout)
286 286 nt.assert_in("_repr_pretty_", captured.stdout)
287 287 nt.assert_in("given", captured.stdout)
288 288 nt.assert_in("argument", captured.stdout)
289 289
290 290
291 291 def test_bad_repr_traceback():
292 292 f = PlainTextFormatter()
293 293 bad = BadRepr()
294 294 with capture_output() as captured:
295 295 result = f(bad)
296 296 # catches error, returns None
297 297 nt.assert_is(result, None)
298 298 nt.assert_in("Traceback", captured.stdout)
299 299 nt.assert_in("__repr__", captured.stdout)
300 300 nt.assert_in("ValueError", captured.stdout)
301 301
302 302
303 303 class MakePDF(object):
304 304 def _repr_pdf_(self):
305 305 return 'PDF'
306 306
307 307 def test_pdf_formatter():
308 308 pdf = MakePDF()
309 309 f = PDFFormatter()
310 310 nt.assert_equal(f(pdf), 'PDF')
311 311
312 312 def test_print_method_bound():
313 313 f = HTMLFormatter()
314 314 class MyHTML(object):
315 315 def _repr_html_(self):
316 316 return "hello"
317 317 with capture_output() as captured:
318 318 result = f(MyHTML)
319 319 nt.assert_is(result, None)
320 320 nt.assert_not_in("FormatterWarning", captured.stderr)
321 321
322 322 with capture_output() as captured:
323 323 result = f(MyHTML())
324 324 nt.assert_equal(result, "hello")
325 325 nt.assert_equal(captured.stderr, "")
326 326
327 327 def test_print_method_weird():
328 328
329 329 class TextMagicHat(object):
330 330 def __getattr__(self, key):
331 331 return key
332 332
333 333 f = HTMLFormatter()
334 334
335 335 text_hat = TextMagicHat()
336 336 nt.assert_equal(text_hat._repr_html_, '_repr_html_')
337 337 with capture_output() as captured:
338 338 result = f(text_hat)
339 339
340 340 nt.assert_is(result, None)
341 341 nt.assert_not_in("FormatterWarning", captured.stderr)
342 342
343 343 class CallableMagicHat(object):
344 344 def __getattr__(self, key):
345 345 return lambda : key
346 346
347 347 call_hat = CallableMagicHat()
348 348 with capture_output() as captured:
349 349 result = f(call_hat)
350 350
351 351 nt.assert_equal(result, None)
352 352
353 353 class BadReprArgs(object):
354 354 def _repr_html_(self, extra, args):
355 355 return "html"
356 356
357 357 bad = BadReprArgs()
358 358 with capture_output() as captured:
359 359 result = f(bad)
360 360
361 361 nt.assert_is(result, None)
362 362 nt.assert_not_in("FormatterWarning", captured.stderr)
363 363
364 364
365 365 def test_format_config():
366 366 """config objects don't pretend to support fancy reprs with lazy attrs"""
367 367 f = HTMLFormatter()
368 368 cfg = Config()
369 369 with capture_output() as captured:
370 370 result = f(cfg)
371 371 nt.assert_is(result, None)
372 372 nt.assert_equal(captured.stderr, "")
373 373
374 374 with capture_output() as captured:
375 375 result = f(Config)
376 376 nt.assert_is(result, None)
377 377 nt.assert_equal(captured.stderr, "")
378 378
379 379 def test_pretty_max_seq_length():
380 380 f = PlainTextFormatter(max_seq_length=1)
381 381 lis = list(range(3))
382 382 text = f(lis)
383 383 nt.assert_equal(text, '[0, ...]')
384 384 f.max_seq_length = 0
385 385 text = f(lis)
386 386 nt.assert_equal(text, '[0, 1, 2]')
387 387 text = f(list(range(1024)))
388 388 lines = text.splitlines()
389 389 nt.assert_equal(len(lines), 1024)
390 390
391 391
392 392 def test_ipython_display_formatter():
393 393 """Objects with _ipython_display_ defined bypass other formatters"""
394 394 f = get_ipython().display_formatter
395 395 catcher = []
396 396 class SelfDisplaying(object):
397 397 def _ipython_display_(self):
398 398 catcher.append(self)
399 399
400 400 class NotSelfDisplaying(object):
401 401 def __repr__(self):
402 402 return "NotSelfDisplaying"
403 403
404 404 def _ipython_display_(self):
405 405 raise NotImplementedError
406 406
407 407 save_enabled = f.ipython_display_formatter.enabled
408 408 f.ipython_display_formatter.enabled = True
409 409
410 410 yes = SelfDisplaying()
411 411 no = NotSelfDisplaying()
412 412
413 413 d, md = f.format(no)
414 414 nt.assert_equal(d, {'text/plain': repr(no)})
415 415 nt.assert_equal(md, {})
416 416 nt.assert_equal(catcher, [])
417 417
418 418 d, md = f.format(yes)
419 419 nt.assert_equal(d, {})
420 420 nt.assert_equal(md, {})
421 421 nt.assert_equal(catcher, [yes])
422 422
423 423 f.ipython_display_formatter.enabled = save_enabled
424 424
425 425
426 426 def test_json_as_string_deprecated():
427 427 class JSONString(object):
428 428 def _repr_json_(self):
429 429 return '{}'
430 430
431 431 f = JSONFormatter()
432 432 with warnings.catch_warnings(record=True) as w:
433 433 d = f(JSONString())
434 434 nt.assert_equal(d, {})
435 435 nt.assert_equal(len(w), 1)
436 436
437 437
438 438 def test_repr_mime():
439 439 class HasReprMime(object):
440 440 def _repr_mimebundle_(self, include=None, exclude=None):
441 441 return {
442 442 'application/json+test.v2': {
443 443 'x': 'y'
444 444 },
445 445 'plain/text' : '<HasReprMime>',
446 446 'image/png' : 'i-overwrite'
447 447 }
448 448
449 449 def _repr_png_(self):
450 450 return 'should-be-overwritten'
451 451 def _repr_html_(self):
452 452 return '<b>hi!</b>'
453 453
454 454 f = get_ipython().display_formatter
455 455 html_f = f.formatters['text/html']
456 456 save_enabled = html_f.enabled
457 457 html_f.enabled = True
458 458 obj = HasReprMime()
459 459 d, md = f.format(obj)
460 460 html_f.enabled = save_enabled
461 461
462 462 nt.assert_equal(sorted(d), ['application/json+test.v2',
463 463 'image/png',
464 464 'plain/text',
465 465 'text/html',
466 466 'text/plain'])
467 467 nt.assert_equal(md, {})
468 468
469 469 d, md = f.format(obj, include={'image/png'})
470 470 nt.assert_equal(list(d.keys()), ['image/png'],
471 471 'Include should filter out even things from repr_mimebundle')
472 472 nt.assert_equal(d['image/png'], 'i-overwrite', '_repr_mimebundle_ take precedence')
473 473
474 474
475 475
476 476 def test_pass_correct_include_exclude():
477 477 class Tester(object):
478 478
479 479 def __init__(self, include=None, exclude=None):
480 480 self.include = include
481 481 self.exclude = exclude
482 482
483 483 def _repr_mimebundle_(self, include, exclude, **kwargs):
484 484 if include and (include != self.include):
485 485 raise ValueError('include got modified: display() may be broken.')
486 486 if exclude and (exclude != self.exclude):
487 487 raise ValueError('exclude got modified: display() may be broken.')
488 488
489 489 return None
490 490
491 491 include = {'a', 'b', 'c'}
492 492 exclude = {'c', 'e' , 'f'}
493 493
494 494 f = get_ipython().display_formatter
495 495 f.format(Tester(include=include, exclude=exclude), include=include, exclude=exclude)
496 496 f.format(Tester(exclude=exclude), exclude=exclude)
497 497 f.format(Tester(include=include), include=include)
498 498
499 499
500 500 def test_repr_mime_meta():
501 501 class HasReprMimeMeta(object):
502 502 def _repr_mimebundle_(self, include=None, exclude=None):
503 503 data = {
504 504 'image/png': 'base64-image-data',
505 505 }
506 506 metadata = {
507 507 'image/png': {
508 508 'width': 5,
509 509 'height': 10,
510 510 }
511 511 }
512 512 return (data, metadata)
513 513
514 514 f = get_ipython().display_formatter
515 515 obj = HasReprMimeMeta()
516 516 d, md = f.format(obj)
517 517 nt.assert_equal(sorted(d), ['image/png', 'text/plain'])
518 518 nt.assert_equal(md, {
519 519 'image/png': {
520 520 'width': 5,
521 521 'height': 10,
522 522 }
523 523 })
524 524
525 525 def test_repr_mime_failure():
526 526 class BadReprMime(object):
527 527 def _repr_mimebundle_(self, include=None, exclude=None):
528 528 raise RuntimeError
529 529
530 530 f = get_ipython().display_formatter
531 531 obj = BadReprMime()
532 532 d, md = f.format(obj)
533 533 nt.assert_in('text/plain', d)
@@ -1,876 +1,865 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 Python advanced pretty printer. This pretty printer is intended to
4 4 replace the old `pprint` python module which does not allow developers
5 5 to provide their own pretty print callbacks.
6 6
7 7 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
8 8
9 9
10 10 Example Usage
11 11 -------------
12 12
13 13 To directly print the representation of an object use `pprint`::
14 14
15 15 from pretty import pprint
16 16 pprint(complex_object)
17 17
18 18 To get a string of the output use `pretty`::
19 19
20 20 from pretty import pretty
21 21 string = pretty(complex_object)
22 22
23 23
24 24 Extending
25 25 ---------
26 26
27 27 The pretty library allows developers to add pretty printing rules for their
28 28 own objects. This process is straightforward. All you have to do is to
29 29 add a `_repr_pretty_` method to your object and call the methods on the
30 30 pretty printer passed::
31 31
32 32 class MyObject(object):
33 33
34 34 def _repr_pretty_(self, p, cycle):
35 35 ...
36 36
37 37 Here is an example implementation of a `_repr_pretty_` method for a list
38 38 subclass::
39 39
40 40 class MyList(list):
41 41
42 42 def _repr_pretty_(self, p, cycle):
43 43 if cycle:
44 44 p.text('MyList(...)')
45 45 else:
46 46 with p.group(8, 'MyList([', '])'):
47 47 for idx, item in enumerate(self):
48 48 if idx:
49 49 p.text(',')
50 50 p.breakable()
51 51 p.pretty(item)
52 52
53 53 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
54 54 react to that or the result is an infinite loop. `p.text()` just adds
55 55 non breaking text to the output, `p.breakable()` either adds a whitespace
56 56 or breaks here. If you pass it an argument it's used instead of the
57 57 default space. `p.pretty` prettyprints another object using the pretty print
58 58 method.
59 59
60 60 The first parameter to the `group` function specifies the extra indentation
61 61 of the next line. In this example the next item will either be on the same
62 62 line (if the items are short enough) or aligned with the right edge of the
63 63 opening bracket of `MyList`.
64 64
65 65 If you just want to indent something you can use the group function
66 66 without open / close parameters. You can also use this code::
67 67
68 68 with p.indent(2):
69 69 ...
70 70
71 71 Inheritance diagram:
72 72
73 73 .. inheritance-diagram:: IPython.lib.pretty
74 74 :parts: 3
75 75
76 76 :copyright: 2007 by Armin Ronacher.
77 77 Portions (c) 2009 by Robert Kern.
78 78 :license: BSD License.
79 79 """
80 80 from contextlib import contextmanager
81 81 import sys
82 82 import types
83 83 import re
84 84 import datetime
85 85 from collections import deque
86 86 from io import StringIO
87 87 from warnings import warn
88 88
89 89 from IPython.utils.decorators import undoc
90 90 from IPython.utils.py3compat import PYPY
91 91 from IPython.utils.signatures import signature
92 92
93 93 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
94 94 'for_type', 'for_type_by_name']
95 95
96 96
97 97 MAX_SEQ_LENGTH = 1000
98 98 # The language spec says that dicts preserve order from 3.7, but CPython
99 99 # does so from 3.6, so it seems likely that people will expect that.
100 100 DICT_IS_ORDERED = sys.version_info >= (3, 6)
101 101 _re_pattern_type = type(re.compile(''))
102 102
103 103 def _safe_getattr(obj, attr, default=None):
104 104 """Safe version of getattr.
105 105
106 106 Same as getattr, but will return ``default`` on any Exception,
107 107 rather than raising.
108 108 """
109 109 try:
110 110 return getattr(obj, attr, default)
111 111 except Exception:
112 112 return default
113 113
114 114 @undoc
115 115 class CUnicodeIO(StringIO):
116 116 def __init__(self, *args, **kwargs):
117 117 super().__init__(*args, **kwargs)
118 118 warn(("CUnicodeIO is deprecated since IPython 6.0. "
119 119 "Please use io.StringIO instead."),
120 120 DeprecationWarning, stacklevel=2)
121 121
122 122 def _sorted_for_pprint(items):
123 123 """
124 124 Sort the given items for pretty printing. Since some predictable
125 125 sorting is better than no sorting at all, we sort on the string
126 126 representation if normal sorting fails.
127 127 """
128 128 items = list(items)
129 129 try:
130 130 return sorted(items)
131 131 except Exception:
132 132 try:
133 133 return sorted(items, key=str)
134 134 except Exception:
135 135 return items
136 136
137 137 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
138 138 """
139 139 Pretty print the object's representation.
140 140 """
141 141 stream = StringIO()
142 142 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
143 143 printer.pretty(obj)
144 144 printer.flush()
145 145 return stream.getvalue()
146 146
147 147
148 148 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
149 149 """
150 150 Like `pretty` but print to stdout.
151 151 """
152 152 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
153 153 printer.pretty(obj)
154 154 printer.flush()
155 155 sys.stdout.write(newline)
156 156 sys.stdout.flush()
157 157
158 158 class _PrettyPrinterBase(object):
159 159
160 160 @contextmanager
161 161 def indent(self, indent):
162 162 """with statement support for indenting/dedenting."""
163 163 self.indentation += indent
164 164 try:
165 165 yield
166 166 finally:
167 167 self.indentation -= indent
168 168
169 169 @contextmanager
170 170 def group(self, indent=0, open='', close=''):
171 171 """like begin_group / end_group but for the with statement."""
172 172 self.begin_group(indent, open)
173 173 try:
174 174 yield
175 175 finally:
176 176 self.end_group(indent, close)
177 177
178 178 class PrettyPrinter(_PrettyPrinterBase):
179 179 """
180 180 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
181 181 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
182 182 this printer knows nothing about the default pprinters or the `_repr_pretty_`
183 183 callback method.
184 184 """
185 185
186 186 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
187 187 self.output = output
188 188 self.max_width = max_width
189 189 self.newline = newline
190 190 self.max_seq_length = max_seq_length
191 191 self.output_width = 0
192 192 self.buffer_width = 0
193 193 self.buffer = deque()
194 194
195 195 root_group = Group(0)
196 196 self.group_stack = [root_group]
197 197 self.group_queue = GroupQueue(root_group)
198 198 self.indentation = 0
199 199
200 200 def _break_outer_groups(self):
201 201 while self.max_width < self.output_width + self.buffer_width:
202 202 group = self.group_queue.deq()
203 203 if not group:
204 204 return
205 205 while group.breakables:
206 206 x = self.buffer.popleft()
207 207 self.output_width = x.output(self.output, self.output_width)
208 208 self.buffer_width -= x.width
209 209 while self.buffer and isinstance(self.buffer[0], Text):
210 210 x = self.buffer.popleft()
211 211 self.output_width = x.output(self.output, self.output_width)
212 212 self.buffer_width -= x.width
213 213
214 214 def text(self, obj):
215 215 """Add literal text to the output."""
216 216 width = len(obj)
217 217 if self.buffer:
218 218 text = self.buffer[-1]
219 219 if not isinstance(text, Text):
220 220 text = Text()
221 221 self.buffer.append(text)
222 222 text.add(obj, width)
223 223 self.buffer_width += width
224 224 self._break_outer_groups()
225 225 else:
226 226 self.output.write(obj)
227 227 self.output_width += width
228 228
229 229 def breakable(self, sep=' '):
230 230 """
231 231 Add a breakable separator to the output. This does not mean that it
232 232 will automatically break here. If no breaking on this position takes
233 233 place the `sep` is inserted which default to one space.
234 234 """
235 235 width = len(sep)
236 236 group = self.group_stack[-1]
237 237 if group.want_break:
238 238 self.flush()
239 239 self.output.write(self.newline)
240 240 self.output.write(' ' * self.indentation)
241 241 self.output_width = self.indentation
242 242 self.buffer_width = 0
243 243 else:
244 244 self.buffer.append(Breakable(sep, width, self))
245 245 self.buffer_width += width
246 246 self._break_outer_groups()
247 247
248 248 def break_(self):
249 249 """
250 250 Explicitly insert a newline into the output, maintaining correct indentation.
251 251 """
252 252 self.flush()
253 253 self.output.write(self.newline)
254 254 self.output.write(' ' * self.indentation)
255 255 self.output_width = self.indentation
256 256 self.buffer_width = 0
257 257
258 258
259 259 def begin_group(self, indent=0, open=''):
260 260 """
261 261 Begin a group. If you want support for python < 2.5 which doesn't has
262 262 the with statement this is the preferred way:
263 263
264 264 p.begin_group(1, '{')
265 265 ...
266 266 p.end_group(1, '}')
267 267
268 268 The python 2.5 expression would be this:
269 269
270 270 with p.group(1, '{', '}'):
271 271 ...
272 272
273 273 The first parameter specifies the indentation for the next line (usually
274 274 the width of the opening text), the second the opening text. All
275 275 parameters are optional.
276 276 """
277 277 if open:
278 278 self.text(open)
279 279 group = Group(self.group_stack[-1].depth + 1)
280 280 self.group_stack.append(group)
281 281 self.group_queue.enq(group)
282 282 self.indentation += indent
283 283
284 284 def _enumerate(self, seq):
285 285 """like enumerate, but with an upper limit on the number of items"""
286 286 for idx, x in enumerate(seq):
287 287 if self.max_seq_length and idx >= self.max_seq_length:
288 288 self.text(',')
289 289 self.breakable()
290 290 self.text('...')
291 291 return
292 292 yield idx, x
293 293
294 294 def end_group(self, dedent=0, close=''):
295 295 """End a group. See `begin_group` for more details."""
296 296 self.indentation -= dedent
297 297 group = self.group_stack.pop()
298 298 if not group.breakables:
299 299 self.group_queue.remove(group)
300 300 if close:
301 301 self.text(close)
302 302
303 303 def flush(self):
304 304 """Flush data that is left in the buffer."""
305 305 for data in self.buffer:
306 306 self.output_width += data.output(self.output, self.output_width)
307 307 self.buffer.clear()
308 308 self.buffer_width = 0
309 309
310 310
311 311 def _get_mro(obj_class):
312 312 """ Get a reasonable method resolution order of a class and its superclasses
313 313 for both old-style and new-style classes.
314 314 """
315 315 if not hasattr(obj_class, '__mro__'):
316 316 # Old-style class. Mix in object to make a fake new-style class.
317 317 try:
318 318 obj_class = type(obj_class.__name__, (obj_class, object), {})
319 319 except TypeError:
320 320 # Old-style extension type that does not descend from object.
321 321 # FIXME: try to construct a more thorough MRO.
322 322 mro = [obj_class]
323 323 else:
324 324 mro = obj_class.__mro__[1:-1]
325 325 else:
326 326 mro = obj_class.__mro__
327 327 return mro
328 328
329 329
330 330 class RepresentationPrinter(PrettyPrinter):
331 331 """
332 332 Special pretty printer that has a `pretty` method that calls the pretty
333 333 printer for a python object.
334 334
335 335 This class stores processing data on `self` so you must *never* use
336 336 this class in a threaded environment. Always lock it or reinstanciate
337 337 it.
338 338
339 339 Instances also have a verbose flag callbacks can access to control their
340 340 output. For example the default instance repr prints all attributes and
341 341 methods that are not prefixed by an underscore if the printer is in
342 342 verbose mode.
343 343 """
344 344
345 345 def __init__(self, output, verbose=False, max_width=79, newline='\n',
346 346 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
347 347 max_seq_length=MAX_SEQ_LENGTH):
348 348
349 349 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
350 350 self.verbose = verbose
351 351 self.stack = []
352 352 if singleton_pprinters is None:
353 353 singleton_pprinters = _singleton_pprinters.copy()
354 354 self.singleton_pprinters = singleton_pprinters
355 355 if type_pprinters is None:
356 356 type_pprinters = _type_pprinters.copy()
357 357 self.type_pprinters = type_pprinters
358 358 if deferred_pprinters is None:
359 359 deferred_pprinters = _deferred_type_pprinters.copy()
360 360 self.deferred_pprinters = deferred_pprinters
361 361
362 362 def pretty(self, obj):
363 363 """Pretty print the given object."""
364 364 obj_id = id(obj)
365 365 cycle = obj_id in self.stack
366 366 self.stack.append(obj_id)
367 367 self.begin_group()
368 368 try:
369 369 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
370 370 # First try to find registered singleton printers for the type.
371 371 try:
372 372 printer = self.singleton_pprinters[obj_id]
373 373 except (TypeError, KeyError):
374 374 pass
375 375 else:
376 376 return printer(obj, self, cycle)
377 377 # Next walk the mro and check for either:
378 378 # 1) a registered printer
379 379 # 2) a _repr_pretty_ method
380 380 for cls in _get_mro(obj_class):
381 381 if cls in self.type_pprinters:
382 382 # printer registered in self.type_pprinters
383 383 return self.type_pprinters[cls](obj, self, cycle)
384 384 else:
385 385 # deferred printer
386 386 printer = self._in_deferred_types(cls)
387 387 if printer is not None:
388 388 return printer(obj, self, cycle)
389 389 else:
390 390 # Finally look for special method names.
391 391 # Some objects automatically create any requested
392 392 # attribute. Try to ignore most of them by checking for
393 393 # callability.
394 394 if '_repr_pretty_' in cls.__dict__:
395 395 meth = cls._repr_pretty_
396 396 if callable(meth):
397 397 return meth(obj, self, cycle)
398 if cls is not object \
399 and callable(cls.__dict__.get('__repr__')):
400 return _repr_pprint(obj, self, cycle)
401
398 402 return _default_pprint(obj, self, cycle)
399 403 finally:
400 404 self.end_group()
401 405 self.stack.pop()
402 406
403 407 def _in_deferred_types(self, cls):
404 408 """
405 409 Check if the given class is specified in the deferred type registry.
406 410
407 411 Returns the printer from the registry if it exists, and None if the
408 412 class is not in the registry. Successful matches will be moved to the
409 413 regular type registry for future use.
410 414 """
411 415 mod = _safe_getattr(cls, '__module__', None)
412 416 name = _safe_getattr(cls, '__name__', None)
413 417 key = (mod, name)
414 418 printer = None
415 419 if key in self.deferred_pprinters:
416 420 # Move the printer over to the regular registry.
417 421 printer = self.deferred_pprinters.pop(key)
418 422 self.type_pprinters[cls] = printer
419 423 return printer
420 424
421 425
422 426 class Printable(object):
423 427
424 428 def output(self, stream, output_width):
425 429 return output_width
426 430
427 431
428 432 class Text(Printable):
429 433
430 434 def __init__(self):
431 435 self.objs = []
432 436 self.width = 0
433 437
434 438 def output(self, stream, output_width):
435 439 for obj in self.objs:
436 440 stream.write(obj)
437 441 return output_width + self.width
438 442
439 443 def add(self, obj, width):
440 444 self.objs.append(obj)
441 445 self.width += width
442 446
443 447
444 448 class Breakable(Printable):
445 449
446 450 def __init__(self, seq, width, pretty):
447 451 self.obj = seq
448 452 self.width = width
449 453 self.pretty = pretty
450 454 self.indentation = pretty.indentation
451 455 self.group = pretty.group_stack[-1]
452 456 self.group.breakables.append(self)
453 457
454 458 def output(self, stream, output_width):
455 459 self.group.breakables.popleft()
456 460 if self.group.want_break:
457 461 stream.write(self.pretty.newline)
458 462 stream.write(' ' * self.indentation)
459 463 return self.indentation
460 464 if not self.group.breakables:
461 465 self.pretty.group_queue.remove(self.group)
462 466 stream.write(self.obj)
463 467 return output_width + self.width
464 468
465 469
466 470 class Group(Printable):
467 471
468 472 def __init__(self, depth):
469 473 self.depth = depth
470 474 self.breakables = deque()
471 475 self.want_break = False
472 476
473 477
474 478 class GroupQueue(object):
475 479
476 480 def __init__(self, *groups):
477 481 self.queue = []
478 482 for group in groups:
479 483 self.enq(group)
480 484
481 485 def enq(self, group):
482 486 depth = group.depth
483 487 while depth > len(self.queue) - 1:
484 488 self.queue.append([])
485 489 self.queue[depth].append(group)
486 490
487 491 def deq(self):
488 492 for stack in self.queue:
489 493 for idx, group in enumerate(reversed(stack)):
490 494 if group.breakables:
491 495 del stack[idx]
492 496 group.want_break = True
493 497 return group
494 498 for group in stack:
495 499 group.want_break = True
496 500 del stack[:]
497 501
498 502 def remove(self, group):
499 503 try:
500 504 self.queue[group.depth].remove(group)
501 505 except ValueError:
502 506 pass
503 507
504 508
505 509 def _default_pprint(obj, p, cycle):
506 510 """
507 511 The default print function. Used if an object does not provide one and
508 512 it's none of the builtin objects.
509 513 """
510 514 klass = _safe_getattr(obj, '__class__', None) or type(obj)
511 515 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
512 516 # A user-provided repr. Find newlines and replace them with p.break_()
513 517 _repr_pprint(obj, p, cycle)
514 518 return
515 519 p.begin_group(1, '<')
516 520 p.pretty(klass)
517 521 p.text(' at 0x%x' % id(obj))
518 522 if cycle:
519 523 p.text(' ...')
520 524 elif p.verbose:
521 525 first = True
522 526 for key in dir(obj):
523 527 if not key.startswith('_'):
524 528 try:
525 529 value = getattr(obj, key)
526 530 except AttributeError:
527 531 continue
528 532 if isinstance(value, types.MethodType):
529 533 continue
530 534 if not first:
531 535 p.text(',')
532 536 p.breakable()
533 537 p.text(key)
534 538 p.text('=')
535 539 step = len(key) + 1
536 540 p.indentation += step
537 541 p.pretty(value)
538 542 p.indentation -= step
539 543 first = False
540 544 p.end_group(1, '>')
541 545
542 546
543 def _seq_pprinter_factory(start, end, basetype):
547 def _seq_pprinter_factory(start, end):
544 548 """
545 549 Factory that returns a pprint function useful for sequences. Used by
546 550 the default pprint for tuples, dicts, and lists.
547 551 """
548 552 def inner(obj, p, cycle):
549 typ = type(obj)
550 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
551 # If the subclass provides its own repr, use it instead.
552 return p.text(typ.__repr__(obj))
553
554 553 if cycle:
555 554 return p.text(start + '...' + end)
556 555 step = len(start)
557 556 p.begin_group(step, start)
558 557 for idx, x in p._enumerate(obj):
559 558 if idx:
560 559 p.text(',')
561 560 p.breakable()
562 561 p.pretty(x)
563 562 if len(obj) == 1 and type(obj) is tuple:
564 563 # Special case for 1-item tuples.
565 564 p.text(',')
566 565 p.end_group(step, end)
567 566 return inner
568 567
569 568
570 def _set_pprinter_factory(start, end, basetype):
569 def _set_pprinter_factory(start, end):
571 570 """
572 571 Factory that returns a pprint function useful for sets and frozensets.
573 572 """
574 573 def inner(obj, p, cycle):
575 typ = type(obj)
576 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
577 # If the subclass provides its own repr, use it instead.
578 return p.text(typ.__repr__(obj))
579
580 574 if cycle:
581 575 return p.text(start + '...' + end)
582 576 if len(obj) == 0:
583 577 # Special case.
584 p.text(basetype.__name__ + '()')
578 p.text(type(obj).__name__ + '()')
585 579 else:
586 580 step = len(start)
587 581 p.begin_group(step, start)
588 582 # Like dictionary keys, we will try to sort the items if there aren't too many
589 583 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
590 584 items = _sorted_for_pprint(obj)
591 585 else:
592 586 items = obj
593 587 for idx, x in p._enumerate(items):
594 588 if idx:
595 589 p.text(',')
596 590 p.breakable()
597 591 p.pretty(x)
598 592 p.end_group(step, end)
599 593 return inner
600 594
601 595
602 def _dict_pprinter_factory(start, end, basetype=None):
596 def _dict_pprinter_factory(start, end):
603 597 """
604 598 Factory that returns a pprint function used by the default pprint of
605 599 dicts and dict proxies.
606 600 """
607 601 def inner(obj, p, cycle):
608 typ = type(obj)
609 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
610 # If the subclass provides its own repr, use it instead.
611 return p.text(typ.__repr__(obj))
612
613 602 if cycle:
614 603 return p.text('{...}')
615 604 step = len(start)
616 605 p.begin_group(step, start)
617 606 keys = obj.keys()
618 607 # if dict isn't large enough to be truncated, sort keys before displaying
619 608 # From Python 3.7, dicts preserve order by definition, so we don't sort.
620 609 if not DICT_IS_ORDERED \
621 610 and not (p.max_seq_length and len(obj) >= p.max_seq_length):
622 611 keys = _sorted_for_pprint(keys)
623 612 for idx, key in p._enumerate(keys):
624 613 if idx:
625 614 p.text(',')
626 615 p.breakable()
627 616 p.pretty(key)
628 617 p.text(': ')
629 618 p.pretty(obj[key])
630 619 p.end_group(step, end)
631 620 return inner
632 621
633 622
634 623 def _super_pprint(obj, p, cycle):
635 624 """The pprint for the super type."""
636 625 p.begin_group(8, '<super: ')
637 626 p.pretty(obj.__thisclass__)
638 627 p.text(',')
639 628 p.breakable()
640 629 if PYPY: # In PyPy, super() objects don't have __self__ attributes
641 630 dself = obj.__repr__.__self__
642 631 p.pretty(None if dself is obj else dself)
643 632 else:
644 633 p.pretty(obj.__self__)
645 634 p.end_group(8, '>')
646 635
647 636
648 637 def _re_pattern_pprint(obj, p, cycle):
649 638 """The pprint function for regular expression patterns."""
650 639 p.text('re.compile(')
651 640 pattern = repr(obj.pattern)
652 641 if pattern[:1] in 'uU':
653 642 pattern = pattern[1:]
654 643 prefix = 'ur'
655 644 else:
656 645 prefix = 'r'
657 646 pattern = prefix + pattern.replace('\\\\', '\\')
658 647 p.text(pattern)
659 648 if obj.flags:
660 649 p.text(',')
661 650 p.breakable()
662 651 done_one = False
663 652 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
664 653 'UNICODE', 'VERBOSE', 'DEBUG'):
665 654 if obj.flags & getattr(re, flag):
666 655 if done_one:
667 656 p.text('|')
668 657 p.text('re.' + flag)
669 658 done_one = True
670 659 p.text(')')
671 660
672 661
673 662 def _type_pprint(obj, p, cycle):
674 663 """The pprint for classes and types."""
675 664 # Heap allocated types might not have the module attribute,
676 665 # and others may set it to None.
677 666
678 667 # Checks for a __repr__ override in the metaclass. Can't compare the
679 668 # type(obj).__repr__ directly because in PyPy the representation function
680 669 # inherited from type isn't the same type.__repr__
681 670 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
682 671 _repr_pprint(obj, p, cycle)
683 672 return
684 673
685 674 mod = _safe_getattr(obj, '__module__', None)
686 675 try:
687 676 name = obj.__qualname__
688 677 if not isinstance(name, str):
689 678 # This can happen if the type implements __qualname__ as a property
690 679 # or other descriptor in Python 2.
691 680 raise Exception("Try __name__")
692 681 except Exception:
693 682 name = obj.__name__
694 683 if not isinstance(name, str):
695 684 name = '<unknown type>'
696 685
697 686 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
698 687 p.text(name)
699 688 else:
700 689 p.text(mod + '.' + name)
701 690
702 691
703 692 def _repr_pprint(obj, p, cycle):
704 693 """A pprint that just redirects to the normal repr function."""
705 694 # Find newlines and replace them with p.break_()
706 695 output = repr(obj)
707 696 for idx,output_line in enumerate(output.splitlines()):
708 697 if idx:
709 698 p.break_()
710 699 p.text(output_line)
711 700
712 701
713 702 def _function_pprint(obj, p, cycle):
714 703 """Base pprint for all functions and builtin functions."""
715 704 name = _safe_getattr(obj, '__qualname__', obj.__name__)
716 705 mod = obj.__module__
717 706 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
718 707 name = mod + '.' + name
719 708 try:
720 709 func_def = name + str(signature(obj))
721 710 except ValueError:
722 711 func_def = name
723 712 p.text('<function %s>' % func_def)
724 713
725 714
726 715 def _exception_pprint(obj, p, cycle):
727 716 """Base pprint for all exceptions."""
728 717 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
729 718 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
730 719 name = '%s.%s' % (obj.__class__.__module__, name)
731 720 step = len(name) + 1
732 721 p.begin_group(step, name + '(')
733 722 for idx, arg in enumerate(getattr(obj, 'args', ())):
734 723 if idx:
735 724 p.text(',')
736 725 p.breakable()
737 726 p.pretty(arg)
738 727 p.end_group(step, ')')
739 728
740 729
741 730 #: the exception base
742 731 try:
743 732 _exception_base = BaseException
744 733 except NameError:
745 734 _exception_base = Exception
746 735
747 736
748 737 #: printers for builtin types
749 738 _type_pprinters = {
750 739 int: _repr_pprint,
751 740 float: _repr_pprint,
752 741 str: _repr_pprint,
753 tuple: _seq_pprinter_factory('(', ')', tuple),
754 list: _seq_pprinter_factory('[', ']', list),
755 dict: _dict_pprinter_factory('{', '}', dict),
742 tuple: _seq_pprinter_factory('(', ')'),
743 list: _seq_pprinter_factory('[', ']'),
744 dict: _dict_pprinter_factory('{', '}'),
756 745
757 set: _set_pprinter_factory('{', '}', set),
758 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
746 set: _set_pprinter_factory('{', '}'),
747 frozenset: _set_pprinter_factory('frozenset({', '})'),
759 748 super: _super_pprint,
760 749 _re_pattern_type: _re_pattern_pprint,
761 750 type: _type_pprint,
762 751 types.FunctionType: _function_pprint,
763 752 types.BuiltinFunctionType: _function_pprint,
764 753 types.MethodType: _repr_pprint,
765 754
766 755 datetime.datetime: _repr_pprint,
767 756 datetime.timedelta: _repr_pprint,
768 757 _exception_base: _exception_pprint
769 758 }
770 759
771 760 try:
772 761 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
773 762 # using dict.setdefault avoids overwritting the dict printer
774 763 _type_pprinters.setdefault(types.DictProxyType,
775 764 _dict_pprinter_factory('dict_proxy({', '})'))
776 765 _type_pprinters[types.ClassType] = _type_pprint
777 766 _type_pprinters[types.SliceType] = _repr_pprint
778 767 except AttributeError: # Python 3
779 768 _type_pprinters[types.MappingProxyType] = \
780 769 _dict_pprinter_factory('mappingproxy({', '})')
781 770 _type_pprinters[slice] = _repr_pprint
782 771
783 772 try:
784 773 _type_pprinters[long] = _repr_pprint
785 774 _type_pprinters[unicode] = _repr_pprint
786 775 except NameError:
787 776 _type_pprinters[range] = _repr_pprint
788 777 _type_pprinters[bytes] = _repr_pprint
789 778
790 779 #: printers for types specified by name
791 780 _deferred_type_pprinters = {
792 781 }
793 782
794 783 def for_type(typ, func):
795 784 """
796 785 Add a pretty printer for a given type.
797 786 """
798 787 oldfunc = _type_pprinters.get(typ, None)
799 788 if func is not None:
800 789 # To support easy restoration of old pprinters, we need to ignore Nones.
801 790 _type_pprinters[typ] = func
802 791 return oldfunc
803 792
804 793 def for_type_by_name(type_module, type_name, func):
805 794 """
806 795 Add a pretty printer for a type specified by the module and name of a type
807 796 rather than the type object itself.
808 797 """
809 798 key = (type_module, type_name)
810 799 oldfunc = _deferred_type_pprinters.get(key, None)
811 800 if func is not None:
812 801 # To support easy restoration of old pprinters, we need to ignore Nones.
813 802 _deferred_type_pprinters[key] = func
814 803 return oldfunc
815 804
816 805
817 806 #: printers for the default singletons
818 807 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
819 808 NotImplemented]), _repr_pprint)
820 809
821 810
822 811 def _defaultdict_pprint(obj, p, cycle):
823 812 name = obj.__class__.__name__
824 813 with p.group(len(name) + 1, name + '(', ')'):
825 814 if cycle:
826 815 p.text('...')
827 816 else:
828 817 p.pretty(obj.default_factory)
829 818 p.text(',')
830 819 p.breakable()
831 820 p.pretty(dict(obj))
832 821
833 822 def _ordereddict_pprint(obj, p, cycle):
834 823 name = obj.__class__.__name__
835 824 with p.group(len(name) + 1, name + '(', ')'):
836 825 if cycle:
837 826 p.text('...')
838 827 elif len(obj):
839 828 p.pretty(list(obj.items()))
840 829
841 830 def _deque_pprint(obj, p, cycle):
842 831 name = obj.__class__.__name__
843 832 with p.group(len(name) + 1, name + '(', ')'):
844 833 if cycle:
845 834 p.text('...')
846 835 else:
847 836 p.pretty(list(obj))
848 837
849 838
850 839 def _counter_pprint(obj, p, cycle):
851 840 name = obj.__class__.__name__
852 841 with p.group(len(name) + 1, name + '(', ')'):
853 842 if cycle:
854 843 p.text('...')
855 844 elif len(obj):
856 845 p.pretty(dict(obj))
857 846
858 847 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
859 848 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
860 849 for_type_by_name('collections', 'deque', _deque_pprint)
861 850 for_type_by_name('collections', 'Counter', _counter_pprint)
862 851
863 852 if __name__ == '__main__':
864 853 from random import randrange
865 854 class Foo(object):
866 855 def __init__(self):
867 856 self.foo = 1
868 857 self.bar = re.compile(r'\s+')
869 858 self.blub = dict.fromkeys(range(30), randrange(1, 40))
870 859 self.hehe = 23424.234234
871 860 self.list = ["blub", "blah", self]
872 861
873 862 def get_foo(self):
874 863 print("foo")
875 864
876 865 pprint(Foo(), verbose=True)
@@ -1,423 +1,443 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 types
10 10 import string
11 11 import unittest
12 12
13 13 import nose.tools as nt
14 14
15 15 from IPython.lib import pretty
16 16 from IPython.testing.decorators import skip_without
17 17
18 18 from io import StringIO
19 19
20 20
21 21 class MyList(object):
22 22 def __init__(self, content):
23 23 self.content = content
24 24 def _repr_pretty_(self, p, cycle):
25 25 if cycle:
26 26 p.text("MyList(...)")
27 27 else:
28 28 with p.group(3, "MyList(", ")"):
29 29 for (i, child) in enumerate(self.content):
30 30 if i:
31 31 p.text(",")
32 32 p.breakable()
33 33 else:
34 34 p.breakable("")
35 35 p.pretty(child)
36 36
37 37
38 38 class MyDict(dict):
39 39 def _repr_pretty_(self, p, cycle):
40 40 p.text("MyDict(...)")
41 41
42 42 class MyObj(object):
43 43 def somemethod(self):
44 44 pass
45 45
46 46
47 47 class Dummy1(object):
48 48 def _repr_pretty_(self, p, cycle):
49 49 p.text("Dummy1(...)")
50 50
51 51 class Dummy2(Dummy1):
52 52 _repr_pretty_ = None
53 53
54 54 class NoModule(object):
55 55 pass
56 56
57 57 NoModule.__module__ = None
58 58
59 59 class Breaking(object):
60 60 def _repr_pretty_(self, p, cycle):
61 61 with p.group(4,"TG: ",":"):
62 62 p.text("Breaking(")
63 63 p.break_()
64 64 p.text(")")
65 65
66 66 class BreakingRepr(object):
67 67 def __repr__(self):
68 68 return "Breaking(\n)"
69 69
70 70 class BreakingReprParent(object):
71 71 def _repr_pretty_(self, p, cycle):
72 72 with p.group(4,"TG: ",":"):
73 73 p.pretty(BreakingRepr())
74 74
75 75 class BadRepr(object):
76 76
77 77 def __repr__(self):
78 78 return 1/0
79 79
80 80
81 81 def test_indentation():
82 82 """Test correct indentation in groups"""
83 83 count = 40
84 84 gotoutput = pretty.pretty(MyList(range(count)))
85 85 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
86 86
87 87 nt.assert_equal(gotoutput, expectedoutput)
88 88
89 89
90 90 def test_dispatch():
91 91 """
92 92 Test correct dispatching: The _repr_pretty_ method for MyDict
93 93 must be found before the registered printer for dict.
94 94 """
95 95 gotoutput = pretty.pretty(MyDict())
96 96 expectedoutput = "MyDict(...)"
97 97
98 98 nt.assert_equal(gotoutput, expectedoutput)
99 99
100 100
101 101 def test_callability_checking():
102 102 """
103 103 Test that the _repr_pretty_ method is tested for callability and skipped if
104 104 not.
105 105 """
106 106 gotoutput = pretty.pretty(Dummy2())
107 107 expectedoutput = "Dummy1(...)"
108 108
109 109 nt.assert_equal(gotoutput, expectedoutput)
110 110
111 111
112 112 def test_sets():
113 113 """
114 114 Test that set and frozenset use Python 3 formatting.
115 115 """
116 116 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
117 117 frozenset([1, 2]), set([-1, -2, -3])]
118 118 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
119 119 'frozenset({1, 2})', '{-3, -2, -1}']
120 120 for obj, expected_output in zip(objects, expected):
121 121 got_output = pretty.pretty(obj)
122 122 yield nt.assert_equal, got_output, expected_output
123 123
124 124
125 125 @skip_without('xxlimited')
126 126 def test_pprint_heap_allocated_type():
127 127 """
128 128 Test that pprint works for heap allocated types.
129 129 """
130 130 import xxlimited
131 131 output = pretty.pretty(xxlimited.Null)
132 132 nt.assert_equal(output, 'xxlimited.Null')
133 133
134 134 def test_pprint_nomod():
135 135 """
136 136 Test that pprint works for classes with no __module__.
137 137 """
138 138 output = pretty.pretty(NoModule)
139 139 nt.assert_equal(output, 'NoModule')
140 140
141 141 def test_pprint_break():
142 142 """
143 143 Test that p.break_ produces expected output
144 144 """
145 145 output = pretty.pretty(Breaking())
146 146 expected = "TG: Breaking(\n ):"
147 147 nt.assert_equal(output, expected)
148 148
149 149 def test_pprint_break_repr():
150 150 """
151 151 Test that p.break_ is used in repr
152 152 """
153 153 output = pretty.pretty(BreakingReprParent())
154 154 expected = "TG: Breaking(\n ):"
155 155 nt.assert_equal(output, expected)
156 156
157 157 def test_bad_repr():
158 158 """Don't catch bad repr errors"""
159 159 with nt.assert_raises(ZeroDivisionError):
160 160 pretty.pretty(BadRepr())
161 161
162 162 class BadException(Exception):
163 163 def __str__(self):
164 164 return -1
165 165
166 166 class ReallyBadRepr(object):
167 167 __module__ = 1
168 168 @property
169 169 def __class__(self):
170 170 raise ValueError("I am horrible")
171 171
172 172 def __repr__(self):
173 173 raise BadException()
174 174
175 175 def test_really_bad_repr():
176 176 with nt.assert_raises(BadException):
177 177 pretty.pretty(ReallyBadRepr())
178 178
179 179
180 180 class SA(object):
181 181 pass
182 182
183 183 class SB(SA):
184 184 pass
185 185
186 186 class TestsPretty(unittest.TestCase):
187 187
188 188 def test_super_repr(self):
189 189 # "<super: module_name.SA, None>"
190 190 output = pretty.pretty(super(SA))
191 191 self.assertRegex(output, r"<super: \S+.SA, None>")
192 192
193 193 # "<super: module_name.SA, <module_name.SB at 0x...>>"
194 194 sb = SB()
195 195 output = pretty.pretty(super(SA, sb))
196 196 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
197 197
198 198
199 199 def test_long_list(self):
200 200 lis = list(range(10000))
201 201 p = pretty.pretty(lis)
202 202 last2 = p.rsplit('\n', 2)[-2:]
203 203 self.assertEqual(last2, [' 999,', ' ...]'])
204 204
205 205 def test_long_set(self):
206 206 s = set(range(10000))
207 207 p = pretty.pretty(s)
208 208 last2 = p.rsplit('\n', 2)[-2:]
209 209 self.assertEqual(last2, [' 999,', ' ...}'])
210 210
211 211 def test_long_tuple(self):
212 212 tup = tuple(range(10000))
213 213 p = pretty.pretty(tup)
214 214 last2 = p.rsplit('\n', 2)[-2:]
215 215 self.assertEqual(last2, [' 999,', ' ...)'])
216 216
217 217 def test_long_dict(self):
218 218 d = { n:n for n in range(10000) }
219 219 p = pretty.pretty(d)
220 220 last2 = p.rsplit('\n', 2)[-2:]
221 221 self.assertEqual(last2, [' 999: 999,', ' ...}'])
222 222
223 223 def test_unbound_method(self):
224 224 output = pretty.pretty(MyObj.somemethod)
225 225 self.assertIn('MyObj.somemethod', output)
226 226
227 227
228 228 class MetaClass(type):
229 229 def __new__(cls, name):
230 230 return type.__new__(cls, name, (object,), {'name': name})
231 231
232 232 def __repr__(self):
233 233 return "[CUSTOM REPR FOR CLASS %s]" % self.name
234 234
235 235
236 236 ClassWithMeta = MetaClass('ClassWithMeta')
237 237
238 238
239 239 def test_metaclass_repr():
240 240 output = pretty.pretty(ClassWithMeta)
241 241 nt.assert_equal(output, "[CUSTOM REPR FOR CLASS ClassWithMeta]")
242 242
243 243
244 244 def test_unicode_repr():
245 245 u = u"üniçodé"
246 246 ustr = u
247 247
248 248 class C(object):
249 249 def __repr__(self):
250 250 return ustr
251 251
252 252 c = C()
253 253 p = pretty.pretty(c)
254 254 nt.assert_equal(p, u)
255 255 p = pretty.pretty([c])
256 256 nt.assert_equal(p, u'[%s]' % u)
257 257
258 258
259 259 def test_basic_class():
260 260 def type_pprint_wrapper(obj, p, cycle):
261 261 if obj is MyObj:
262 262 type_pprint_wrapper.called = True
263 263 return pretty._type_pprint(obj, p, cycle)
264 264 type_pprint_wrapper.called = False
265 265
266 266 stream = StringIO()
267 267 printer = pretty.RepresentationPrinter(stream)
268 268 printer.type_pprinters[type] = type_pprint_wrapper
269 269 printer.pretty(MyObj)
270 270 printer.flush()
271 271 output = stream.getvalue()
272 272
273 273 nt.assert_equal(output, '%s.MyObj' % __name__)
274 274 nt.assert_true(type_pprint_wrapper.called)
275 275
276 276
277 277 def test_collections_defaultdict():
278 278 # Create defaultdicts with cycles
279 279 a = defaultdict()
280 280 a.default_factory = a
281 281 b = defaultdict(list)
282 282 b['key'] = b
283 283
284 284 # Dictionary order cannot be relied on, test against single keys.
285 285 cases = [
286 286 (defaultdict(list), 'defaultdict(list, {})'),
287 287 (defaultdict(list, {'key': '-' * 50}),
288 288 "defaultdict(list,\n"
289 289 " {'key': '--------------------------------------------------'})"),
290 290 (a, 'defaultdict(defaultdict(...), {})'),
291 291 (b, "defaultdict(list, {'key': defaultdict(...)})"),
292 292 ]
293 293 for obj, expected in cases:
294 294 nt.assert_equal(pretty.pretty(obj), expected)
295 295
296 296
297 297 def test_collections_ordereddict():
298 298 # Create OrderedDict with cycle
299 299 a = OrderedDict()
300 300 a['key'] = a
301 301
302 302 cases = [
303 303 (OrderedDict(), 'OrderedDict()'),
304 304 (OrderedDict((i, i) for i in range(1000, 1010)),
305 305 'OrderedDict([(1000, 1000),\n'
306 306 ' (1001, 1001),\n'
307 307 ' (1002, 1002),\n'
308 308 ' (1003, 1003),\n'
309 309 ' (1004, 1004),\n'
310 310 ' (1005, 1005),\n'
311 311 ' (1006, 1006),\n'
312 312 ' (1007, 1007),\n'
313 313 ' (1008, 1008),\n'
314 314 ' (1009, 1009)])'),
315 315 (a, "OrderedDict([('key', OrderedDict(...))])"),
316 316 ]
317 317 for obj, expected in cases:
318 318 nt.assert_equal(pretty.pretty(obj), expected)
319 319
320 320
321 321 def test_collections_deque():
322 322 # Create deque with cycle
323 323 a = deque()
324 324 a.append(a)
325 325
326 326 cases = [
327 327 (deque(), 'deque([])'),
328 328 (deque(i for i in range(1000, 1020)),
329 329 'deque([1000,\n'
330 330 ' 1001,\n'
331 331 ' 1002,\n'
332 332 ' 1003,\n'
333 333 ' 1004,\n'
334 334 ' 1005,\n'
335 335 ' 1006,\n'
336 336 ' 1007,\n'
337 337 ' 1008,\n'
338 338 ' 1009,\n'
339 339 ' 1010,\n'
340 340 ' 1011,\n'
341 341 ' 1012,\n'
342 342 ' 1013,\n'
343 343 ' 1014,\n'
344 344 ' 1015,\n'
345 345 ' 1016,\n'
346 346 ' 1017,\n'
347 347 ' 1018,\n'
348 348 ' 1019])'),
349 349 (a, 'deque([deque(...)])'),
350 350 ]
351 351 for obj, expected in cases:
352 352 nt.assert_equal(pretty.pretty(obj), expected)
353 353
354 354 def test_collections_counter():
355 355 class MyCounter(Counter):
356 356 pass
357 357 cases = [
358 358 (Counter(), 'Counter()'),
359 359 (Counter(a=1), "Counter({'a': 1})"),
360 360 (MyCounter(a=1), "MyCounter({'a': 1})"),
361 361 ]
362 362 for obj, expected in cases:
363 363 nt.assert_equal(pretty.pretty(obj), expected)
364 364
365 365 def test_mappingproxy():
366 366 MP = types.MappingProxyType
367 367 underlying_dict = {}
368 368 mp_recursive = MP(underlying_dict)
369 369 underlying_dict[2] = mp_recursive
370 370 underlying_dict[3] = underlying_dict
371 371
372 372 cases = [
373 373 (MP({}), "mappingproxy({})"),
374 374 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
375 375 (MP({k: k.upper() for k in string.ascii_lowercase}),
376 376 "mappingproxy({'a': 'A',\n"
377 377 " 'b': 'B',\n"
378 378 " 'c': 'C',\n"
379 379 " 'd': 'D',\n"
380 380 " 'e': 'E',\n"
381 381 " 'f': 'F',\n"
382 382 " 'g': 'G',\n"
383 383 " 'h': 'H',\n"
384 384 " 'i': 'I',\n"
385 385 " 'j': 'J',\n"
386 386 " 'k': 'K',\n"
387 387 " 'l': 'L',\n"
388 388 " 'm': 'M',\n"
389 389 " 'n': 'N',\n"
390 390 " 'o': 'O',\n"
391 391 " 'p': 'P',\n"
392 392 " 'q': 'Q',\n"
393 393 " 'r': 'R',\n"
394 394 " 's': 'S',\n"
395 395 " 't': 'T',\n"
396 396 " 'u': 'U',\n"
397 397 " 'v': 'V',\n"
398 398 " 'w': 'W',\n"
399 399 " 'x': 'X',\n"
400 400 " 'y': 'Y',\n"
401 401 " 'z': 'Z'})"),
402 402 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
403 403 (underlying_dict,
404 404 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
405 405 ]
406 406 for obj, expected in cases:
407 407 nt.assert_equal(pretty.pretty(obj), expected)
408 408
409 409 def test_function_pretty():
410 410 "Test pretty print of function"
411 411 # posixpath is a pure python module, its interface is consistent
412 412 # across Python distributions
413 413 import posixpath
414 414 nt.assert_equal(pretty.pretty(posixpath.join), '<function posixpath.join(a, *p)>')
415 415
416 416 # custom function
417 417 def meaning_of_life(question=None):
418 418 if question:
419 419 return 42
420 420 return "Don't panic"
421 421
422 422 nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life))
423
423
424
425 class OrderedCounter(Counter, OrderedDict):
426 'Counter that remembers the order elements are first encountered'
427
428 def __repr__(self):
429 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
430
431 def __reduce__(self):
432 return self.__class__, (OrderedDict(self),)
433
434 class MySet(set): # Override repr of a basic type
435 def __repr__(self):
436 return 'mine'
437
438 def test_custom_repr():
439 """A custom repr should override a pretty printer for a parent type"""
440 oc = OrderedCounter("abracadabra")
441 nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc))
442
443 nt.assert_equal(pretty.pretty(MySet()), 'mine')
General Comments 0
You need to be logged in to leave comments. Login now