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