##// END OF EJS Templates
Fix dispatching in the pretty printing module....
Walter Doerwald -
Show More
@@ -1,728 +1,732 b''
1 1 # -*- coding: utf-8 -*-
2 2 """
3 3 pretty
4 4 ~~
5 5
6 6 Python advanced pretty printer. This pretty printer is intended to
7 7 replace the old `pprint` python module which does not allow developers
8 8 to provide their own pretty print callbacks.
9 9
10 10 This module is based on ruby's `prettyprint.rb` library by `Tanaka Akira`.
11 11
12 12
13 13 Example Usage
14 14 =============
15 15
16 16 To directly print the representation of an object use `pprint`::
17 17
18 18 from pretty import pprint
19 19 pprint(complex_object)
20 20
21 21 To get a string of the output use `pretty`::
22 22
23 23 from pretty import pretty
24 24 string = pretty(complex_object)
25 25
26 26
27 27 Extending
28 28 =========
29 29
30 30 The pretty library allows developers to add pretty printing rules for their
31 31 own objects. This process is straightforward. All you have to do is to
32 32 add a `_repr_pretty_` method to your object and call the methods on the
33 33 pretty printer passed::
34 34
35 35 class MyObject(object):
36 36
37 37 def _repr_pretty_(self, p, cycle):
38 38 ...
39 39
40 40 Depending on the python version you want to support you have two
41 41 possibilities. The following list shows the python 2.5 version and the
42 42 compatibility one.
43 43
44 44
45 45 Here the example implementation of a `_repr_pretty_` method for a list
46 46 subclass for python 2.5 and higher (python 2.5 requires the with statement
47 47 __future__ import)::
48 48
49 49 class MyList(list):
50 50
51 51 def _repr_pretty_(self, p, cycle):
52 52 if cycle:
53 53 p.text('MyList(...)')
54 54 else:
55 55 with p.group(8, 'MyList([', '])'):
56 56 for idx, item in enumerate(self):
57 57 if idx:
58 58 p.text(',')
59 59 p.breakable()
60 60 p.pretty(item)
61 61
62 62 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
63 63 react to that or the result is an infinite loop. `p.text()` just adds
64 64 non breaking text to the output, `p.breakable()` either adds a whitespace
65 65 or breaks here. If you pass it an argument it's used instead of the
66 66 default space. `p.pretty` prettyprints another object using the pretty print
67 67 method.
68 68
69 69 The first parameter to the `group` function specifies the extra indentation
70 70 of the next line. In this example the next item will either be not
71 71 breaked (if the items are short enough) or aligned with the right edge of
72 72 the opening bracked of `MyList`.
73 73
74 74 If you want to support python 2.4 and lower you can use this code::
75 75
76 76 class MyList(list):
77 77
78 78 def _repr_pretty_(self, p, cycle):
79 79 if cycle:
80 80 p.text('MyList(...)')
81 81 else:
82 82 p.begin_group(8, 'MyList([')
83 83 for idx, item in enumerate(self):
84 84 if idx:
85 85 p.text(',')
86 86 p.breakable()
87 87 p.pretty(item)
88 88 p.end_group(8, '])')
89 89
90 90 If you just want to indent something you can use the group function
91 91 without open / close parameters. Under python 2.5 you can also use this
92 92 code::
93 93
94 94 with p.indent(2):
95 95 ...
96 96
97 97 Or under python2.4 you might want to modify ``p.indentation`` by hand but
98 98 this is rather ugly.
99 99
100 100 :copyright: 2007 by Armin Ronacher.
101 101 Portions (c) 2009 by Robert Kern.
102 102 :license: BSD License.
103 103 """
104 104 from __future__ import with_statement
105 105 from contextlib import contextmanager
106 106 import sys
107 107 import types
108 108 import re
109 109 import datetime
110 110 from StringIO import StringIO
111 111 from collections import deque
112 112
113 113
114 114 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
115 115 'for_type', 'for_type_by_name']
116 116
117 117
118 118 _re_pattern_type = type(re.compile(''))
119 119
120 120
121 121 def pretty(obj, verbose=False, max_width=79, newline='\n'):
122 122 """
123 123 Pretty print the object's representation.
124 124 """
125 125 stream = StringIO()
126 126 printer = RepresentationPrinter(stream, verbose, max_width, newline)
127 127 printer.pretty(obj)
128 128 printer.flush()
129 129 return stream.getvalue()
130 130
131 131
132 132 def pprint(obj, verbose=False, max_width=79, newline='\n'):
133 133 """
134 134 Like `pretty` but print to stdout.
135 135 """
136 136 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline)
137 137 printer.pretty(obj)
138 138 printer.flush()
139 139 sys.stdout.write(newline)
140 140 sys.stdout.flush()
141 141
142 142 class _PrettyPrinterBase(object):
143 143
144 144 @contextmanager
145 145 def indent(self, indent):
146 146 """with statement support for indenting/dedenting."""
147 147 self.indentation += indent
148 148 try:
149 149 yield
150 150 finally:
151 151 self.indentation -= indent
152 152
153 153 @contextmanager
154 154 def group(self, indent=0, open='', close=''):
155 155 """like begin_group / end_group but for the with statement."""
156 156 self.begin_group(indent, open)
157 157 try:
158 158 yield
159 159 finally:
160 160 self.end_group(indent, close)
161 161
162 162 class PrettyPrinter(_PrettyPrinterBase):
163 163 """
164 164 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
165 165 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
166 166 this printer knows nothing about the default pprinters or the `_repr_pretty_`
167 167 callback method.
168 168 """
169 169
170 170 def __init__(self, output, max_width=79, newline='\n'):
171 171 self.output = output
172 172 self.max_width = max_width
173 173 self.newline = newline
174 174 self.output_width = 0
175 175 self.buffer_width = 0
176 176 self.buffer = deque()
177 177
178 178 root_group = Group(0)
179 179 self.group_stack = [root_group]
180 180 self.group_queue = GroupQueue(root_group)
181 181 self.indentation = 0
182 182
183 183 def _break_outer_groups(self):
184 184 while self.max_width < self.output_width + self.buffer_width:
185 185 group = self.group_queue.deq()
186 186 if not group:
187 187 return
188 188 while group.breakables:
189 189 x = self.buffer.popleft()
190 190 self.output_width = x.output(self.output, self.output_width)
191 191 self.buffer_width -= x.width
192 192 while self.buffer and isinstance(self.buffer[0], Text):
193 193 x = self.buffer.popleft()
194 194 self.output_width = x.output(self.output, self.output_width)
195 195 self.buffer_width -= x.width
196 196
197 197 def text(self, obj):
198 198 """Add literal text to the output."""
199 199 width = len(obj)
200 200 if self.buffer:
201 201 text = self.buffer[-1]
202 202 if not isinstance(text, Text):
203 203 text = Text()
204 204 self.buffer.append(text)
205 205 text.add(obj, width)
206 206 self.buffer_width += width
207 207 self._break_outer_groups()
208 208 else:
209 209 self.output.write(obj)
210 210 self.output_width += width
211 211
212 212 def breakable(self, sep=' '):
213 213 """
214 214 Add a breakable separator to the output. This does not mean that it
215 215 will automatically break here. If no breaking on this position takes
216 216 place the `sep` is inserted which default to one space.
217 217 """
218 218 width = len(sep)
219 219 group = self.group_stack[-1]
220 220 if group.want_break:
221 221 self.flush()
222 222 self.output.write(self.newline)
223 223 self.output.write(' ' * self.indentation)
224 224 self.output_width = self.indentation
225 225 self.buffer_width = 0
226 226 else:
227 227 self.buffer.append(Breakable(sep, width, self))
228 228 self.buffer_width += width
229 229 self._break_outer_groups()
230 230
231 231
232 232 def begin_group(self, indent=0, open=''):
233 233 """
234 234 Begin a group. If you want support for python < 2.5 which doesn't has
235 235 the with statement this is the preferred way:
236 236
237 237 p.begin_group(1, '{')
238 238 ...
239 239 p.end_group(1, '}')
240 240
241 241 The python 2.5 expression would be this:
242 242
243 243 with p.group(1, '{', '}'):
244 244 ...
245 245
246 246 The first parameter specifies the indentation for the next line (usually
247 247 the width of the opening text), the second the opening text. All
248 248 parameters are optional.
249 249 """
250 250 if open:
251 251 self.text(open)
252 252 group = Group(self.group_stack[-1].depth + 1)
253 253 self.group_stack.append(group)
254 254 self.group_queue.enq(group)
255 255 self.indentation += indent
256 256
257 257 def end_group(self, dedent=0, close=''):
258 258 """End a group. See `begin_group` for more details."""
259 259 self.indentation -= dedent
260 260 group = self.group_stack.pop()
261 261 if not group.breakables:
262 262 self.group_queue.remove(group)
263 263 if close:
264 264 self.text(close)
265 265
266 266 def flush(self):
267 267 """Flush data that is left in the buffer."""
268 268 for data in self.buffer:
269 269 self.output_width += data.output(self.output, self.output_width)
270 270 self.buffer.clear()
271 271 self.buffer_width = 0
272 272
273 273
274 274 def _get_mro(obj_class):
275 275 """ Get a reasonable method resolution order of a class and its superclasses
276 276 for both old-style and new-style classes.
277 277 """
278 278 if not hasattr(obj_class, '__mro__'):
279 279 # Old-style class. Mix in object to make a fake new-style class.
280 280 try:
281 281 obj_class = type(obj_class.__name__, (obj_class, object), {})
282 282 except TypeError:
283 283 # Old-style extension type that does not descend from object.
284 284 # FIXME: try to construct a more thorough MRO.
285 285 mro = [obj_class]
286 286 else:
287 287 mro = obj_class.__mro__[1:-1]
288 288 else:
289 289 mro = obj_class.__mro__
290 290 return mro
291 291
292 292
293 293 class RepresentationPrinter(PrettyPrinter):
294 294 """
295 295 Special pretty printer that has a `pretty` method that calls the pretty
296 296 printer for a python object.
297 297
298 298 This class stores processing data on `self` so you must *never* use
299 299 this class in a threaded environment. Always lock it or reinstanciate
300 300 it.
301 301
302 302 Instances also have a verbose flag callbacks can access to control their
303 303 output. For example the default instance repr prints all attributes and
304 304 methods that are not prefixed by an underscore if the printer is in
305 305 verbose mode.
306 306 """
307 307
308 308 def __init__(self, output, verbose=False, max_width=79, newline='\n',
309 309 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None):
310 310
311 311 PrettyPrinter.__init__(self, output, max_width, newline)
312 312 self.verbose = verbose
313 313 self.stack = []
314 314 if singleton_pprinters is None:
315 315 singleton_pprinters = _singleton_pprinters.copy()
316 316 self.singleton_pprinters = singleton_pprinters
317 317 if type_pprinters is None:
318 318 type_pprinters = _type_pprinters.copy()
319 319 self.type_pprinters = type_pprinters
320 320 if deferred_pprinters is None:
321 321 deferred_pprinters = _deferred_type_pprinters.copy()
322 322 self.deferred_pprinters = deferred_pprinters
323 323
324 324 def pretty(self, obj):
325 325 """Pretty print the given object."""
326 326 obj_id = id(obj)
327 327 cycle = obj_id in self.stack
328 328 self.stack.append(obj_id)
329 329 self.begin_group()
330 330 try:
331 331 obj_class = getattr(obj, '__class__', None) or type(obj)
332 332 # First try to find registered singleton printers for the type.
333 333 try:
334 334 printer = self.singleton_pprinters[obj_id]
335 335 except (TypeError, KeyError):
336 336 pass
337 337 else:
338 338 return printer(obj, self, cycle)
339 # Next look for type_printers.
339 # Next walk the mro and check for either:
340 # 1) a registered printer
341 # 2) a _repr_pretty_ method
340 342 for cls in _get_mro(obj_class):
341 343 if cls in self.type_pprinters:
344 # printer registered in self.type_pprinters
342 345 return self.type_pprinters[cls](obj, self, cycle)
343 346 else:
347 # deferred printer
344 348 printer = self._in_deferred_types(cls)
345 349 if printer is not None:
346 350 return printer(obj, self, cycle)
347 # Finally look for special method names.
348 if hasattr(obj_class, '_repr_pretty_'):
349 # Some objects automatically create any requested
350 # attribute. Try to ignore most of them by checking for
351 # callability.
352 if callable(obj_class._repr_pretty_):
353 return obj_class._repr_pretty_(obj, self, cycle)
351 else:
352 # Finally look for special method names.
353 # Some objects automatically create any requested
354 # attribute. Try to ignore most of them by checking for
355 # callability.
356 if callable(getattr(obj_class, '_repr_pretty_')):
357 return obj_class._repr_pretty_(obj, self, cycle)
354 358 return _default_pprint(obj, self, cycle)
355 359 finally:
356 360 self.end_group()
357 361 self.stack.pop()
358 362
359 363 def _in_deferred_types(self, cls):
360 364 """
361 365 Check if the given class is specified in the deferred type registry.
362 366
363 367 Returns the printer from the registry if it exists, and None if the
364 368 class is not in the registry. Successful matches will be moved to the
365 369 regular type registry for future use.
366 370 """
367 371 mod = getattr(cls, '__module__', None)
368 372 name = getattr(cls, '__name__', None)
369 373 key = (mod, name)
370 374 printer = None
371 375 if key in self.deferred_pprinters:
372 376 # Move the printer over to the regular registry.
373 377 printer = self.deferred_pprinters.pop(key)
374 378 self.type_pprinters[cls] = printer
375 379 return printer
376 380
377 381
378 382 class Printable(object):
379 383
380 384 def output(self, stream, output_width):
381 385 return output_width
382 386
383 387
384 388 class Text(Printable):
385 389
386 390 def __init__(self):
387 391 self.objs = []
388 392 self.width = 0
389 393
390 394 def output(self, stream, output_width):
391 395 for obj in self.objs:
392 396 stream.write(obj)
393 397 return output_width + self.width
394 398
395 399 def add(self, obj, width):
396 400 self.objs.append(obj)
397 401 self.width += width
398 402
399 403
400 404 class Breakable(Printable):
401 405
402 406 def __init__(self, seq, width, pretty):
403 407 self.obj = seq
404 408 self.width = width
405 409 self.pretty = pretty
406 410 self.indentation = pretty.indentation
407 411 self.group = pretty.group_stack[-1]
408 412 self.group.breakables.append(self)
409 413
410 414 def output(self, stream, output_width):
411 415 self.group.breakables.popleft()
412 416 if self.group.want_break:
413 417 stream.write(self.pretty.newline)
414 418 stream.write(' ' * self.indentation)
415 419 return self.indentation
416 420 if not self.group.breakables:
417 421 self.pretty.group_queue.remove(self.group)
418 422 stream.write(self.obj)
419 423 return output_width + self.width
420 424
421 425
422 426 class Group(Printable):
423 427
424 428 def __init__(self, depth):
425 429 self.depth = depth
426 430 self.breakables = deque()
427 431 self.want_break = False
428 432
429 433
430 434 class GroupQueue(object):
431 435
432 436 def __init__(self, *groups):
433 437 self.queue = []
434 438 for group in groups:
435 439 self.enq(group)
436 440
437 441 def enq(self, group):
438 442 depth = group.depth
439 443 while depth > len(self.queue) - 1:
440 444 self.queue.append([])
441 445 self.queue[depth].append(group)
442 446
443 447 def deq(self):
444 448 for stack in self.queue:
445 449 for idx, group in enumerate(reversed(stack)):
446 450 if group.breakables:
447 451 del stack[idx]
448 452 group.want_break = True
449 453 return group
450 454 for group in stack:
451 455 group.want_break = True
452 456 del stack[:]
453 457
454 458 def remove(self, group):
455 459 try:
456 460 self.queue[group.depth].remove(group)
457 461 except ValueError:
458 462 pass
459 463
460 464 try:
461 465 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
462 466 except AttributeError: # Python 3
463 467 _baseclass_reprs = (object.__repr__,)
464 468
465 469
466 470 def _default_pprint(obj, p, cycle):
467 471 """
468 472 The default print function. Used if an object does not provide one and
469 473 it's none of the builtin objects.
470 474 """
471 475 klass = getattr(obj, '__class__', None) or type(obj)
472 476 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
473 477 # A user-provided repr.
474 478 p.text(repr(obj))
475 479 return
476 480 p.begin_group(1, '<')
477 481 p.pretty(klass)
478 482 p.text(' at 0x%x' % id(obj))
479 483 if cycle:
480 484 p.text(' ...')
481 485 elif p.verbose:
482 486 first = True
483 487 for key in dir(obj):
484 488 if not key.startswith('_'):
485 489 try:
486 490 value = getattr(obj, key)
487 491 except AttributeError:
488 492 continue
489 493 if isinstance(value, types.MethodType):
490 494 continue
491 495 if not first:
492 496 p.text(',')
493 497 p.breakable()
494 498 p.text(key)
495 499 p.text('=')
496 500 step = len(key) + 1
497 501 p.indentation += step
498 502 p.pretty(value)
499 503 p.indentation -= step
500 504 first = False
501 505 p.end_group(1, '>')
502 506
503 507
504 508 def _seq_pprinter_factory(start, end, basetype):
505 509 """
506 510 Factory that returns a pprint function useful for sequences. Used by
507 511 the default pprint for tuples, dicts, lists, sets and frozensets.
508 512 """
509 513 def inner(obj, p, cycle):
510 514 typ = type(obj)
511 515 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
512 516 # If the subclass provides its own repr, use it instead.
513 517 return p.text(typ.__repr__(obj))
514 518
515 519 if cycle:
516 520 return p.text(start + '...' + end)
517 521 step = len(start)
518 522 p.begin_group(step, start)
519 523 for idx, x in enumerate(obj):
520 524 if idx:
521 525 p.text(',')
522 526 p.breakable()
523 527 p.pretty(x)
524 528 if len(obj) == 1 and type(obj) is tuple:
525 529 # Special case for 1-item tuples.
526 530 p.text(',')
527 531 p.end_group(step, end)
528 532 return inner
529 533
530 534
531 535 def _dict_pprinter_factory(start, end, basetype=None):
532 536 """
533 537 Factory that returns a pprint function used by the default pprint of
534 538 dicts and dict proxies.
535 539 """
536 540 def inner(obj, p, cycle):
537 541 typ = type(obj)
538 542 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
539 543 # If the subclass provides its own repr, use it instead.
540 544 return p.text(typ.__repr__(obj))
541 545
542 546 if cycle:
543 547 return p.text('{...}')
544 548 p.begin_group(1, start)
545 549 keys = obj.keys()
546 550 try:
547 551 keys.sort()
548 552 except Exception, e:
549 553 # Sometimes the keys don't sort.
550 554 pass
551 555 for idx, key in enumerate(keys):
552 556 if idx:
553 557 p.text(',')
554 558 p.breakable()
555 559 p.pretty(key)
556 560 p.text(': ')
557 561 p.pretty(obj[key])
558 562 p.end_group(1, end)
559 563 return inner
560 564
561 565
562 566 def _super_pprint(obj, p, cycle):
563 567 """The pprint for the super type."""
564 568 p.begin_group(8, '<super: ')
565 569 p.pretty(obj.__self_class__)
566 570 p.text(',')
567 571 p.breakable()
568 572 p.pretty(obj.__self__)
569 573 p.end_group(8, '>')
570 574
571 575
572 576 def _re_pattern_pprint(obj, p, cycle):
573 577 """The pprint function for regular expression patterns."""
574 578 p.text('re.compile(')
575 579 pattern = repr(obj.pattern)
576 580 if pattern[:1] in 'uU':
577 581 pattern = pattern[1:]
578 582 prefix = 'ur'
579 583 else:
580 584 prefix = 'r'
581 585 pattern = prefix + pattern.replace('\\\\', '\\')
582 586 p.text(pattern)
583 587 if obj.flags:
584 588 p.text(',')
585 589 p.breakable()
586 590 done_one = False
587 591 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
588 592 'UNICODE', 'VERBOSE', 'DEBUG'):
589 593 if obj.flags & getattr(re, flag):
590 594 if done_one:
591 595 p.text('|')
592 596 p.text('re.' + flag)
593 597 done_one = True
594 598 p.text(')')
595 599
596 600
597 601 def _type_pprint(obj, p, cycle):
598 602 """The pprint for classes and types."""
599 603 if obj.__module__ in ('__builtin__', 'exceptions'):
600 604 name = obj.__name__
601 605 else:
602 606 name = obj.__module__ + '.' + obj.__name__
603 607 p.text(name)
604 608
605 609
606 610 def _repr_pprint(obj, p, cycle):
607 611 """A pprint that just redirects to the normal repr function."""
608 612 p.text(repr(obj))
609 613
610 614
611 615 def _function_pprint(obj, p, cycle):
612 616 """Base pprint for all functions and builtin functions."""
613 617 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
614 618 name = obj.__name__
615 619 else:
616 620 name = obj.__module__ + '.' + obj.__name__
617 621 p.text('<function %s>' % name)
618 622
619 623
620 624 def _exception_pprint(obj, p, cycle):
621 625 """Base pprint for all exceptions."""
622 626 if obj.__class__.__module__ in ('exceptions', 'builtins'):
623 627 name = obj.__class__.__name__
624 628 else:
625 629 name = '%s.%s' % (
626 630 obj.__class__.__module__,
627 631 obj.__class__.__name__
628 632 )
629 633 step = len(name) + 1
630 634 p.begin_group(step, name + '(')
631 635 for idx, arg in enumerate(getattr(obj, 'args', ())):
632 636 if idx:
633 637 p.text(',')
634 638 p.breakable()
635 639 p.pretty(arg)
636 640 p.end_group(step, ')')
637 641
638 642
639 643 #: the exception base
640 644 try:
641 645 _exception_base = BaseException
642 646 except NameError:
643 647 _exception_base = Exception
644 648
645 649
646 650 #: printers for builtin types
647 651 _type_pprinters = {
648 652 int: _repr_pprint,
649 653 long: _repr_pprint,
650 654 float: _repr_pprint,
651 655 str: _repr_pprint,
652 656 unicode: _repr_pprint,
653 657 tuple: _seq_pprinter_factory('(', ')', tuple),
654 658 list: _seq_pprinter_factory('[', ']', list),
655 659 dict: _dict_pprinter_factory('{', '}', dict),
656 660
657 661 set: _seq_pprinter_factory('set([', '])', set),
658 662 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
659 663 super: _super_pprint,
660 664 _re_pattern_type: _re_pattern_pprint,
661 665 type: _type_pprint,
662 666 types.FunctionType: _function_pprint,
663 667 types.BuiltinFunctionType: _function_pprint,
664 668 types.SliceType: _repr_pprint,
665 669 types.MethodType: _repr_pprint,
666 670
667 671 datetime.datetime: _repr_pprint,
668 672 datetime.timedelta: _repr_pprint,
669 673 _exception_base: _exception_pprint
670 674 }
671 675
672 676 try:
673 677 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
674 678 _type_pprinters[types.ClassType] = _type_pprint
675 679 except AttributeError: # Python 3
676 680 pass
677 681
678 682 try:
679 683 _type_pprinters[xrange] = _repr_pprint
680 684 except NameError:
681 685 _type_pprinters[range] = _repr_pprint
682 686
683 687 #: printers for types specified by name
684 688 _deferred_type_pprinters = {
685 689 }
686 690
687 691 def for_type(typ, func):
688 692 """
689 693 Add a pretty printer for a given type.
690 694 """
691 695 oldfunc = _type_pprinters.get(typ, None)
692 696 if func is not None:
693 697 # To support easy restoration of old pprinters, we need to ignore Nones.
694 698 _type_pprinters[typ] = func
695 699 return oldfunc
696 700
697 701 def for_type_by_name(type_module, type_name, func):
698 702 """
699 703 Add a pretty printer for a type specified by the module and name of a type
700 704 rather than the type object itself.
701 705 """
702 706 key = (type_module, type_name)
703 707 oldfunc = _deferred_type_pprinters.get(key, None)
704 708 if func is not None:
705 709 # To support easy restoration of old pprinters, we need to ignore Nones.
706 710 _deferred_type_pprinters[key] = func
707 711 return oldfunc
708 712
709 713
710 714 #: printers for the default singletons
711 715 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
712 716 NotImplemented]), _repr_pprint)
713 717
714 718
715 719 if __name__ == '__main__':
716 720 from random import randrange
717 721 class Foo(object):
718 722 def __init__(self):
719 723 self.foo = 1
720 724 self.bar = re.compile(r'\s+')
721 725 self.blub = dict.fromkeys(range(30), randrange(1, 40))
722 726 self.hehe = 23424.234234
723 727 self.list = ["blub", "blah", self]
724 728
725 729 def get_foo(self):
726 730 print "foo"
727 731
728 732 pprint(Foo(), verbose=True)
@@ -1,49 +1,65 b''
1 1 """Tests for IPython.lib.pretty.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2011, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 16 # Third-party imports
17 17 import nose.tools as nt
18 18
19 19 # Our own imports
20 20 from IPython.lib import pretty
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Classes and functions
24 24 #-----------------------------------------------------------------------------
25 25
26 26 class MyList(object):
27 27 def __init__(self, content):
28 28 self.content = content
29 29 def _repr_pretty_(self, p, cycle):
30 30 if cycle:
31 31 p.text("MyList(...)")
32 32 else:
33 33 with p.group(3, "MyList(", ")"):
34 34 for (i, child) in enumerate(self.content):
35 35 if i:
36 36 p.text(",")
37 37 p.breakable()
38 38 else:
39 39 p.breakable("")
40 40 p.pretty(child)
41 41
42 42
43 class MyDict(dict):
44 def _repr_pretty_(self, p, cycle):
45 p.text("MyDict(...)")
46
47
43 48 def test_indentation():
44 49 """Test correct indentation in groups"""
45 50 count = 40
46 51 gotoutput = pretty.pretty(MyList(range(count)))
47 52 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
48 53
49 54 nt.assert_equals(gotoutput, expectedoutput)
55
56
57 def test_dispatch():
58 """
59 Test correct dispatching: The _repr_pretty_ method for MyDict
60 must be found before the registered printer for dict.
61 """
62 gotoutput = pretty.pretty(MyDict())
63 expectedoutput = "MyDict(...)"
64
65 nt.assert_equals(gotoutput, expectedoutput)
General Comments 0
You need to be logged in to leave comments. Login now