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