##// END OF EJS Templates
Backport PR #12230: Add pretty-printing for types.SimpleNamespace
Matthias Bussonnier -
Show More
@@ -1,856 +1,873 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
81 81 from contextlib import contextmanager
82 82 import datetime
83 83 import os
84 84 import re
85 85 import sys
86 86 import types
87 87 from collections import deque
88 88 from inspect import signature
89 89 from io import StringIO
90 90 from warnings import warn
91 91
92 92 from IPython.utils.decorators import undoc
93 93 from IPython.utils.py3compat import PYPY
94 94
95 95 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
96 96 'for_type', 'for_type_by_name']
97 97
98 98
99 99 MAX_SEQ_LENGTH = 1000
100 100 _re_pattern_type = type(re.compile(''))
101 101
102 102 def _safe_getattr(obj, attr, default=None):
103 103 """Safe version of getattr.
104 104
105 105 Same as getattr, but will return ``default`` on any Exception,
106 106 rather than raising.
107 107 """
108 108 try:
109 109 return getattr(obj, attr, default)
110 110 except Exception:
111 111 return default
112 112
113 113 @undoc
114 114 class CUnicodeIO(StringIO):
115 115 def __init__(self, *args, **kwargs):
116 116 super().__init__(*args, **kwargs)
117 117 warn(("CUnicodeIO is deprecated since IPython 6.0. "
118 118 "Please use io.StringIO instead."),
119 119 DeprecationWarning, stacklevel=2)
120 120
121 121 def _sorted_for_pprint(items):
122 122 """
123 123 Sort the given items for pretty printing. Since some predictable
124 124 sorting is better than no sorting at all, we sort on the string
125 125 representation if normal sorting fails.
126 126 """
127 127 items = list(items)
128 128 try:
129 129 return sorted(items)
130 130 except Exception:
131 131 try:
132 132 return sorted(items, key=str)
133 133 except Exception:
134 134 return items
135 135
136 136 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
137 137 """
138 138 Pretty print the object's representation.
139 139 """
140 140 stream = StringIO()
141 141 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
142 142 printer.pretty(obj)
143 143 printer.flush()
144 144 return stream.getvalue()
145 145
146 146
147 147 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
148 148 """
149 149 Like `pretty` but print to stdout.
150 150 """
151 151 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
152 152 printer.pretty(obj)
153 153 printer.flush()
154 154 sys.stdout.write(newline)
155 155 sys.stdout.flush()
156 156
157 157 class _PrettyPrinterBase(object):
158 158
159 159 @contextmanager
160 160 def indent(self, indent):
161 161 """with statement support for indenting/dedenting."""
162 162 self.indentation += indent
163 163 try:
164 164 yield
165 165 finally:
166 166 self.indentation -= indent
167 167
168 168 @contextmanager
169 169 def group(self, indent=0, open='', close=''):
170 170 """like begin_group / end_group but for the with statement."""
171 171 self.begin_group(indent, open)
172 172 try:
173 173 yield
174 174 finally:
175 175 self.end_group(indent, close)
176 176
177 177 class PrettyPrinter(_PrettyPrinterBase):
178 178 """
179 179 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
180 180 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
181 181 this printer knows nothing about the default pprinters or the `_repr_pretty_`
182 182 callback method.
183 183 """
184 184
185 185 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
186 186 self.output = output
187 187 self.max_width = max_width
188 188 self.newline = newline
189 189 self.max_seq_length = max_seq_length
190 190 self.output_width = 0
191 191 self.buffer_width = 0
192 192 self.buffer = deque()
193 193
194 194 root_group = Group(0)
195 195 self.group_stack = [root_group]
196 196 self.group_queue = GroupQueue(root_group)
197 197 self.indentation = 0
198 198
199 199 def _break_one_group(self, group):
200 200 while group.breakables:
201 201 x = self.buffer.popleft()
202 202 self.output_width = x.output(self.output, self.output_width)
203 203 self.buffer_width -= x.width
204 204 while self.buffer and isinstance(self.buffer[0], Text):
205 205 x = self.buffer.popleft()
206 206 self.output_width = x.output(self.output, self.output_width)
207 207 self.buffer_width -= x.width
208 208
209 209 def _break_outer_groups(self):
210 210 while self.max_width < self.output_width + self.buffer_width:
211 211 group = self.group_queue.deq()
212 212 if not group:
213 213 return
214 214 self._break_one_group(group)
215 215
216 216 def text(self, obj):
217 217 """Add literal text to the output."""
218 218 width = len(obj)
219 219 if self.buffer:
220 220 text = self.buffer[-1]
221 221 if not isinstance(text, Text):
222 222 text = Text()
223 223 self.buffer.append(text)
224 224 text.add(obj, width)
225 225 self.buffer_width += width
226 226 self._break_outer_groups()
227 227 else:
228 228 self.output.write(obj)
229 229 self.output_width += width
230 230
231 231 def breakable(self, sep=' '):
232 232 """
233 233 Add a breakable separator to the output. This does not mean that it
234 234 will automatically break here. If no breaking on this position takes
235 235 place the `sep` is inserted which default to one space.
236 236 """
237 237 width = len(sep)
238 238 group = self.group_stack[-1]
239 239 if group.want_break:
240 240 self.flush()
241 241 self.output.write(self.newline)
242 242 self.output.write(' ' * self.indentation)
243 243 self.output_width = self.indentation
244 244 self.buffer_width = 0
245 245 else:
246 246 self.buffer.append(Breakable(sep, width, self))
247 247 self.buffer_width += width
248 248 self._break_outer_groups()
249 249
250 250 def break_(self):
251 251 """
252 252 Explicitly insert a newline into the output, maintaining correct indentation.
253 253 """
254 254 group = self.group_queue.deq()
255 255 if group:
256 256 self._break_one_group(group)
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
263 263
264 264 def begin_group(self, indent=0, open=''):
265 265 """
266 266 Begin a group.
267 267 The first parameter specifies the indentation for the next line (usually
268 268 the width of the opening text), the second the opening text. All
269 269 parameters are optional.
270 270 """
271 271 if open:
272 272 self.text(open)
273 273 group = Group(self.group_stack[-1].depth + 1)
274 274 self.group_stack.append(group)
275 275 self.group_queue.enq(group)
276 276 self.indentation += indent
277 277
278 278 def _enumerate(self, seq):
279 279 """like enumerate, but with an upper limit on the number of items"""
280 280 for idx, x in enumerate(seq):
281 281 if self.max_seq_length and idx >= self.max_seq_length:
282 282 self.text(',')
283 283 self.breakable()
284 284 self.text('...')
285 285 return
286 286 yield idx, x
287 287
288 288 def end_group(self, dedent=0, close=''):
289 289 """End a group. See `begin_group` for more details."""
290 290 self.indentation -= dedent
291 291 group = self.group_stack.pop()
292 292 if not group.breakables:
293 293 self.group_queue.remove(group)
294 294 if close:
295 295 self.text(close)
296 296
297 297 def flush(self):
298 298 """Flush data that is left in the buffer."""
299 299 for data in self.buffer:
300 300 self.output_width += data.output(self.output, self.output_width)
301 301 self.buffer.clear()
302 302 self.buffer_width = 0
303 303
304 304
305 305 def _get_mro(obj_class):
306 306 """ Get a reasonable method resolution order of a class and its superclasses
307 307 for both old-style and new-style classes.
308 308 """
309 309 if not hasattr(obj_class, '__mro__'):
310 310 # Old-style class. Mix in object to make a fake new-style class.
311 311 try:
312 312 obj_class = type(obj_class.__name__, (obj_class, object), {})
313 313 except TypeError:
314 314 # Old-style extension type that does not descend from object.
315 315 # FIXME: try to construct a more thorough MRO.
316 316 mro = [obj_class]
317 317 else:
318 318 mro = obj_class.__mro__[1:-1]
319 319 else:
320 320 mro = obj_class.__mro__
321 321 return mro
322 322
323 323
324 324 class RepresentationPrinter(PrettyPrinter):
325 325 """
326 326 Special pretty printer that has a `pretty` method that calls the pretty
327 327 printer for a python object.
328 328
329 329 This class stores processing data on `self` so you must *never* use
330 330 this class in a threaded environment. Always lock it or reinstanciate
331 331 it.
332 332
333 333 Instances also have a verbose flag callbacks can access to control their
334 334 output. For example the default instance repr prints all attributes and
335 335 methods that are not prefixed by an underscore if the printer is in
336 336 verbose mode.
337 337 """
338 338
339 339 def __init__(self, output, verbose=False, max_width=79, newline='\n',
340 340 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
341 341 max_seq_length=MAX_SEQ_LENGTH):
342 342
343 343 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
344 344 self.verbose = verbose
345 345 self.stack = []
346 346 if singleton_pprinters is None:
347 347 singleton_pprinters = _singleton_pprinters.copy()
348 348 self.singleton_pprinters = singleton_pprinters
349 349 if type_pprinters is None:
350 350 type_pprinters = _type_pprinters.copy()
351 351 self.type_pprinters = type_pprinters
352 352 if deferred_pprinters is None:
353 353 deferred_pprinters = _deferred_type_pprinters.copy()
354 354 self.deferred_pprinters = deferred_pprinters
355 355
356 356 def pretty(self, obj):
357 357 """Pretty print the given object."""
358 358 obj_id = id(obj)
359 359 cycle = obj_id in self.stack
360 360 self.stack.append(obj_id)
361 361 self.begin_group()
362 362 try:
363 363 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
364 364 # First try to find registered singleton printers for the type.
365 365 try:
366 366 printer = self.singleton_pprinters[obj_id]
367 367 except (TypeError, KeyError):
368 368 pass
369 369 else:
370 370 return printer(obj, self, cycle)
371 371 # Next walk the mro and check for either:
372 372 # 1) a registered printer
373 373 # 2) a _repr_pretty_ method
374 374 for cls in _get_mro(obj_class):
375 375 if cls in self.type_pprinters:
376 376 # printer registered in self.type_pprinters
377 377 return self.type_pprinters[cls](obj, self, cycle)
378 378 else:
379 379 # deferred printer
380 380 printer = self._in_deferred_types(cls)
381 381 if printer is not None:
382 382 return printer(obj, self, cycle)
383 383 else:
384 384 # Finally look for special method names.
385 385 # Some objects automatically create any requested
386 386 # attribute. Try to ignore most of them by checking for
387 387 # callability.
388 388 if '_repr_pretty_' in cls.__dict__:
389 389 meth = cls._repr_pretty_
390 390 if callable(meth):
391 391 return meth(obj, self, cycle)
392 392 if cls is not object \
393 393 and callable(cls.__dict__.get('__repr__')):
394 394 return _repr_pprint(obj, self, cycle)
395 395
396 396 return _default_pprint(obj, self, cycle)
397 397 finally:
398 398 self.end_group()
399 399 self.stack.pop()
400 400
401 401 def _in_deferred_types(self, cls):
402 402 """
403 403 Check if the given class is specified in the deferred type registry.
404 404
405 405 Returns the printer from the registry if it exists, and None if the
406 406 class is not in the registry. Successful matches will be moved to the
407 407 regular type registry for future use.
408 408 """
409 409 mod = _safe_getattr(cls, '__module__', None)
410 410 name = _safe_getattr(cls, '__name__', None)
411 411 key = (mod, name)
412 412 printer = None
413 413 if key in self.deferred_pprinters:
414 414 # Move the printer over to the regular registry.
415 415 printer = self.deferred_pprinters.pop(key)
416 416 self.type_pprinters[cls] = printer
417 417 return printer
418 418
419 419
420 420 class Printable(object):
421 421
422 422 def output(self, stream, output_width):
423 423 return output_width
424 424
425 425
426 426 class Text(Printable):
427 427
428 428 def __init__(self):
429 429 self.objs = []
430 430 self.width = 0
431 431
432 432 def output(self, stream, output_width):
433 433 for obj in self.objs:
434 434 stream.write(obj)
435 435 return output_width + self.width
436 436
437 437 def add(self, obj, width):
438 438 self.objs.append(obj)
439 439 self.width += width
440 440
441 441
442 442 class Breakable(Printable):
443 443
444 444 def __init__(self, seq, width, pretty):
445 445 self.obj = seq
446 446 self.width = width
447 447 self.pretty = pretty
448 448 self.indentation = pretty.indentation
449 449 self.group = pretty.group_stack[-1]
450 450 self.group.breakables.append(self)
451 451
452 452 def output(self, stream, output_width):
453 453 self.group.breakables.popleft()
454 454 if self.group.want_break:
455 455 stream.write(self.pretty.newline)
456 456 stream.write(' ' * self.indentation)
457 457 return self.indentation
458 458 if not self.group.breakables:
459 459 self.pretty.group_queue.remove(self.group)
460 460 stream.write(self.obj)
461 461 return output_width + self.width
462 462
463 463
464 464 class Group(Printable):
465 465
466 466 def __init__(self, depth):
467 467 self.depth = depth
468 468 self.breakables = deque()
469 469 self.want_break = False
470 470
471 471
472 472 class GroupQueue(object):
473 473
474 474 def __init__(self, *groups):
475 475 self.queue = []
476 476 for group in groups:
477 477 self.enq(group)
478 478
479 479 def enq(self, group):
480 480 depth = group.depth
481 481 while depth > len(self.queue) - 1:
482 482 self.queue.append([])
483 483 self.queue[depth].append(group)
484 484
485 485 def deq(self):
486 486 for stack in self.queue:
487 487 for idx, group in enumerate(reversed(stack)):
488 488 if group.breakables:
489 489 del stack[idx]
490 490 group.want_break = True
491 491 return group
492 492 for group in stack:
493 493 group.want_break = True
494 494 del stack[:]
495 495
496 496 def remove(self, group):
497 497 try:
498 498 self.queue[group.depth].remove(group)
499 499 except ValueError:
500 500 pass
501 501
502 502
503 503 def _default_pprint(obj, p, cycle):
504 504 """
505 505 The default print function. Used if an object does not provide one and
506 506 it's none of the builtin objects.
507 507 """
508 508 klass = _safe_getattr(obj, '__class__', None) or type(obj)
509 509 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
510 510 # A user-provided repr. Find newlines and replace them with p.break_()
511 511 _repr_pprint(obj, p, cycle)
512 512 return
513 513 p.begin_group(1, '<')
514 514 p.pretty(klass)
515 515 p.text(' at 0x%x' % id(obj))
516 516 if cycle:
517 517 p.text(' ...')
518 518 elif p.verbose:
519 519 first = True
520 520 for key in dir(obj):
521 521 if not key.startswith('_'):
522 522 try:
523 523 value = getattr(obj, key)
524 524 except AttributeError:
525 525 continue
526 526 if isinstance(value, types.MethodType):
527 527 continue
528 528 if not first:
529 529 p.text(',')
530 530 p.breakable()
531 531 p.text(key)
532 532 p.text('=')
533 533 step = len(key) + 1
534 534 p.indentation += step
535 535 p.pretty(value)
536 536 p.indentation -= step
537 537 first = False
538 538 p.end_group(1, '>')
539 539
540 540
541 541 def _seq_pprinter_factory(start, end):
542 542 """
543 543 Factory that returns a pprint function useful for sequences. Used by
544 544 the default pprint for tuples, dicts, and lists.
545 545 """
546 546 def inner(obj, p, cycle):
547 547 if cycle:
548 548 return p.text(start + '...' + end)
549 549 step = len(start)
550 550 p.begin_group(step, start)
551 551 for idx, x in p._enumerate(obj):
552 552 if idx:
553 553 p.text(',')
554 554 p.breakable()
555 555 p.pretty(x)
556 556 if len(obj) == 1 and type(obj) is tuple:
557 557 # Special case for 1-item tuples.
558 558 p.text(',')
559 559 p.end_group(step, end)
560 560 return inner
561 561
562 562
563 563 def _set_pprinter_factory(start, end):
564 564 """
565 565 Factory that returns a pprint function useful for sets and frozensets.
566 566 """
567 567 def inner(obj, p, cycle):
568 568 if cycle:
569 569 return p.text(start + '...' + end)
570 570 if len(obj) == 0:
571 571 # Special case.
572 572 p.text(type(obj).__name__ + '()')
573 573 else:
574 574 step = len(start)
575 575 p.begin_group(step, start)
576 576 # Like dictionary keys, we will try to sort the items if there aren't too many
577 577 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
578 578 items = _sorted_for_pprint(obj)
579 579 else:
580 580 items = obj
581 581 for idx, x in p._enumerate(items):
582 582 if idx:
583 583 p.text(',')
584 584 p.breakable()
585 585 p.pretty(x)
586 586 p.end_group(step, end)
587 587 return inner
588 588
589 589
590 590 def _dict_pprinter_factory(start, end):
591 591 """
592 592 Factory that returns a pprint function used by the default pprint of
593 593 dicts and dict proxies.
594 594 """
595 595 def inner(obj, p, cycle):
596 596 if cycle:
597 597 return p.text('{...}')
598 598 step = len(start)
599 599 p.begin_group(step, start)
600 600 keys = obj.keys()
601 601 for idx, key in p._enumerate(keys):
602 602 if idx:
603 603 p.text(',')
604 604 p.breakable()
605 605 p.pretty(key)
606 606 p.text(': ')
607 607 p.pretty(obj[key])
608 608 p.end_group(step, end)
609 609 return inner
610 610
611 611
612 612 def _super_pprint(obj, p, cycle):
613 613 """The pprint for the super type."""
614 614 p.begin_group(8, '<super: ')
615 615 p.pretty(obj.__thisclass__)
616 616 p.text(',')
617 617 p.breakable()
618 618 if PYPY: # In PyPy, super() objects don't have __self__ attributes
619 619 dself = obj.__repr__.__self__
620 620 p.pretty(None if dself is obj else dself)
621 621 else:
622 622 p.pretty(obj.__self__)
623 623 p.end_group(8, '>')
624 624
625 625
626 626 def _re_pattern_pprint(obj, p, cycle):
627 627 """The pprint function for regular expression patterns."""
628 628 p.text('re.compile(')
629 629 pattern = repr(obj.pattern)
630 630 if pattern[:1] in 'uU':
631 631 pattern = pattern[1:]
632 632 prefix = 'ur'
633 633 else:
634 634 prefix = 'r'
635 635 pattern = prefix + pattern.replace('\\\\', '\\')
636 636 p.text(pattern)
637 637 if obj.flags:
638 638 p.text(',')
639 639 p.breakable()
640 640 done_one = False
641 641 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
642 642 'UNICODE', 'VERBOSE', 'DEBUG'):
643 643 if obj.flags & getattr(re, flag):
644 644 if done_one:
645 645 p.text('|')
646 646 p.text('re.' + flag)
647 647 done_one = True
648 648 p.text(')')
649 649
650 650
651 def _types_simplenamespace_pprint(obj, p, cycle):
652 """The pprint function for types.SimpleNamespace."""
653 name = 'namespace'
654 with p.group(len(name) + 1, name + '(', ')'):
655 if cycle:
656 p.text('...')
657 else:
658 for idx, (attr, value) in enumerate(obj.__dict__.items()):
659 if idx:
660 p.text(',')
661 p.breakable()
662 attr_kwarg = '{}='.format(attr)
663 with p.group(len(attr_kwarg), attr_kwarg):
664 p.pretty(value)
665
666
651 667 def _type_pprint(obj, p, cycle):
652 668 """The pprint for classes and types."""
653 669 # Heap allocated types might not have the module attribute,
654 670 # and others may set it to None.
655 671
656 672 # Checks for a __repr__ override in the metaclass. Can't compare the
657 673 # type(obj).__repr__ directly because in PyPy the representation function
658 674 # inherited from type isn't the same type.__repr__
659 675 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
660 676 _repr_pprint(obj, p, cycle)
661 677 return
662 678
663 679 mod = _safe_getattr(obj, '__module__', None)
664 680 try:
665 681 name = obj.__qualname__
666 682 if not isinstance(name, str):
667 683 # This can happen if the type implements __qualname__ as a property
668 684 # or other descriptor in Python 2.
669 685 raise Exception("Try __name__")
670 686 except Exception:
671 687 name = obj.__name__
672 688 if not isinstance(name, str):
673 689 name = '<unknown type>'
674 690
675 691 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
676 692 p.text(name)
677 693 else:
678 694 p.text(mod + '.' + name)
679 695
680 696
681 697 def _repr_pprint(obj, p, cycle):
682 698 """A pprint that just redirects to the normal repr function."""
683 699 # Find newlines and replace them with p.break_()
684 700 output = repr(obj)
685 701 lines = output.splitlines()
686 702 with p.group():
687 703 for idx, output_line in enumerate(lines):
688 704 if idx:
689 705 p.break_()
690 706 p.text(output_line)
691 707
692 708
693 709 def _function_pprint(obj, p, cycle):
694 710 """Base pprint for all functions and builtin functions."""
695 711 name = _safe_getattr(obj, '__qualname__', obj.__name__)
696 712 mod = obj.__module__
697 713 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
698 714 name = mod + '.' + name
699 715 try:
700 716 func_def = name + str(signature(obj))
701 717 except ValueError:
702 718 func_def = name
703 719 p.text('<function %s>' % func_def)
704 720
705 721
706 722 def _exception_pprint(obj, p, cycle):
707 723 """Base pprint for all exceptions."""
708 724 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
709 725 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
710 726 name = '%s.%s' % (obj.__class__.__module__, name)
711 727 step = len(name) + 1
712 728 p.begin_group(step, name + '(')
713 729 for idx, arg in enumerate(getattr(obj, 'args', ())):
714 730 if idx:
715 731 p.text(',')
716 732 p.breakable()
717 733 p.pretty(arg)
718 734 p.end_group(step, ')')
719 735
720 736
721 737 #: the exception base
722 738 try:
723 739 _exception_base = BaseException
724 740 except NameError:
725 741 _exception_base = Exception
726 742
727 743
728 744 #: printers for builtin types
729 745 _type_pprinters = {
730 746 int: _repr_pprint,
731 747 float: _repr_pprint,
732 748 str: _repr_pprint,
733 749 tuple: _seq_pprinter_factory('(', ')'),
734 750 list: _seq_pprinter_factory('[', ']'),
735 751 dict: _dict_pprinter_factory('{', '}'),
736 752 set: _set_pprinter_factory('{', '}'),
737 753 frozenset: _set_pprinter_factory('frozenset({', '})'),
738 754 super: _super_pprint,
739 755 _re_pattern_type: _re_pattern_pprint,
740 756 type: _type_pprint,
741 757 types.FunctionType: _function_pprint,
742 758 types.BuiltinFunctionType: _function_pprint,
743 759 types.MethodType: _repr_pprint,
760 types.SimpleNamespace: _types_simplenamespace_pprint,
744 761 datetime.datetime: _repr_pprint,
745 762 datetime.timedelta: _repr_pprint,
746 763 _exception_base: _exception_pprint
747 764 }
748 765
749 766 # render os.environ like a dict
750 767 _env_type = type(os.environ)
751 768 # future-proof in case os.environ becomes a plain dict?
752 769 if _env_type is not dict:
753 770 _type_pprinters[_env_type] = _dict_pprinter_factory('environ{', '}')
754 771
755 772 try:
756 773 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
757 774 # using dict.setdefault avoids overwriting the dict printer
758 775 _type_pprinters.setdefault(types.DictProxyType,
759 776 _dict_pprinter_factory('dict_proxy({', '})'))
760 777 _type_pprinters[types.ClassType] = _type_pprint
761 778 _type_pprinters[types.SliceType] = _repr_pprint
762 779 except AttributeError: # Python 3
763 780 _type_pprinters[types.MappingProxyType] = \
764 781 _dict_pprinter_factory('mappingproxy({', '})')
765 782 _type_pprinters[slice] = _repr_pprint
766 783
767 784 _type_pprinters[range] = _repr_pprint
768 785 _type_pprinters[bytes] = _repr_pprint
769 786
770 787 #: printers for types specified by name
771 788 _deferred_type_pprinters = {
772 789 }
773 790
774 791 def for_type(typ, func):
775 792 """
776 793 Add a pretty printer for a given type.
777 794 """
778 795 oldfunc = _type_pprinters.get(typ, None)
779 796 if func is not None:
780 797 # To support easy restoration of old pprinters, we need to ignore Nones.
781 798 _type_pprinters[typ] = func
782 799 return oldfunc
783 800
784 801 def for_type_by_name(type_module, type_name, func):
785 802 """
786 803 Add a pretty printer for a type specified by the module and name of a type
787 804 rather than the type object itself.
788 805 """
789 806 key = (type_module, type_name)
790 807 oldfunc = _deferred_type_pprinters.get(key, None)
791 808 if func is not None:
792 809 # To support easy restoration of old pprinters, we need to ignore Nones.
793 810 _deferred_type_pprinters[key] = func
794 811 return oldfunc
795 812
796 813
797 814 #: printers for the default singletons
798 815 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
799 816 NotImplemented]), _repr_pprint)
800 817
801 818
802 819 def _defaultdict_pprint(obj, p, cycle):
803 820 name = obj.__class__.__name__
804 821 with p.group(len(name) + 1, name + '(', ')'):
805 822 if cycle:
806 823 p.text('...')
807 824 else:
808 825 p.pretty(obj.default_factory)
809 826 p.text(',')
810 827 p.breakable()
811 828 p.pretty(dict(obj))
812 829
813 830 def _ordereddict_pprint(obj, p, cycle):
814 831 name = obj.__class__.__name__
815 832 with p.group(len(name) + 1, name + '(', ')'):
816 833 if cycle:
817 834 p.text('...')
818 835 elif len(obj):
819 836 p.pretty(list(obj.items()))
820 837
821 838 def _deque_pprint(obj, p, cycle):
822 839 name = obj.__class__.__name__
823 840 with p.group(len(name) + 1, name + '(', ')'):
824 841 if cycle:
825 842 p.text('...')
826 843 else:
827 844 p.pretty(list(obj))
828 845
829 846
830 847 def _counter_pprint(obj, p, cycle):
831 848 name = obj.__class__.__name__
832 849 with p.group(len(name) + 1, name + '(', ')'):
833 850 if cycle:
834 851 p.text('...')
835 852 elif len(obj):
836 853 p.pretty(dict(obj))
837 854
838 855 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
839 856 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
840 857 for_type_by_name('collections', 'deque', _deque_pprint)
841 858 for_type_by_name('collections', 'Counter', _counter_pprint)
842 859
843 860 if __name__ == '__main__':
844 861 from random import randrange
845 862 class Foo(object):
846 863 def __init__(self):
847 864 self.foo = 1
848 865 self.bar = re.compile(r'\s+')
849 866 self.blub = dict.fromkeys(range(30), randrange(1, 40))
850 867 self.hehe = 23424.234234
851 868 self.list = ["blub", "blah", self]
852 869
853 870 def get_foo(self):
854 871 print("foo")
855 872
856 873 pprint(Foo(), verbose=True)
@@ -1,452 +1,472 b''
1 1 # coding: utf-8
2 2 """Tests for IPython.lib.pretty."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from collections import Counter, defaultdict, deque, OrderedDict
9 9 import os
10 10 import types
11 11 import string
12 12 import unittest
13 13
14 14 import nose.tools as nt
15 15
16 16 from IPython.lib import pretty
17 17 from IPython.testing.decorators import skip_without
18 18
19 19 from io import StringIO
20 20
21 21
22 22 class MyList(object):
23 23 def __init__(self, content):
24 24 self.content = content
25 25 def _repr_pretty_(self, p, cycle):
26 26 if cycle:
27 27 p.text("MyList(...)")
28 28 else:
29 29 with p.group(3, "MyList(", ")"):
30 30 for (i, child) in enumerate(self.content):
31 31 if i:
32 32 p.text(",")
33 33 p.breakable()
34 34 else:
35 35 p.breakable("")
36 36 p.pretty(child)
37 37
38 38
39 39 class MyDict(dict):
40 40 def _repr_pretty_(self, p, cycle):
41 41 p.text("MyDict(...)")
42 42
43 43 class MyObj(object):
44 44 def somemethod(self):
45 45 pass
46 46
47 47
48 48 class Dummy1(object):
49 49 def _repr_pretty_(self, p, cycle):
50 50 p.text("Dummy1(...)")
51 51
52 52 class Dummy2(Dummy1):
53 53 _repr_pretty_ = None
54 54
55 55 class NoModule(object):
56 56 pass
57 57
58 58 NoModule.__module__ = None
59 59
60 60 class Breaking(object):
61 61 def _repr_pretty_(self, p, cycle):
62 62 with p.group(4,"TG: ",":"):
63 63 p.text("Breaking(")
64 64 p.break_()
65 65 p.text(")")
66 66
67 67 class BreakingRepr(object):
68 68 def __repr__(self):
69 69 return "Breaking(\n)"
70 70
71 71 class BadRepr(object):
72 72
73 73 def __repr__(self):
74 74 return 1/0
75 75
76 76
77 77 def test_indentation():
78 78 """Test correct indentation in groups"""
79 79 count = 40
80 80 gotoutput = pretty.pretty(MyList(range(count)))
81 81 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
82 82
83 83 nt.assert_equal(gotoutput, expectedoutput)
84 84
85 85
86 86 def test_dispatch():
87 87 """
88 88 Test correct dispatching: The _repr_pretty_ method for MyDict
89 89 must be found before the registered printer for dict.
90 90 """
91 91 gotoutput = pretty.pretty(MyDict())
92 92 expectedoutput = "MyDict(...)"
93 93
94 94 nt.assert_equal(gotoutput, expectedoutput)
95 95
96 96
97 97 def test_callability_checking():
98 98 """
99 99 Test that the _repr_pretty_ method is tested for callability and skipped if
100 100 not.
101 101 """
102 102 gotoutput = pretty.pretty(Dummy2())
103 103 expectedoutput = "Dummy1(...)"
104 104
105 105 nt.assert_equal(gotoutput, expectedoutput)
106 106
107 107
108 108 def test_sets():
109 109 """
110 110 Test that set and frozenset use Python 3 formatting.
111 111 """
112 112 objects = [set(), frozenset(), set([1]), frozenset([1]), set([1, 2]),
113 113 frozenset([1, 2]), set([-1, -2, -3])]
114 114 expected = ['set()', 'frozenset()', '{1}', 'frozenset({1})', '{1, 2}',
115 115 'frozenset({1, 2})', '{-3, -2, -1}']
116 116 for obj, expected_output in zip(objects, expected):
117 117 got_output = pretty.pretty(obj)
118 118 yield nt.assert_equal, got_output, expected_output
119 119
120 120
121 121 @skip_without('xxlimited')
122 122 def test_pprint_heap_allocated_type():
123 123 """
124 124 Test that pprint works for heap allocated types.
125 125 """
126 126 import xxlimited
127 127 output = pretty.pretty(xxlimited.Null)
128 128 nt.assert_equal(output, 'xxlimited.Null')
129 129
130 130 def test_pprint_nomod():
131 131 """
132 132 Test that pprint works for classes with no __module__.
133 133 """
134 134 output = pretty.pretty(NoModule)
135 135 nt.assert_equal(output, 'NoModule')
136 136
137 137 def test_pprint_break():
138 138 """
139 139 Test that p.break_ produces expected output
140 140 """
141 141 output = pretty.pretty(Breaking())
142 142 expected = "TG: Breaking(\n ):"
143 143 nt.assert_equal(output, expected)
144 144
145 145 def test_pprint_break_repr():
146 146 """
147 147 Test that p.break_ is used in repr
148 148 """
149 149 output = pretty.pretty([[BreakingRepr()]])
150 150 expected = "[[Breaking(\n )]]"
151 151 nt.assert_equal(output, expected)
152 152
153 153 output = pretty.pretty([[BreakingRepr()]*2])
154 154 expected = "[[Breaking(\n ),\n 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
410 def test_simplenamespace():
411 SN = types.SimpleNamespace
412
413 sn_recursive = SN()
414 sn_recursive.first = sn_recursive
415 sn_recursive.second = sn_recursive
416 cases = [
417 (SN(), "namespace()"),
418 (SN(x=SN()), "namespace(x=namespace())"),
419 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
420 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
421 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
422 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
423 " a_short_name=None)"),
424 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
425 ]
426 for obj, expected in cases:
427 nt.assert_equal(pretty.pretty(obj), expected)
428
429
410 430 def test_pretty_environ():
411 431 dict_repr = pretty.pretty(dict(os.environ))
412 432 # reindent to align with 'environ' prefix
413 433 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
414 434 env_repr = pretty.pretty(os.environ)
415 435 nt.assert_equal(env_repr, 'environ' + dict_indented)
416 436
417 437
418 438 def test_function_pretty():
419 439 "Test pretty print of function"
420 440 # posixpath is a pure python module, its interface is consistent
421 441 # across Python distributions
422 442 import posixpath
423 443 nt.assert_equal(pretty.pretty(posixpath.join), '<function posixpath.join(a, *p)>')
424 444
425 445 # custom function
426 446 def meaning_of_life(question=None):
427 447 if question:
428 448 return 42
429 449 return "Don't panic"
430 450
431 451 nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life))
432 452
433 453
434 454 class OrderedCounter(Counter, OrderedDict):
435 455 'Counter that remembers the order elements are first encountered'
436 456
437 457 def __repr__(self):
438 458 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
439 459
440 460 def __reduce__(self):
441 461 return self.__class__, (OrderedDict(self),)
442 462
443 463 class MySet(set): # Override repr of a basic type
444 464 def __repr__(self):
445 465 return 'mine'
446 466
447 467 def test_custom_repr():
448 468 """A custom repr should override a pretty printer for a parent type"""
449 469 oc = OrderedCounter("abracadabra")
450 470 nt.assert_in("OrderedCounter(OrderedDict", pretty.pretty(oc))
451 471
452 472 nt.assert_equal(pretty.pretty(MySet()), 'mine')
General Comments 0
You need to be logged in to leave comments. Login now