##// END OF EJS Templates
ENH: Add the ipy_pretty extension.
Robert Kern -
Show More
@@ -0,0 +1,61 b''
1 """ Use pretty.py for configurable pretty-printing.
2
3 Register pretty-printers for types using pretty.for_type() or
4 pretty.for_type_by_name(). For example, to make a pretty-printer for numpy dtype
5 objects, add the following to your ipy_user_conf.py::
6
7 from IPython.Extensions import ipy_pretty, pretty
8
9 def dtype_pprinter(obj, p, cycle):
10 if cycle:
11 return p.text('dtype(...)')
12 if obj.fields is None:
13 p.text(repr(obj))
14 else:
15 p.begin_group(7, 'dtype([')
16 for i, field in enumerate(obj.descr):
17 if i > 0:
18 p.text(',')
19 p.breakable()
20 p.pretty(field)
21 p.end_group(7, '])')
22
23 # If you want to have numpy always imported anyways:
24 import numpy
25 pretty.for_type(numpy.dtype, dtype_pprinter)
26
27 # If you don't want to have numpy imported until it needs to be:
28 pretty.for_type_by_name('numpy', 'dtype', dtype_pprinter)
29 """
30
31 import IPython.ipapi
32 from IPython.genutils import Term
33
34 from IPython.Extensions import pretty
35
36 ip = IPython.ipapi.get()
37
38 def pretty_result_display(self, arg):
39 """ Uber-pretty-printing display hook.
40
41 Called for displaying the result to the user.
42 """
43
44 if self.rc.pprint:
45 out = pretty.pretty(arg, verbose=getattr(self.rc, 'pretty_verbose', False))
46 if '\n' in out:
47 # So that multi-line strings line up with the left column of
48 # the screen, instead of having the output prompt mess up
49 # their first line.
50 Term.cout.write('\n')
51 print >>Term.cout, out
52 else:
53 # By default, the interactive prompt uses repr() to display results,
54 # so we should honor this. Users who'd rather use a different
55 # mechanism can easily override this hook.
56 print >>Term.cout, repr(arg)
57 # the default display hook doesn't manipulate the value to put in history
58 return None
59
60 ip.set_hook('result_display', pretty_result_display)
61
This diff has been collapsed as it changes many lines, (699 lines changed) Show them Hide them
@@ -0,0 +1,699 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 obj_class = type(obj_class.__name__, (obj_class, object), {})
297 mro = obj_class.__mro__[1:-1]
298 else:
299 mro = obj_class.__mro__
300 return mro
301
302
303 class RepresentationPrinter(PrettyPrinter):
304 """
305 Special pretty printer that has a `pretty` method that calls the pretty
306 printer for a python object.
307
308 This class stores processing data on `self` so you must *never* use
309 this class in a threaded environment. Always lock it or reinstanciate
310 it.
311
312 Instances also have a verbose flag callbacks can access to control their
313 output. For example the default instance repr prints all attributes and
314 methods that are not prefixed by an underscore if the printer is in
315 verbose mode.
316 """
317
318 def __init__(self, output, verbose=False, max_width=79, newline='\n'):
319 PrettyPrinter.__init__(self, output, max_width, newline)
320 self.verbose = verbose
321 self.stack = []
322
323 def pretty(self, obj):
324 """Pretty print the given object."""
325 obj_id = id(obj)
326 cycle = obj_id in self.stack
327 self.stack.append(obj_id)
328 self.begin_group()
329 try:
330 obj_class = getattr(obj, '__class__', None) or type(obj)
331 if hasattr(obj_class, '__pretty__'):
332 return obj_class.__pretty__(obj, self, cycle)
333 try:
334 printer = _singleton_pprinters[obj_id]
335 except (TypeError, KeyError):
336 pass
337 else:
338 return printer(obj, self, cycle)
339 for cls in _get_mro(obj_class):
340 if cls in _type_pprinters:
341 return _type_pprinters[cls](obj, self, cycle)
342 else:
343 printer = self._in_deferred_types(cls)
344 if printer is not None:
345 return printer(obj, self, cycle)
346 return _default_pprint(obj, self, cycle)
347 finally:
348 self.end_group()
349 self.stack.pop()
350
351 def _in_deferred_types(self, cls):
352 """
353 Check if the given class is specified in the deferred type registry.
354
355 Returns the printer from the registry if it exists, and None if the
356 class is not in the registry. Successful matches will be moved to the
357 regular type registry for future use.
358 """
359 mod = getattr(cls, '__module__', None)
360 name = getattr(cls, '__name__', None)
361 key = (mod, name)
362 printer = None
363 if key in _deferred_type_pprinters:
364 # Move the printer over to the regular registry.
365 printer = _deferred_type_pprinters.pop(key)
366 _type_pprinters[cls] = printer
367 return printer
368
369
370
371 class Printable(object):
372
373 def output(self, stream, output_width):
374 return output_width
375
376
377 class Text(Printable):
378
379 def __init__(self):
380 self.objs = []
381 self.width = 0
382
383 def output(self, stream, output_width):
384 for obj in self.objs:
385 stream.write(obj)
386 return output_width + self.width
387
388 def add(self, obj, width):
389 self.objs.append(obj)
390 self.width += width
391
392
393 class Breakable(Printable):
394
395 def __init__(self, seq, width, pretty):
396 self.obj = seq
397 self.width = width
398 self.pretty = pretty
399 self.indentation = pretty.indentation
400 self.group = pretty.group_stack[-1]
401 self.group.breakables.append(self)
402
403 def output(self, stream, output_width):
404 self.group.breakables.popleft()
405 if self.group.want_break:
406 stream.write(self.pretty.newline)
407 stream.write(' ' * self.indentation)
408 return self.indentation
409 if not self.group.breakables:
410 self.pretty.group_queue.remove(self.group)
411 stream.write(self.obj)
412 return output_width + self.width
413
414
415 class Group(Printable):
416
417 def __init__(self, depth):
418 self.depth = depth
419 self.breakables = deque()
420 self.want_break = False
421
422
423 class GroupQueue(object):
424
425 def __init__(self, *groups):
426 self.queue = []
427 for group in groups:
428 self.enq(group)
429
430 def enq(self, group):
431 depth = group.depth
432 while depth > len(self.queue) - 1:
433 self.queue.append([])
434 self.queue[depth].append(group)
435
436 def deq(self):
437 for stack in self.queue:
438 for idx, group in enumerate(reversed(stack)):
439 if group.breakables:
440 del stack[idx]
441 group.want_break = True
442 return group
443 for group in stack:
444 group.want_break = True
445 del stack[:]
446
447 def remove(self, group):
448 try:
449 self.queue[group.depth].remove(group)
450 except ValueError:
451 pass
452
453
454 _baseclass_reprs = (object.__repr__, types.InstanceType.__repr__)
455
456
457 def _default_pprint(obj, p, cycle):
458 """
459 The default print function. Used if an object does not provide one and
460 it's none of the builtin objects.
461 """
462 klass = getattr(obj, '__class__', None) or type(obj)
463 if getattr(klass, '__repr__', None) not in _baseclass_reprs:
464 # A user-provided repr.
465 p.text(repr(obj))
466 return
467 p.begin_group(1, '<')
468 p.pretty(klass)
469 p.text(' at 0x%x' % id(obj))
470 if cycle:
471 p.text(' ...')
472 elif p.verbose:
473 first = True
474 for key in dir(obj):
475 if not key.startswith('_'):
476 try:
477 value = getattr(obj, key)
478 except AttributeError:
479 continue
480 if isinstance(value, types.MethodType):
481 continue
482 if not first:
483 p.text(',')
484 p.breakable()
485 p.text(key)
486 p.text('=')
487 step = len(key) + 1
488 p.indentation += step
489 p.pretty(value)
490 p.indentation -= step
491 first = False
492 p.end_group(1, '>')
493
494
495 def _seq_pprinter_factory(start, end):
496 """
497 Factory that returns a pprint function useful for sequences. Used by
498 the default pprint for tuples, dicts, lists, sets and frozensets.
499 """
500 def inner(obj, p, cycle):
501 if cycle:
502 return p.text(start + '...' + end)
503 step = len(start)
504 p.begin_group(step, start)
505 for idx, x in enumerate(obj):
506 if idx:
507 p.text(',')
508 p.breakable()
509 p.pretty(x)
510 if len(obj) == 1 and type(obj) is tuple:
511 # Special case for 1-item tuples.
512 p.text(',')
513 p.end_group(step, end)
514 return inner
515
516
517 def _dict_pprinter_factory(start, end):
518 """
519 Factory that returns a pprint function used by the default pprint of
520 dicts and dict proxies.
521 """
522 def inner(obj, p, cycle):
523 if cycle:
524 return p.text('{...}')
525 p.begin_group(1, start)
526 keys = obj.keys()
527 try:
528 keys.sort()
529 except Exception, e:
530 # Sometimes the keys don't sort.
531 pass
532 for idx, key in enumerate(keys):
533 if idx:
534 p.text(',')
535 p.breakable()
536 p.pretty(key)
537 p.text(': ')
538 p.pretty(obj[key])
539 p.end_group(1, end)
540 return inner
541
542
543 def _super_pprint(obj, p, cycle):
544 """The pprint for the super type."""
545 p.begin_group(8, '<super: ')
546 p.pretty(obj.__self_class__)
547 p.text(',')
548 p.breakable()
549 p.pretty(obj.__self__)
550 p.end_group(8, '>')
551
552
553 def _re_pattern_pprint(obj, p, cycle):
554 """The pprint function for regular expression patterns."""
555 p.text('re.compile(')
556 pattern = repr(obj.pattern)
557 if pattern[:1] in 'uU':
558 pattern = pattern[1:]
559 prefix = 'ur'
560 else:
561 prefix = 'r'
562 pattern = prefix + pattern.replace('\\\\', '\\')
563 p.text(pattern)
564 if obj.flags:
565 p.text(',')
566 p.breakable()
567 done_one = False
568 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
569 'UNICODE', 'VERBOSE', 'DEBUG'):
570 if obj.flags & getattr(re, flag):
571 if done_one:
572 p.text('|')
573 p.text('re.' + flag)
574 done_one = True
575 p.text(')')
576
577
578 def _type_pprint(obj, p, cycle):
579 """The pprint for classes and types."""
580 if obj.__module__ in ('__builtin__', 'exceptions'):
581 name = obj.__name__
582 else:
583 name = obj.__module__ + '.' + obj.__name__
584 p.text(name)
585
586
587 def _repr_pprint(obj, p, cycle):
588 """A pprint that just redirects to the normal repr function."""
589 p.text(repr(obj))
590
591
592 def _function_pprint(obj, p, cycle):
593 """Base pprint for all functions and builtin functions."""
594 if obj.__module__ in ('__builtin__', 'exceptions') or not obj.__module__:
595 name = obj.__name__
596 else:
597 name = obj.__module__ + '.' + obj.__name__
598 p.text('<function %s>' % name)
599
600
601 def _exception_pprint(obj, p, cycle):
602 """Base pprint for all exceptions."""
603 if obj.__class__.__module__ == 'exceptions':
604 name = obj.__class__.__name__
605 else:
606 name = '%s.%s' % (
607 obj.__class__.__module__,
608 obj.__class__.__name__
609 )
610 step = len(name) + 1
611 p.begin_group(step, '(')
612 for idx, arg in enumerate(getattr(obj, 'args', ())):
613 if idx:
614 p.text(',')
615 p.breakable()
616 p.pretty(arg)
617 p.end_group(step, ')')
618
619
620 #: the exception base
621 try:
622 _exception_base = BaseException
623 except NameError:
624 _exception_base = Exception
625
626
627 #: printers for builtin types
628 _type_pprinters = {
629 int: _repr_pprint,
630 long: _repr_pprint,
631 float: _repr_pprint,
632 str: _repr_pprint,
633 unicode: _repr_pprint,
634 tuple: _seq_pprinter_factory('(', ')'),
635 list: _seq_pprinter_factory('[', ']'),
636 dict: _dict_pprinter_factory('{', '}'),
637 types.DictProxyType: _dict_pprinter_factory('<dictproxy {', '}>'),
638 set: _seq_pprinter_factory('set([', '])'),
639 frozenset: _seq_pprinter_factory('frozenset([', '])'),
640 super: _super_pprint,
641 _re_pattern_type: _re_pattern_pprint,
642 type: _type_pprint,
643 types.ClassType: _type_pprint,
644 types.FunctionType: _function_pprint,
645 types.BuiltinFunctionType: _function_pprint,
646 types.SliceType: _repr_pprint,
647 types.MethodType: _repr_pprint,
648 xrange: _repr_pprint,
649 datetime.datetime: _repr_pprint,
650 datetime.timedelta: _repr_pprint,
651 _exception_base: _exception_pprint
652 }
653
654 #: printers for types specified by name
655 _deferred_type_pprinters = {
656 }
657
658 def for_type(typ, func):
659 """
660 Add a pretty printer for a given type.
661 """
662 oldfunc = _type_pprinters.get(typ, None)
663 if func is not None:
664 # To support easy restoration of old pprinters, we need to ignore Nones.
665 _type_pprinters[typ] = func
666 return oldfunc
667
668 def for_type_by_name(type_module, type_name, func):
669 """
670 Add a pretty printer for a type specified by the module and name of a type
671 rather than the type object itself.
672 """
673 key = (type_module, type_name)
674 oldfunc = _deferred_type_pprinters.get(key, None)
675 if func is not None:
676 # To support easy restoration of old pprinters, we need to ignore Nones.
677 _deferred_type_pprinters[key] = func
678 return oldfunc
679
680
681 #: printers for the default singletons
682 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
683 NotImplemented]), _repr_pprint)
684
685
686 if __name__ == '__main__':
687 from random import randrange
688 class Foo(object):
689 def __init__(self):
690 self.foo = 1
691 self.bar = re.compile(r'\s+')
692 self.blub = dict.fromkeys(range(30), randrange(1, 40))
693 self.hehe = 23424.234234
694 self.list = ["blub", "blah", self]
695
696 def get_foo(self):
697 print "foo"
698
699 pprint(Foo(), verbose=True)
General Comments 0
You need to be logged in to leave comments. Login now