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