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