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