##// END OF EJS Templates
Merge pull request #2123 from rkern/fix-pretty...
Bradley M. Froehle -
r7849:4f10bd8a merge
parent child Browse files
Show More
@@ -1,734 +1,734
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 339 # Next walk the mro and check for either:
340 340 # 1) a registered printer
341 341 # 2) a _repr_pretty_ method
342 342 for cls in _get_mro(obj_class):
343 343 if cls in self.type_pprinters:
344 344 # printer registered in self.type_pprinters
345 345 return self.type_pprinters[cls](obj, self, cycle)
346 346 else:
347 347 # deferred printer
348 348 printer = self._in_deferred_types(cls)
349 349 if printer is not None:
350 350 return printer(obj, self, cycle)
351 351 else:
352 352 # Finally look for special method names.
353 353 # Some objects automatically create any requested
354 354 # attribute. Try to ignore most of them by checking for
355 355 # callability.
356 if '_repr_pretty_' in obj_class.__dict__:
357 meth = obj_class._repr_pretty_
356 if '_repr_pretty_' in cls.__dict__:
357 meth = cls._repr_pretty_
358 358 if callable(meth):
359 359 return meth(obj, self, cycle)
360 360 return _default_pprint(obj, self, cycle)
361 361 finally:
362 362 self.end_group()
363 363 self.stack.pop()
364 364
365 365 def _in_deferred_types(self, cls):
366 366 """
367 367 Check if the given class is specified in the deferred type registry.
368 368
369 369 Returns the printer from the registry if it exists, and None if the
370 370 class is not in the registry. Successful matches will be moved to the
371 371 regular type registry for future use.
372 372 """
373 373 mod = getattr(cls, '__module__', None)
374 374 name = getattr(cls, '__name__', None)
375 375 key = (mod, name)
376 376 printer = None
377 377 if key in self.deferred_pprinters:
378 378 # Move the printer over to the regular registry.
379 379 printer = self.deferred_pprinters.pop(key)
380 380 self.type_pprinters[cls] = printer
381 381 return printer
382 382
383 383
384 384 class Printable(object):
385 385
386 386 def output(self, stream, output_width):
387 387 return output_width
388 388
389 389
390 390 class Text(Printable):
391 391
392 392 def __init__(self):
393 393 self.objs = []
394 394 self.width = 0
395 395
396 396 def output(self, stream, output_width):
397 397 for obj in self.objs:
398 398 stream.write(obj)
399 399 return output_width + self.width
400 400
401 401 def add(self, obj, width):
402 402 self.objs.append(obj)
403 403 self.width += width
404 404
405 405
406 406 class Breakable(Printable):
407 407
408 408 def __init__(self, seq, width, pretty):
409 409 self.obj = seq
410 410 self.width = width
411 411 self.pretty = pretty
412 412 self.indentation = pretty.indentation
413 413 self.group = pretty.group_stack[-1]
414 414 self.group.breakables.append(self)
415 415
416 416 def output(self, stream, output_width):
417 417 self.group.breakables.popleft()
418 418 if self.group.want_break:
419 419 stream.write(self.pretty.newline)
420 420 stream.write(' ' * self.indentation)
421 421 return self.indentation
422 422 if not self.group.breakables:
423 423 self.pretty.group_queue.remove(self.group)
424 424 stream.write(self.obj)
425 425 return output_width + self.width
426 426
427 427
428 428 class Group(Printable):
429 429
430 430 def __init__(self, depth):
431 431 self.depth = depth
432 432 self.breakables = deque()
433 433 self.want_break = False
434 434
435 435
436 436 class GroupQueue(object):
437 437
438 438 def __init__(self, *groups):
439 439 self.queue = []
440 440 for group in groups:
441 441 self.enq(group)
442 442
443 443 def enq(self, group):
444 444 depth = group.depth
445 445 while depth > len(self.queue) - 1:
446 446 self.queue.append([])
447 447 self.queue[depth].append(group)
448 448
449 449 def deq(self):
450 450 for stack in self.queue:
451 451 for idx, group in enumerate(reversed(stack)):
452 452 if group.breakables:
453 453 del stack[idx]
454 454 group.want_break = True
455 455 return group
456 456 for group in stack:
457 457 group.want_break = True
458 458 del stack[:]
459 459
460 460 def remove(self, group):
461 461 try:
462 462 self.queue[group.depth].remove(group)
463 463 except ValueError:
464 464 pass
465 465
466 466 try:
467 467 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
468 468 except AttributeError: # Python 3
469 469 _baseclass_reprs = (object.__repr__,)
470 470
471 471
472 472 def _default_pprint(obj, p, cycle):
473 473 """
474 474 The default print function. Used if an object does not provide one and
475 475 it's none of the builtin objects.
476 476 """
477 477 klass = getattr(obj, '__class__', None) or type(obj)
478 478 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
479 479 # A user-provided repr.
480 480 p.text(repr(obj))
481 481 return
482 482 p.begin_group(1, '<')
483 483 p.pretty(klass)
484 484 p.text(' at 0x%x' % id(obj))
485 485 if cycle:
486 486 p.text(' ...')
487 487 elif p.verbose:
488 488 first = True
489 489 for key in dir(obj):
490 490 if not key.startswith('_'):
491 491 try:
492 492 value = getattr(obj, key)
493 493 except AttributeError:
494 494 continue
495 495 if isinstance(value, types.MethodType):
496 496 continue
497 497 if not first:
498 498 p.text(',')
499 499 p.breakable()
500 500 p.text(key)
501 501 p.text('=')
502 502 step = len(key) + 1
503 503 p.indentation += step
504 504 p.pretty(value)
505 505 p.indentation -= step
506 506 first = False
507 507 p.end_group(1, '>')
508 508
509 509
510 510 def _seq_pprinter_factory(start, end, basetype):
511 511 """
512 512 Factory that returns a pprint function useful for sequences. Used by
513 513 the default pprint for tuples, dicts, lists, sets and frozensets.
514 514 """
515 515 def inner(obj, p, cycle):
516 516 typ = type(obj)
517 517 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
518 518 # If the subclass provides its own repr, use it instead.
519 519 return p.text(typ.__repr__(obj))
520 520
521 521 if cycle:
522 522 return p.text(start + '...' + end)
523 523 step = len(start)
524 524 p.begin_group(step, start)
525 525 for idx, x in enumerate(obj):
526 526 if idx:
527 527 p.text(',')
528 528 p.breakable()
529 529 p.pretty(x)
530 530 if len(obj) == 1 and type(obj) is tuple:
531 531 # Special case for 1-item tuples.
532 532 p.text(',')
533 533 p.end_group(step, end)
534 534 return inner
535 535
536 536
537 537 def _dict_pprinter_factory(start, end, basetype=None):
538 538 """
539 539 Factory that returns a pprint function used by the default pprint of
540 540 dicts and dict proxies.
541 541 """
542 542 def inner(obj, p, cycle):
543 543 typ = type(obj)
544 544 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
545 545 # If the subclass provides its own repr, use it instead.
546 546 return p.text(typ.__repr__(obj))
547 547
548 548 if cycle:
549 549 return p.text('{...}')
550 550 p.begin_group(1, start)
551 551 keys = obj.keys()
552 552 try:
553 553 keys.sort()
554 554 except Exception as e:
555 555 # Sometimes the keys don't sort.
556 556 pass
557 557 for idx, key in enumerate(keys):
558 558 if idx:
559 559 p.text(',')
560 560 p.breakable()
561 561 p.pretty(key)
562 562 p.text(': ')
563 563 p.pretty(obj[key])
564 564 p.end_group(1, end)
565 565 return inner
566 566
567 567
568 568 def _super_pprint(obj, p, cycle):
569 569 """The pprint for the super type."""
570 570 p.begin_group(8, '<super: ')
571 571 p.pretty(obj.__self_class__)
572 572 p.text(',')
573 573 p.breakable()
574 574 p.pretty(obj.__self__)
575 575 p.end_group(8, '>')
576 576
577 577
578 578 def _re_pattern_pprint(obj, p, cycle):
579 579 """The pprint function for regular expression patterns."""
580 580 p.text('re.compile(')
581 581 pattern = repr(obj.pattern)
582 582 if pattern[:1] in 'uU':
583 583 pattern = pattern[1:]
584 584 prefix = 'ur'
585 585 else:
586 586 prefix = 'r'
587 587 pattern = prefix + pattern.replace('\\\\', '\\')
588 588 p.text(pattern)
589 589 if obj.flags:
590 590 p.text(',')
591 591 p.breakable()
592 592 done_one = False
593 593 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
594 594 'UNICODE', 'VERBOSE', 'DEBUG'):
595 595 if obj.flags & getattr(re, flag):
596 596 if done_one:
597 597 p.text('|')
598 598 p.text('re.' + flag)
599 599 done_one = True
600 600 p.text(')')
601 601
602 602
603 603 def _type_pprint(obj, p, cycle):
604 604 """The pprint for classes and types."""
605 605 if obj.__module__ in ('__builtin__', 'exceptions'):
606 606 name = obj.__name__
607 607 else:
608 608 name = obj.__module__ + '.' + obj.__name__
609 609 p.text(name)
610 610
611 611
612 612 def _repr_pprint(obj, p, cycle):
613 613 """A pprint that just redirects to the normal repr function."""
614 614 p.text(repr(obj))
615 615
616 616
617 617 def _function_pprint(obj, p, cycle):
618 618 """Base pprint for all functions and builtin functions."""
619 619 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
620 620 name = obj.__name__
621 621 else:
622 622 name = obj.__module__ + '.' + obj.__name__
623 623 p.text('<function %s>' % name)
624 624
625 625
626 626 def _exception_pprint(obj, p, cycle):
627 627 """Base pprint for all exceptions."""
628 628 if obj.__class__.__module__ in ('exceptions', 'builtins'):
629 629 name = obj.__class__.__name__
630 630 else:
631 631 name = '%s.%s' % (
632 632 obj.__class__.__module__,
633 633 obj.__class__.__name__
634 634 )
635 635 step = len(name) + 1
636 636 p.begin_group(step, name + '(')
637 637 for idx, arg in enumerate(getattr(obj, 'args', ())):
638 638 if idx:
639 639 p.text(',')
640 640 p.breakable()
641 641 p.pretty(arg)
642 642 p.end_group(step, ')')
643 643
644 644
645 645 #: the exception base
646 646 try:
647 647 _exception_base = BaseException
648 648 except NameError:
649 649 _exception_base = Exception
650 650
651 651
652 652 #: printers for builtin types
653 653 _type_pprinters = {
654 654 int: _repr_pprint,
655 655 long: _repr_pprint,
656 656 float: _repr_pprint,
657 657 str: _repr_pprint,
658 658 unicode: _repr_pprint,
659 659 tuple: _seq_pprinter_factory('(', ')', tuple),
660 660 list: _seq_pprinter_factory('[', ']', list),
661 661 dict: _dict_pprinter_factory('{', '}', dict),
662 662
663 663 set: _seq_pprinter_factory('set([', '])', set),
664 664 frozenset: _seq_pprinter_factory('frozenset([', '])', frozenset),
665 665 super: _super_pprint,
666 666 _re_pattern_type: _re_pattern_pprint,
667 667 type: _type_pprint,
668 668 types.FunctionType: _function_pprint,
669 669 types.BuiltinFunctionType: _function_pprint,
670 670 types.SliceType: _repr_pprint,
671 671 types.MethodType: _repr_pprint,
672 672
673 673 datetime.datetime: _repr_pprint,
674 674 datetime.timedelta: _repr_pprint,
675 675 _exception_base: _exception_pprint
676 676 }
677 677
678 678 try:
679 679 _type_pprinters[types.DictProxyType] = _dict_pprinter_factory('<dictproxy {', '}>')
680 680 _type_pprinters[types.ClassType] = _type_pprint
681 681 except AttributeError: # Python 3
682 682 pass
683 683
684 684 try:
685 685 _type_pprinters[xrange] = _repr_pprint
686 686 except NameError:
687 687 _type_pprinters[range] = _repr_pprint
688 688
689 689 #: printers for types specified by name
690 690 _deferred_type_pprinters = {
691 691 }
692 692
693 693 def for_type(typ, func):
694 694 """
695 695 Add a pretty printer for a given type.
696 696 """
697 697 oldfunc = _type_pprinters.get(typ, None)
698 698 if func is not None:
699 699 # To support easy restoration of old pprinters, we need to ignore Nones.
700 700 _type_pprinters[typ] = func
701 701 return oldfunc
702 702
703 703 def for_type_by_name(type_module, type_name, func):
704 704 """
705 705 Add a pretty printer for a type specified by the module and name of a type
706 706 rather than the type object itself.
707 707 """
708 708 key = (type_module, type_name)
709 709 oldfunc = _deferred_type_pprinters.get(key, None)
710 710 if func is not None:
711 711 # To support easy restoration of old pprinters, we need to ignore Nones.
712 712 _deferred_type_pprinters[key] = func
713 713 return oldfunc
714 714
715 715
716 716 #: printers for the default singletons
717 717 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
718 718 NotImplemented]), _repr_pprint)
719 719
720 720
721 721 if __name__ == '__main__':
722 722 from random import randrange
723 723 class Foo(object):
724 724 def __init__(self):
725 725 self.foo = 1
726 726 self.bar = re.compile(r'\s+')
727 727 self.blub = dict.fromkeys(range(30), randrange(1, 40))
728 728 self.hehe = 23424.234234
729 729 self.list = ["blub", "blah", self]
730 730
731 731 def get_foo(self):
732 732 print "foo"
733 733
734 734 pprint(Foo(), verbose=True)
@@ -1,65 +1,84
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 43 class MyDict(dict):
44 44 def _repr_pretty_(self, p, cycle):
45 45 p.text("MyDict(...)")
46 46
47 47
48 class Dummy1(object):
49 def _repr_pretty_(self, p, cycle):
50 p.text("Dummy1(...)")
51
52 class Dummy2(Dummy1):
53 _repr_pretty_ = None
54
55
48 56 def test_indentation():
49 57 """Test correct indentation in groups"""
50 58 count = 40
51 59 gotoutput = pretty.pretty(MyList(range(count)))
52 60 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
53 61
54 62 nt.assert_equals(gotoutput, expectedoutput)
55 63
56 64
57 65 def test_dispatch():
58 66 """
59 67 Test correct dispatching: The _repr_pretty_ method for MyDict
60 68 must be found before the registered printer for dict.
61 69 """
62 70 gotoutput = pretty.pretty(MyDict())
63 71 expectedoutput = "MyDict(...)"
64 72
65 73 nt.assert_equals(gotoutput, expectedoutput)
74
75
76 def test_callability_checking():
77 """
78 Test that the _repr_pretty_ method is tested for callability and skipped if
79 not.
80 """
81 gotoutput = pretty.pretty(Dummy2())
82 expectedoutput = "Dummy1(...)"
83
84 nt.assert_equals(gotoutput, expectedoutput)
General Comments 0
You need to be logged in to leave comments. Login now