##// END OF EJS Templates
Added sorting on counter and passed all tests
Jono Tassia -
Show More
@@ -1,953 +1,953 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 Here's an example for a class with a simple constructor::
37 Here's an example for a class with a simple constructor::
38
38
39 class MySimpleObject:
39 class MySimpleObject:
40
40
41 def __init__(self, a, b, *, c=None):
41 def __init__(self, a, b, *, c=None):
42 self.a = a
42 self.a = a
43 self.b = b
43 self.b = b
44 self.c = c
44 self.c = c
45
45
46 def _repr_pretty_(self, p, cycle):
46 def _repr_pretty_(self, p, cycle):
47 ctor = CallExpression.factory(self.__class__.__name__)
47 ctor = CallExpression.factory(self.__class__.__name__)
48 if self.c is None:
48 if self.c is None:
49 p.pretty(ctor(a, b))
49 p.pretty(ctor(a, b))
50 else:
50 else:
51 p.pretty(ctor(a, b, c=c))
51 p.pretty(ctor(a, b, c=c))
52
52
53 Here is an example implementation of a `_repr_pretty_` method for a list
53 Here is an example implementation of a `_repr_pretty_` method for a list
54 subclass::
54 subclass::
55
55
56 class MyList(list):
56 class MyList(list):
57
57
58 def _repr_pretty_(self, p, cycle):
58 def _repr_pretty_(self, p, cycle):
59 if cycle:
59 if cycle:
60 p.text('MyList(...)')
60 p.text('MyList(...)')
61 else:
61 else:
62 with p.group(8, 'MyList([', '])'):
62 with p.group(8, 'MyList([', '])'):
63 for idx, item in enumerate(self):
63 for idx, item in enumerate(self):
64 if idx:
64 if idx:
65 p.text(',')
65 p.text(',')
66 p.breakable()
66 p.breakable()
67 p.pretty(item)
67 p.pretty(item)
68
68
69 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
69 The `cycle` parameter is `True` if pretty detected a cycle. You *have* to
70 react to that or the result is an infinite loop. `p.text()` just adds
70 react to that or the result is an infinite loop. `p.text()` just adds
71 non breaking text to the output, `p.breakable()` either adds a whitespace
71 non breaking text to the output, `p.breakable()` either adds a whitespace
72 or breaks here. If you pass it an argument it's used instead of the
72 or breaks here. If you pass it an argument it's used instead of the
73 default space. `p.pretty` prettyprints another object using the pretty print
73 default space. `p.pretty` prettyprints another object using the pretty print
74 method.
74 method.
75
75
76 The first parameter to the `group` function specifies the extra indentation
76 The first parameter to the `group` function specifies the extra indentation
77 of the next line. In this example the next item will either be on the same
77 of the next line. In this example the next item will either be on the same
78 line (if the items are short enough) or aligned with the right edge of the
78 line (if the items are short enough) or aligned with the right edge of the
79 opening bracket of `MyList`.
79 opening bracket of `MyList`.
80
80
81 If you just want to indent something you can use the group function
81 If you just want to indent something you can use the group function
82 without open / close parameters. You can also use this code::
82 without open / close parameters. You can also use this code::
83
83
84 with p.indent(2):
84 with p.indent(2):
85 ...
85 ...
86
86
87 Inheritance diagram:
87 Inheritance diagram:
88
88
89 .. inheritance-diagram:: IPython.lib.pretty
89 .. inheritance-diagram:: IPython.lib.pretty
90 :parts: 3
90 :parts: 3
91
91
92 :copyright: 2007 by Armin Ronacher.
92 :copyright: 2007 by Armin Ronacher.
93 Portions (c) 2009 by Robert Kern.
93 Portions (c) 2009 by Robert Kern.
94 :license: BSD License.
94 :license: BSD License.
95 """
95 """
96
96
97 from contextlib import contextmanager
97 from contextlib import contextmanager
98 import datetime
98 import datetime
99 import os
99 import os
100 import re
100 import re
101 import sys
101 import sys
102 import types
102 import types
103 from collections import deque
103 from collections import deque
104 from inspect import signature
104 from inspect import signature
105 from io import StringIO
105 from io import StringIO
106 from warnings import warn
106 from warnings import warn
107
107
108 from IPython.utils.decorators import undoc
108 from IPython.utils.decorators import undoc
109 from IPython.utils.py3compat import PYPY
109 from IPython.utils.py3compat import PYPY
110
110
111 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
111 __all__ = ['pretty', 'pprint', 'PrettyPrinter', 'RepresentationPrinter',
112 'for_type', 'for_type_by_name', 'RawText', 'RawStringLiteral', 'CallExpression']
112 'for_type', 'for_type_by_name', 'RawText', 'RawStringLiteral', 'CallExpression']
113
113
114
114
115 MAX_SEQ_LENGTH = 1000
115 MAX_SEQ_LENGTH = 1000
116 _re_pattern_type = type(re.compile(''))
116 _re_pattern_type = type(re.compile(''))
117
117
118 def _safe_getattr(obj, attr, default=None):
118 def _safe_getattr(obj, attr, default=None):
119 """Safe version of getattr.
119 """Safe version of getattr.
120
120
121 Same as getattr, but will return ``default`` on any Exception,
121 Same as getattr, but will return ``default`` on any Exception,
122 rather than raising.
122 rather than raising.
123 """
123 """
124 try:
124 try:
125 return getattr(obj, attr, default)
125 return getattr(obj, attr, default)
126 except Exception:
126 except Exception:
127 return default
127 return default
128
128
129 @undoc
129 @undoc
130 class CUnicodeIO(StringIO):
130 class CUnicodeIO(StringIO):
131 def __init__(self, *args, **kwargs):
131 def __init__(self, *args, **kwargs):
132 super().__init__(*args, **kwargs)
132 super().__init__(*args, **kwargs)
133 warn(("CUnicodeIO is deprecated since IPython 6.0. "
133 warn(("CUnicodeIO is deprecated since IPython 6.0. "
134 "Please use io.StringIO instead."),
134 "Please use io.StringIO instead."),
135 DeprecationWarning, stacklevel=2)
135 DeprecationWarning, stacklevel=2)
136
136
137 def _sorted_for_pprint(items):
137 def _sorted_for_pprint(items):
138 """
138 """
139 Sort the given items for pretty printing. Since some predictable
139 Sort the given items for pretty printing. Since some predictable
140 sorting is better than no sorting at all, we sort on the string
140 sorting is better than no sorting at all, we sort on the string
141 representation if normal sorting fails.
141 representation if normal sorting fails.
142 """
142 """
143 items = list(items)
143 items = list(items)
144 try:
144 try:
145 return sorted(items)
145 return sorted(items)
146 except Exception:
146 except Exception:
147 try:
147 try:
148 return sorted(items, key=str)
148 return sorted(items, key=str)
149 except Exception:
149 except Exception:
150 return items
150 return items
151
151
152 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
152 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
153 """
153 """
154 Pretty print the object's representation.
154 Pretty print the object's representation.
155 """
155 """
156 stream = StringIO()
156 stream = StringIO()
157 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
157 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
158 printer.pretty(obj)
158 printer.pretty(obj)
159 printer.flush()
159 printer.flush()
160 return stream.getvalue()
160 return stream.getvalue()
161
161
162
162
163 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
163 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
164 """
164 """
165 Like `pretty` but print to stdout.
165 Like `pretty` but print to stdout.
166 """
166 """
167 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
167 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
168 printer.pretty(obj)
168 printer.pretty(obj)
169 printer.flush()
169 printer.flush()
170 sys.stdout.write(newline)
170 sys.stdout.write(newline)
171 sys.stdout.flush()
171 sys.stdout.flush()
172
172
173 class _PrettyPrinterBase(object):
173 class _PrettyPrinterBase(object):
174
174
175 @contextmanager
175 @contextmanager
176 def indent(self, indent):
176 def indent(self, indent):
177 """with statement support for indenting/dedenting."""
177 """with statement support for indenting/dedenting."""
178 self.indentation += indent
178 self.indentation += indent
179 try:
179 try:
180 yield
180 yield
181 finally:
181 finally:
182 self.indentation -= indent
182 self.indentation -= indent
183
183
184 @contextmanager
184 @contextmanager
185 def group(self, indent=0, open='', close=''):
185 def group(self, indent=0, open='', close=''):
186 """like begin_group / end_group but for the with statement."""
186 """like begin_group / end_group but for the with statement."""
187 self.begin_group(indent, open)
187 self.begin_group(indent, open)
188 try:
188 try:
189 yield
189 yield
190 finally:
190 finally:
191 self.end_group(indent, close)
191 self.end_group(indent, close)
192
192
193 class PrettyPrinter(_PrettyPrinterBase):
193 class PrettyPrinter(_PrettyPrinterBase):
194 """
194 """
195 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
195 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
196 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
196 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
197 this printer knows nothing about the default pprinters or the `_repr_pretty_`
197 this printer knows nothing about the default pprinters or the `_repr_pretty_`
198 callback method.
198 callback method.
199 """
199 """
200
200
201 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
201 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
202 self.output = output
202 self.output = output
203 self.max_width = max_width
203 self.max_width = max_width
204 self.newline = newline
204 self.newline = newline
205 self.max_seq_length = max_seq_length
205 self.max_seq_length = max_seq_length
206 self.output_width = 0
206 self.output_width = 0
207 self.buffer_width = 0
207 self.buffer_width = 0
208 self.buffer = deque()
208 self.buffer = deque()
209
209
210 root_group = Group(0)
210 root_group = Group(0)
211 self.group_stack = [root_group]
211 self.group_stack = [root_group]
212 self.group_queue = GroupQueue(root_group)
212 self.group_queue = GroupQueue(root_group)
213 self.indentation = 0
213 self.indentation = 0
214
214
215 def _break_one_group(self, group):
215 def _break_one_group(self, group):
216 while group.breakables:
216 while group.breakables:
217 x = self.buffer.popleft()
217 x = self.buffer.popleft()
218 self.output_width = x.output(self.output, self.output_width)
218 self.output_width = x.output(self.output, self.output_width)
219 self.buffer_width -= x.width
219 self.buffer_width -= x.width
220 while self.buffer and isinstance(self.buffer[0], Text):
220 while self.buffer and isinstance(self.buffer[0], Text):
221 x = self.buffer.popleft()
221 x = self.buffer.popleft()
222 self.output_width = x.output(self.output, self.output_width)
222 self.output_width = x.output(self.output, self.output_width)
223 self.buffer_width -= x.width
223 self.buffer_width -= x.width
224
224
225 def _break_outer_groups(self):
225 def _break_outer_groups(self):
226 while self.max_width < self.output_width + self.buffer_width:
226 while self.max_width < self.output_width + self.buffer_width:
227 group = self.group_queue.deq()
227 group = self.group_queue.deq()
228 if not group:
228 if not group:
229 return
229 return
230 self._break_one_group(group)
230 self._break_one_group(group)
231
231
232 def text(self, obj):
232 def text(self, obj):
233 """Add literal text to the output."""
233 """Add literal text to the output."""
234 width = len(obj)
234 width = len(obj)
235 if self.buffer:
235 if self.buffer:
236 text = self.buffer[-1]
236 text = self.buffer[-1]
237 if not isinstance(text, Text):
237 if not isinstance(text, Text):
238 text = Text()
238 text = Text()
239 self.buffer.append(text)
239 self.buffer.append(text)
240 text.add(obj, width)
240 text.add(obj, width)
241 self.buffer_width += width
241 self.buffer_width += width
242 self._break_outer_groups()
242 self._break_outer_groups()
243 else:
243 else:
244 self.output.write(obj)
244 self.output.write(obj)
245 self.output_width += width
245 self.output_width += width
246
246
247 def breakable(self, sep=' '):
247 def breakable(self, sep=' '):
248 """
248 """
249 Add a breakable separator to the output. This does not mean that it
249 Add a breakable separator to the output. This does not mean that it
250 will automatically break here. If no breaking on this position takes
250 will automatically break here. If no breaking on this position takes
251 place the `sep` is inserted which default to one space.
251 place the `sep` is inserted which default to one space.
252 """
252 """
253 width = len(sep)
253 width = len(sep)
254 group = self.group_stack[-1]
254 group = self.group_stack[-1]
255 if group.want_break:
255 if group.want_break:
256 self.flush()
256 self.flush()
257 self.output.write(self.newline)
257 self.output.write(self.newline)
258 self.output.write(' ' * self.indentation)
258 self.output.write(' ' * self.indentation)
259 self.output_width = self.indentation
259 self.output_width = self.indentation
260 self.buffer_width = 0
260 self.buffer_width = 0
261 else:
261 else:
262 self.buffer.append(Breakable(sep, width, self))
262 self.buffer.append(Breakable(sep, width, self))
263 self.buffer_width += width
263 self.buffer_width += width
264 self._break_outer_groups()
264 self._break_outer_groups()
265
265
266 def break_(self):
266 def break_(self):
267 """
267 """
268 Explicitly insert a newline into the output, maintaining correct indentation.
268 Explicitly insert a newline into the output, maintaining correct indentation.
269 """
269 """
270 group = self.group_queue.deq()
270 group = self.group_queue.deq()
271 if group:
271 if group:
272 self._break_one_group(group)
272 self._break_one_group(group)
273 self.flush()
273 self.flush()
274 self.output.write(self.newline)
274 self.output.write(self.newline)
275 self.output.write(' ' * self.indentation)
275 self.output.write(' ' * self.indentation)
276 self.output_width = self.indentation
276 self.output_width = self.indentation
277 self.buffer_width = 0
277 self.buffer_width = 0
278
278
279
279
280 def begin_group(self, indent=0, open=''):
280 def begin_group(self, indent=0, open=''):
281 """
281 """
282 Begin a group.
282 Begin a group.
283 The first parameter specifies the indentation for the next line (usually
283 The first parameter specifies the indentation for the next line (usually
284 the width of the opening text), the second the opening text. All
284 the width of the opening text), the second the opening text. All
285 parameters are optional.
285 parameters are optional.
286 """
286 """
287 if open:
287 if open:
288 self.text(open)
288 self.text(open)
289 group = Group(self.group_stack[-1].depth + 1)
289 group = Group(self.group_stack[-1].depth + 1)
290 self.group_stack.append(group)
290 self.group_stack.append(group)
291 self.group_queue.enq(group)
291 self.group_queue.enq(group)
292 self.indentation += indent
292 self.indentation += indent
293
293
294 def _enumerate(self, seq):
294 def _enumerate(self, seq):
295 """like enumerate, but with an upper limit on the number of items"""
295 """like enumerate, but with an upper limit on the number of items"""
296 for idx, x in enumerate(seq):
296 for idx, x in enumerate(seq):
297 if self.max_seq_length and idx >= self.max_seq_length:
297 if self.max_seq_length and idx >= self.max_seq_length:
298 self.text(',')
298 self.text(',')
299 self.breakable()
299 self.breakable()
300 self.text('...')
300 self.text('...')
301 return
301 return
302 yield idx, x
302 yield idx, x
303
303
304 def end_group(self, dedent=0, close=''):
304 def end_group(self, dedent=0, close=''):
305 """End a group. See `begin_group` for more details."""
305 """End a group. See `begin_group` for more details."""
306 self.indentation -= dedent
306 self.indentation -= dedent
307 group = self.group_stack.pop()
307 group = self.group_stack.pop()
308 if not group.breakables:
308 if not group.breakables:
309 self.group_queue.remove(group)
309 self.group_queue.remove(group)
310 if close:
310 if close:
311 self.text(close)
311 self.text(close)
312
312
313 def flush(self):
313 def flush(self):
314 """Flush data that is left in the buffer."""
314 """Flush data that is left in the buffer."""
315 for data in self.buffer:
315 for data in self.buffer:
316 self.output_width += data.output(self.output, self.output_width)
316 self.output_width += data.output(self.output, self.output_width)
317 self.buffer.clear()
317 self.buffer.clear()
318 self.buffer_width = 0
318 self.buffer_width = 0
319
319
320
320
321 def _get_mro(obj_class):
321 def _get_mro(obj_class):
322 """ Get a reasonable method resolution order of a class and its superclasses
322 """ Get a reasonable method resolution order of a class and its superclasses
323 for both old-style and new-style classes.
323 for both old-style and new-style classes.
324 """
324 """
325 if not hasattr(obj_class, '__mro__'):
325 if not hasattr(obj_class, '__mro__'):
326 # Old-style class. Mix in object to make a fake new-style class.
326 # Old-style class. Mix in object to make a fake new-style class.
327 try:
327 try:
328 obj_class = type(obj_class.__name__, (obj_class, object), {})
328 obj_class = type(obj_class.__name__, (obj_class, object), {})
329 except TypeError:
329 except TypeError:
330 # Old-style extension type that does not descend from object.
330 # Old-style extension type that does not descend from object.
331 # FIXME: try to construct a more thorough MRO.
331 # FIXME: try to construct a more thorough MRO.
332 mro = [obj_class]
332 mro = [obj_class]
333 else:
333 else:
334 mro = obj_class.__mro__[1:-1]
334 mro = obj_class.__mro__[1:-1]
335 else:
335 else:
336 mro = obj_class.__mro__
336 mro = obj_class.__mro__
337 return mro
337 return mro
338
338
339
339
340 class RepresentationPrinter(PrettyPrinter):
340 class RepresentationPrinter(PrettyPrinter):
341 """
341 """
342 Special pretty printer that has a `pretty` method that calls the pretty
342 Special pretty printer that has a `pretty` method that calls the pretty
343 printer for a python object.
343 printer for a python object.
344
344
345 This class stores processing data on `self` so you must *never* use
345 This class stores processing data on `self` so you must *never* use
346 this class in a threaded environment. Always lock it or reinstanciate
346 this class in a threaded environment. Always lock it or reinstanciate
347 it.
347 it.
348
348
349 Instances also have a verbose flag callbacks can access to control their
349 Instances also have a verbose flag callbacks can access to control their
350 output. For example the default instance repr prints all attributes and
350 output. For example the default instance repr prints all attributes and
351 methods that are not prefixed by an underscore if the printer is in
351 methods that are not prefixed by an underscore if the printer is in
352 verbose mode.
352 verbose mode.
353 """
353 """
354
354
355 def __init__(self, output, verbose=False, max_width=79, newline='\n',
355 def __init__(self, output, verbose=False, max_width=79, newline='\n',
356 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
356 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
357 max_seq_length=MAX_SEQ_LENGTH):
357 max_seq_length=MAX_SEQ_LENGTH):
358
358
359 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
359 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
360 self.verbose = verbose
360 self.verbose = verbose
361 self.stack = []
361 self.stack = []
362 if singleton_pprinters is None:
362 if singleton_pprinters is None:
363 singleton_pprinters = _singleton_pprinters.copy()
363 singleton_pprinters = _singleton_pprinters.copy()
364 self.singleton_pprinters = singleton_pprinters
364 self.singleton_pprinters = singleton_pprinters
365 if type_pprinters is None:
365 if type_pprinters is None:
366 type_pprinters = _type_pprinters.copy()
366 type_pprinters = _type_pprinters.copy()
367 self.type_pprinters = type_pprinters
367 self.type_pprinters = type_pprinters
368 if deferred_pprinters is None:
368 if deferred_pprinters is None:
369 deferred_pprinters = _deferred_type_pprinters.copy()
369 deferred_pprinters = _deferred_type_pprinters.copy()
370 self.deferred_pprinters = deferred_pprinters
370 self.deferred_pprinters = deferred_pprinters
371
371
372 def pretty(self, obj):
372 def pretty(self, obj):
373 """Pretty print the given object."""
373 """Pretty print the given object."""
374 obj_id = id(obj)
374 obj_id = id(obj)
375 cycle = obj_id in self.stack
375 cycle = obj_id in self.stack
376 self.stack.append(obj_id)
376 self.stack.append(obj_id)
377 self.begin_group()
377 self.begin_group()
378 try:
378 try:
379 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
379 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
380 # First try to find registered singleton printers for the type.
380 # First try to find registered singleton printers for the type.
381 try:
381 try:
382 printer = self.singleton_pprinters[obj_id]
382 printer = self.singleton_pprinters[obj_id]
383 except (TypeError, KeyError):
383 except (TypeError, KeyError):
384 pass
384 pass
385 else:
385 else:
386 return printer(obj, self, cycle)
386 return printer(obj, self, cycle)
387 # Next walk the mro and check for either:
387 # Next walk the mro and check for either:
388 # 1) a registered printer
388 # 1) a registered printer
389 # 2) a _repr_pretty_ method
389 # 2) a _repr_pretty_ method
390 for cls in _get_mro(obj_class):
390 for cls in _get_mro(obj_class):
391 if cls in self.type_pprinters:
391 if cls in self.type_pprinters:
392 # printer registered in self.type_pprinters
392 # printer registered in self.type_pprinters
393 return self.type_pprinters[cls](obj, self, cycle)
393 return self.type_pprinters[cls](obj, self, cycle)
394 else:
394 else:
395 # deferred printer
395 # deferred printer
396 printer = self._in_deferred_types(cls)
396 printer = self._in_deferred_types(cls)
397 if printer is not None:
397 if printer is not None:
398 return printer(obj, self, cycle)
398 return printer(obj, self, cycle)
399 else:
399 else:
400 # Finally look for special method names.
400 # Finally look for special method names.
401 # Some objects automatically create any requested
401 # Some objects automatically create any requested
402 # attribute. Try to ignore most of them by checking for
402 # attribute. Try to ignore most of them by checking for
403 # callability.
403 # callability.
404 if '_repr_pretty_' in cls.__dict__:
404 if '_repr_pretty_' in cls.__dict__:
405 meth = cls._repr_pretty_
405 meth = cls._repr_pretty_
406 if callable(meth):
406 if callable(meth):
407 return meth(obj, self, cycle)
407 return meth(obj, self, cycle)
408 if cls is not object \
408 if cls is not object \
409 and callable(cls.__dict__.get('__repr__')):
409 and callable(cls.__dict__.get('__repr__')):
410 return _repr_pprint(obj, self, cycle)
410 return _repr_pprint(obj, self, cycle)
411
411
412 return _default_pprint(obj, self, cycle)
412 return _default_pprint(obj, self, cycle)
413 finally:
413 finally:
414 self.end_group()
414 self.end_group()
415 self.stack.pop()
415 self.stack.pop()
416
416
417 def _in_deferred_types(self, cls):
417 def _in_deferred_types(self, cls):
418 """
418 """
419 Check if the given class is specified in the deferred type registry.
419 Check if the given class is specified in the deferred type registry.
420
420
421 Returns the printer from the registry if it exists, and None if the
421 Returns the printer from the registry if it exists, and None if the
422 class is not in the registry. Successful matches will be moved to the
422 class is not in the registry. Successful matches will be moved to the
423 regular type registry for future use.
423 regular type registry for future use.
424 """
424 """
425 mod = _safe_getattr(cls, '__module__', None)
425 mod = _safe_getattr(cls, '__module__', None)
426 name = _safe_getattr(cls, '__name__', None)
426 name = _safe_getattr(cls, '__name__', None)
427 key = (mod, name)
427 key = (mod, name)
428 printer = None
428 printer = None
429 if key in self.deferred_pprinters:
429 if key in self.deferred_pprinters:
430 # Move the printer over to the regular registry.
430 # Move the printer over to the regular registry.
431 printer = self.deferred_pprinters.pop(key)
431 printer = self.deferred_pprinters.pop(key)
432 self.type_pprinters[cls] = printer
432 self.type_pprinters[cls] = printer
433 return printer
433 return printer
434
434
435
435
436 class Printable(object):
436 class Printable(object):
437
437
438 def output(self, stream, output_width):
438 def output(self, stream, output_width):
439 return output_width
439 return output_width
440
440
441
441
442 class Text(Printable):
442 class Text(Printable):
443
443
444 def __init__(self):
444 def __init__(self):
445 self.objs = []
445 self.objs = []
446 self.width = 0
446 self.width = 0
447
447
448 def output(self, stream, output_width):
448 def output(self, stream, output_width):
449 for obj in self.objs:
449 for obj in self.objs:
450 stream.write(obj)
450 stream.write(obj)
451 return output_width + self.width
451 return output_width + self.width
452
452
453 def add(self, obj, width):
453 def add(self, obj, width):
454 self.objs.append(obj)
454 self.objs.append(obj)
455 self.width += width
455 self.width += width
456
456
457
457
458 class Breakable(Printable):
458 class Breakable(Printable):
459
459
460 def __init__(self, seq, width, pretty):
460 def __init__(self, seq, width, pretty):
461 self.obj = seq
461 self.obj = seq
462 self.width = width
462 self.width = width
463 self.pretty = pretty
463 self.pretty = pretty
464 self.indentation = pretty.indentation
464 self.indentation = pretty.indentation
465 self.group = pretty.group_stack[-1]
465 self.group = pretty.group_stack[-1]
466 self.group.breakables.append(self)
466 self.group.breakables.append(self)
467
467
468 def output(self, stream, output_width):
468 def output(self, stream, output_width):
469 self.group.breakables.popleft()
469 self.group.breakables.popleft()
470 if self.group.want_break:
470 if self.group.want_break:
471 stream.write(self.pretty.newline)
471 stream.write(self.pretty.newline)
472 stream.write(' ' * self.indentation)
472 stream.write(' ' * self.indentation)
473 return self.indentation
473 return self.indentation
474 if not self.group.breakables:
474 if not self.group.breakables:
475 self.pretty.group_queue.remove(self.group)
475 self.pretty.group_queue.remove(self.group)
476 stream.write(self.obj)
476 stream.write(self.obj)
477 return output_width + self.width
477 return output_width + self.width
478
478
479
479
480 class Group(Printable):
480 class Group(Printable):
481
481
482 def __init__(self, depth):
482 def __init__(self, depth):
483 self.depth = depth
483 self.depth = depth
484 self.breakables = deque()
484 self.breakables = deque()
485 self.want_break = False
485 self.want_break = False
486
486
487
487
488 class GroupQueue(object):
488 class GroupQueue(object):
489
489
490 def __init__(self, *groups):
490 def __init__(self, *groups):
491 self.queue = []
491 self.queue = []
492 for group in groups:
492 for group in groups:
493 self.enq(group)
493 self.enq(group)
494
494
495 def enq(self, group):
495 def enq(self, group):
496 depth = group.depth
496 depth = group.depth
497 while depth > len(self.queue) - 1:
497 while depth > len(self.queue) - 1:
498 self.queue.append([])
498 self.queue.append([])
499 self.queue[depth].append(group)
499 self.queue[depth].append(group)
500
500
501 def deq(self):
501 def deq(self):
502 for stack in self.queue:
502 for stack in self.queue:
503 for idx, group in enumerate(reversed(stack)):
503 for idx, group in enumerate(reversed(stack)):
504 if group.breakables:
504 if group.breakables:
505 del stack[idx]
505 del stack[idx]
506 group.want_break = True
506 group.want_break = True
507 return group
507 return group
508 for group in stack:
508 for group in stack:
509 group.want_break = True
509 group.want_break = True
510 del stack[:]
510 del stack[:]
511
511
512 def remove(self, group):
512 def remove(self, group):
513 try:
513 try:
514 self.queue[group.depth].remove(group)
514 self.queue[group.depth].remove(group)
515 except ValueError:
515 except ValueError:
516 pass
516 pass
517
517
518
518
519 class RawText:
519 class RawText:
520 """ Object such that ``p.pretty(RawText(value))`` is the same as ``p.text(value)``.
520 """ Object such that ``p.pretty(RawText(value))`` is the same as ``p.text(value)``.
521
521
522 An example usage of this would be to show a list as binary numbers, using
522 An example usage of this would be to show a list as binary numbers, using
523 ``p.pretty([RawText(bin(i)) for i in integers])``.
523 ``p.pretty([RawText(bin(i)) for i in integers])``.
524 """
524 """
525 def __init__(self, value):
525 def __init__(self, value):
526 self.value = value
526 self.value = value
527
527
528 def _repr_pretty_(self, p, cycle):
528 def _repr_pretty_(self, p, cycle):
529 p.text(self.value)
529 p.text(self.value)
530
530
531
531
532 class CallExpression:
532 class CallExpression:
533 """ Object which emits a line-wrapped call expression in the form `__name(*args, **kwargs)` """
533 """ Object which emits a line-wrapped call expression in the form `__name(*args, **kwargs)` """
534 def __init__(__self, __name, *args, **kwargs):
534 def __init__(__self, __name, *args, **kwargs):
535 # dunders are to avoid clashes with kwargs, as python's name manging
535 # dunders are to avoid clashes with kwargs, as python's name manging
536 # will kick in.
536 # will kick in.
537 self = __self
537 self = __self
538 self.name = __name
538 self.name = __name
539 self.args = args
539 self.args = args
540 self.kwargs = kwargs
540 self.kwargs = kwargs
541
541
542 @classmethod
542 @classmethod
543 def factory(cls, name):
543 def factory(cls, name):
544 def inner(*args, **kwargs):
544 def inner(*args, **kwargs):
545 return cls(name, *args, **kwargs)
545 return cls(name, *args, **kwargs)
546 return inner
546 return inner
547
547
548 def _repr_pretty_(self, p, cycle):
548 def _repr_pretty_(self, p, cycle):
549 # dunders are to avoid clashes with kwargs, as python's name manging
549 # dunders are to avoid clashes with kwargs, as python's name manging
550 # will kick in.
550 # will kick in.
551
551
552 started = False
552 started = False
553 def new_item():
553 def new_item():
554 nonlocal started
554 nonlocal started
555 if started:
555 if started:
556 p.text(",")
556 p.text(",")
557 p.breakable()
557 p.breakable()
558 started = True
558 started = True
559
559
560 prefix = self.name + "("
560 prefix = self.name + "("
561 with p.group(len(prefix), prefix, ")"):
561 with p.group(len(prefix), prefix, ")"):
562 for arg in self.args:
562 for arg in self.args:
563 new_item()
563 new_item()
564 p.pretty(arg)
564 p.pretty(arg)
565 for arg_name, arg in self.kwargs.items():
565 for arg_name, arg in self.kwargs.items():
566 new_item()
566 new_item()
567 arg_prefix = arg_name + "="
567 arg_prefix = arg_name + "="
568 with p.group(len(arg_prefix), arg_prefix):
568 with p.group(len(arg_prefix), arg_prefix):
569 p.pretty(arg)
569 p.pretty(arg)
570
570
571
571
572 class RawStringLiteral:
572 class RawStringLiteral:
573 """ Wrapper that shows a string with a `r` prefix """
573 """ Wrapper that shows a string with a `r` prefix """
574 def __init__(self, value):
574 def __init__(self, value):
575 self.value = value
575 self.value = value
576
576
577 def _repr_pretty_(self, p, cycle):
577 def _repr_pretty_(self, p, cycle):
578 base_repr = repr(self.value)
578 base_repr = repr(self.value)
579 if base_repr[:1] in 'uU':
579 if base_repr[:1] in 'uU':
580 base_repr = base_repr[1:]
580 base_repr = base_repr[1:]
581 prefix = 'ur'
581 prefix = 'ur'
582 else:
582 else:
583 prefix = 'r'
583 prefix = 'r'
584 base_repr = prefix + base_repr.replace('\\\\', '\\')
584 base_repr = prefix + base_repr.replace('\\\\', '\\')
585 p.text(base_repr)
585 p.text(base_repr)
586
586
587
587
588 def _default_pprint(obj, p, cycle):
588 def _default_pprint(obj, p, cycle):
589 """
589 """
590 The default print function. Used if an object does not provide one and
590 The default print function. Used if an object does not provide one and
591 it's none of the builtin objects.
591 it's none of the builtin objects.
592 """
592 """
593 klass = _safe_getattr(obj, '__class__', None) or type(obj)
593 klass = _safe_getattr(obj, '__class__', None) or type(obj)
594 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
594 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
595 # A user-provided repr. Find newlines and replace them with p.break_()
595 # A user-provided repr. Find newlines and replace them with p.break_()
596 _repr_pprint(obj, p, cycle)
596 _repr_pprint(obj, p, cycle)
597 return
597 return
598 p.begin_group(1, '<')
598 p.begin_group(1, '<')
599 p.pretty(klass)
599 p.pretty(klass)
600 p.text(' at 0x%x' % id(obj))
600 p.text(' at 0x%x' % id(obj))
601 if cycle:
601 if cycle:
602 p.text(' ...')
602 p.text(' ...')
603 elif p.verbose:
603 elif p.verbose:
604 first = True
604 first = True
605 for key in dir(obj):
605 for key in dir(obj):
606 if not key.startswith('_'):
606 if not key.startswith('_'):
607 try:
607 try:
608 value = getattr(obj, key)
608 value = getattr(obj, key)
609 except AttributeError:
609 except AttributeError:
610 continue
610 continue
611 if isinstance(value, types.MethodType):
611 if isinstance(value, types.MethodType):
612 continue
612 continue
613 if not first:
613 if not first:
614 p.text(',')
614 p.text(',')
615 p.breakable()
615 p.breakable()
616 p.text(key)
616 p.text(key)
617 p.text('=')
617 p.text('=')
618 step = len(key) + 1
618 step = len(key) + 1
619 p.indentation += step
619 p.indentation += step
620 p.pretty(value)
620 p.pretty(value)
621 p.indentation -= step
621 p.indentation -= step
622 first = False
622 first = False
623 p.end_group(1, '>')
623 p.end_group(1, '>')
624
624
625
625
626 def _seq_pprinter_factory(start, end):
626 def _seq_pprinter_factory(start, end):
627 """
627 """
628 Factory that returns a pprint function useful for sequences. Used by
628 Factory that returns a pprint function useful for sequences. Used by
629 the default pprint for tuples and lists.
629 the default pprint for tuples and lists.
630 """
630 """
631 def inner(obj, p, cycle):
631 def inner(obj, p, cycle):
632 if cycle:
632 if cycle:
633 return p.text(start + '...' + end)
633 return p.text(start + '...' + end)
634 step = len(start)
634 step = len(start)
635 p.begin_group(step, start)
635 p.begin_group(step, start)
636 for idx, x in p._enumerate(obj):
636 for idx, x in p._enumerate(obj):
637 if idx:
637 if idx:
638 p.text(',')
638 p.text(',')
639 p.breakable()
639 p.breakable()
640 p.pretty(x)
640 p.pretty(x)
641 if len(obj) == 1 and isinstance(obj, tuple):
641 if len(obj) == 1 and isinstance(obj, tuple):
642 # Special case for 1-item tuples.
642 # Special case for 1-item tuples.
643 p.text(',')
643 p.text(',')
644 p.end_group(step, end)
644 p.end_group(step, end)
645 return inner
645 return inner
646
646
647
647
648 def _set_pprinter_factory(start, end):
648 def _set_pprinter_factory(start, end):
649 """
649 """
650 Factory that returns a pprint function useful for sets and frozensets.
650 Factory that returns a pprint function useful for sets and frozensets.
651 """
651 """
652 def inner(obj, p, cycle):
652 def inner(obj, p, cycle):
653 if cycle:
653 if cycle:
654 return p.text(start + '...' + end)
654 return p.text(start + '...' + end)
655 if len(obj) == 0:
655 if len(obj) == 0:
656 # Special case.
656 # Special case.
657 p.text(type(obj).__name__ + '()')
657 p.text(type(obj).__name__ + '()')
658 else:
658 else:
659 step = len(start)
659 step = len(start)
660 p.begin_group(step, start)
660 p.begin_group(step, start)
661 # Like dictionary keys, we will try to sort the items if there aren't too many
661 # Like dictionary keys, we will try to sort the items if there aren't too many
662 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
662 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
663 items = _sorted_for_pprint(obj)
663 items = _sorted_for_pprint(obj)
664 else:
664 else:
665 items = obj
665 items = obj
666 for idx, x in p._enumerate(items):
666 for idx, x in p._enumerate(items):
667 if idx:
667 if idx:
668 p.text(',')
668 p.text(',')
669 p.breakable()
669 p.breakable()
670 p.pretty(x)
670 p.pretty(x)
671 p.end_group(step, end)
671 p.end_group(step, end)
672 return inner
672 return inner
673
673
674
674
675 def _dict_pprinter_factory(start, end):
675 def _dict_pprinter_factory(start, end):
676 """
676 """
677 Factory that returns a pprint function used by the default pprint of
677 Factory that returns a pprint function used by the default pprint of
678 dicts and dict proxies.
678 dicts and dict proxies.
679 """
679 """
680 def inner(obj, p, cycle):
680 def inner(obj, p, cycle):
681 if cycle:
681 if cycle:
682 return p.text('{...}')
682 return p.text('{...}')
683 step = len(start)
683 step = len(start)
684 p.begin_group(step, start)
684 p.begin_group(step, start)
685 keys = obj.keys()
685 keys = obj.keys()
686 for idx, key in p._enumerate(keys):
686 for idx, key in p._enumerate(keys):
687 if idx:
687 if idx:
688 p.text(',')
688 p.text(',')
689 p.breakable()
689 p.breakable()
690 p.pretty(key)
690 p.pretty(key)
691 p.text(': ')
691 p.text(': ')
692 p.pretty(obj[key])
692 p.pretty(obj[key])
693 p.end_group(step, end)
693 p.end_group(step, end)
694 return inner
694 return inner
695
695
696
696
697 def _super_pprint(obj, p, cycle):
697 def _super_pprint(obj, p, cycle):
698 """The pprint for the super type."""
698 """The pprint for the super type."""
699 p.begin_group(8, '<super: ')
699 p.begin_group(8, '<super: ')
700 p.pretty(obj.__thisclass__)
700 p.pretty(obj.__thisclass__)
701 p.text(',')
701 p.text(',')
702 p.breakable()
702 p.breakable()
703 if PYPY: # In PyPy, super() objects don't have __self__ attributes
703 if PYPY: # In PyPy, super() objects don't have __self__ attributes
704 dself = obj.__repr__.__self__
704 dself = obj.__repr__.__self__
705 p.pretty(None if dself is obj else dself)
705 p.pretty(None if dself is obj else dself)
706 else:
706 else:
707 p.pretty(obj.__self__)
707 p.pretty(obj.__self__)
708 p.end_group(8, '>')
708 p.end_group(8, '>')
709
709
710
710
711
711
712 class _ReFlags:
712 class _ReFlags:
713 def __init__(self, value):
713 def __init__(self, value):
714 self.value = value
714 self.value = value
715
715
716 def _repr_pretty_(self, p, cycle):
716 def _repr_pretty_(self, p, cycle):
717 done_one = False
717 done_one = False
718 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
718 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
719 'UNICODE', 'VERBOSE', 'DEBUG'):
719 'UNICODE', 'VERBOSE', 'DEBUG'):
720 if self.value & getattr(re, flag):
720 if self.value & getattr(re, flag):
721 if done_one:
721 if done_one:
722 p.text('|')
722 p.text('|')
723 p.text('re.' + flag)
723 p.text('re.' + flag)
724 done_one = True
724 done_one = True
725
725
726
726
727 def _re_pattern_pprint(obj, p, cycle):
727 def _re_pattern_pprint(obj, p, cycle):
728 """The pprint function for regular expression patterns."""
728 """The pprint function for regular expression patterns."""
729 re_compile = CallExpression.factory('re.compile')
729 re_compile = CallExpression.factory('re.compile')
730 if obj.flags:
730 if obj.flags:
731 p.pretty(re_compile(RawStringLiteral(obj.pattern), _ReFlags(obj.flags)))
731 p.pretty(re_compile(RawStringLiteral(obj.pattern), _ReFlags(obj.flags)))
732 else:
732 else:
733 p.pretty(re_compile(RawStringLiteral(obj.pattern)))
733 p.pretty(re_compile(RawStringLiteral(obj.pattern)))
734
734
735
735
736 def _types_simplenamespace_pprint(obj, p, cycle):
736 def _types_simplenamespace_pprint(obj, p, cycle):
737 """The pprint function for types.SimpleNamespace."""
737 """The pprint function for types.SimpleNamespace."""
738 namespace = CallExpression.factory('namespace')
738 namespace = CallExpression.factory('namespace')
739 if cycle:
739 if cycle:
740 p.pretty(namespace(RawText("...")))
740 p.pretty(namespace(RawText("...")))
741 else:
741 else:
742 p.pretty(namespace(**obj.__dict__))
742 p.pretty(namespace(**obj.__dict__))
743
743
744
744
745 def _type_pprint(obj, p, cycle):
745 def _type_pprint(obj, p, cycle):
746 """The pprint for classes and types."""
746 """The pprint for classes and types."""
747 # Heap allocated types might not have the module attribute,
747 # Heap allocated types might not have the module attribute,
748 # and others may set it to None.
748 # and others may set it to None.
749
749
750 # Checks for a __repr__ override in the metaclass. Can't compare the
750 # Checks for a __repr__ override in the metaclass. Can't compare the
751 # type(obj).__repr__ directly because in PyPy the representation function
751 # type(obj).__repr__ directly because in PyPy the representation function
752 # inherited from type isn't the same type.__repr__
752 # inherited from type isn't the same type.__repr__
753 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
753 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
754 _repr_pprint(obj, p, cycle)
754 _repr_pprint(obj, p, cycle)
755 return
755 return
756
756
757 mod = _safe_getattr(obj, '__module__', None)
757 mod = _safe_getattr(obj, '__module__', None)
758 try:
758 try:
759 name = obj.__qualname__
759 name = obj.__qualname__
760 if not isinstance(name, str):
760 if not isinstance(name, str):
761 # This can happen if the type implements __qualname__ as a property
761 # This can happen if the type implements __qualname__ as a property
762 # or other descriptor in Python 2.
762 # or other descriptor in Python 2.
763 raise Exception("Try __name__")
763 raise Exception("Try __name__")
764 except Exception:
764 except Exception:
765 name = obj.__name__
765 name = obj.__name__
766 if not isinstance(name, str):
766 if not isinstance(name, str):
767 name = '<unknown type>'
767 name = '<unknown type>'
768
768
769 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
769 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
770 p.text(name)
770 p.text(name)
771 else:
771 else:
772 p.text(mod + '.' + name)
772 p.text(mod + '.' + name)
773
773
774
774
775 def _repr_pprint(obj, p, cycle):
775 def _repr_pprint(obj, p, cycle):
776 """A pprint that just redirects to the normal repr function."""
776 """A pprint that just redirects to the normal repr function."""
777 # Find newlines and replace them with p.break_()
777 # Find newlines and replace them with p.break_()
778 output = repr(obj)
778 output = repr(obj)
779 lines = output.splitlines()
779 lines = output.splitlines()
780 with p.group():
780 with p.group():
781 for idx, output_line in enumerate(lines):
781 for idx, output_line in enumerate(lines):
782 if idx:
782 if idx:
783 p.break_()
783 p.break_()
784 p.text(output_line)
784 p.text(output_line)
785
785
786
786
787 def _function_pprint(obj, p, cycle):
787 def _function_pprint(obj, p, cycle):
788 """Base pprint for all functions and builtin functions."""
788 """Base pprint for all functions and builtin functions."""
789 name = _safe_getattr(obj, '__qualname__', obj.__name__)
789 name = _safe_getattr(obj, '__qualname__', obj.__name__)
790 mod = obj.__module__
790 mod = obj.__module__
791 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
791 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
792 name = mod + '.' + name
792 name = mod + '.' + name
793 try:
793 try:
794 func_def = name + str(signature(obj))
794 func_def = name + str(signature(obj))
795 except ValueError:
795 except ValueError:
796 func_def = name
796 func_def = name
797 p.text('<function %s>' % func_def)
797 p.text('<function %s>' % func_def)
798
798
799
799
800 def _exception_pprint(obj, p, cycle):
800 def _exception_pprint(obj, p, cycle):
801 """Base pprint for all exceptions."""
801 """Base pprint for all exceptions."""
802 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
802 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
803 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
803 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
804 name = '%s.%s' % (obj.__class__.__module__, name)
804 name = '%s.%s' % (obj.__class__.__module__, name)
805
805
806 p.pretty(CallExpression(name, *getattr(obj, 'args', ())))
806 p.pretty(CallExpression(name, *getattr(obj, 'args', ())))
807
807
808
808
809 #: the exception base
809 #: the exception base
810 try:
810 try:
811 _exception_base = BaseException
811 _exception_base = BaseException
812 except NameError:
812 except NameError:
813 _exception_base = Exception
813 _exception_base = Exception
814
814
815
815
816 #: printers for builtin types
816 #: printers for builtin types
817 _type_pprinters = {
817 _type_pprinters = {
818 int: _repr_pprint,
818 int: _repr_pprint,
819 float: _repr_pprint,
819 float: _repr_pprint,
820 str: _repr_pprint,
820 str: _repr_pprint,
821 tuple: _seq_pprinter_factory('(', ')'),
821 tuple: _seq_pprinter_factory('(', ')'),
822 list: _seq_pprinter_factory('[', ']'),
822 list: _seq_pprinter_factory('[', ']'),
823 dict: _dict_pprinter_factory('{', '}'),
823 dict: _dict_pprinter_factory('{', '}'),
824 set: _set_pprinter_factory('{', '}'),
824 set: _set_pprinter_factory('{', '}'),
825 frozenset: _set_pprinter_factory('frozenset({', '})'),
825 frozenset: _set_pprinter_factory('frozenset({', '})'),
826 super: _super_pprint,
826 super: _super_pprint,
827 _re_pattern_type: _re_pattern_pprint,
827 _re_pattern_type: _re_pattern_pprint,
828 type: _type_pprint,
828 type: _type_pprint,
829 types.FunctionType: _function_pprint,
829 types.FunctionType: _function_pprint,
830 types.BuiltinFunctionType: _function_pprint,
830 types.BuiltinFunctionType: _function_pprint,
831 types.MethodType: _repr_pprint,
831 types.MethodType: _repr_pprint,
832 types.SimpleNamespace: _types_simplenamespace_pprint,
832 types.SimpleNamespace: _types_simplenamespace_pprint,
833 datetime.datetime: _repr_pprint,
833 datetime.datetime: _repr_pprint,
834 datetime.timedelta: _repr_pprint,
834 datetime.timedelta: _repr_pprint,
835 _exception_base: _exception_pprint
835 _exception_base: _exception_pprint
836 }
836 }
837
837
838 # render os.environ like a dict
838 # render os.environ like a dict
839 _env_type = type(os.environ)
839 _env_type = type(os.environ)
840 # future-proof in case os.environ becomes a plain dict?
840 # future-proof in case os.environ becomes a plain dict?
841 if _env_type is not dict:
841 if _env_type is not dict:
842 _type_pprinters[_env_type] = _dict_pprinter_factory('environ{', '}')
842 _type_pprinters[_env_type] = _dict_pprinter_factory('environ{', '}')
843
843
844 try:
844 try:
845 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
845 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
846 # using dict.setdefault avoids overwriting the dict printer
846 # using dict.setdefault avoids overwriting the dict printer
847 _type_pprinters.setdefault(types.DictProxyType,
847 _type_pprinters.setdefault(types.DictProxyType,
848 _dict_pprinter_factory('dict_proxy({', '})'))
848 _dict_pprinter_factory('dict_proxy({', '})'))
849 _type_pprinters[types.ClassType] = _type_pprint
849 _type_pprinters[types.ClassType] = _type_pprint
850 _type_pprinters[types.SliceType] = _repr_pprint
850 _type_pprinters[types.SliceType] = _repr_pprint
851 except AttributeError: # Python 3
851 except AttributeError: # Python 3
852 _type_pprinters[types.MappingProxyType] = \
852 _type_pprinters[types.MappingProxyType] = \
853 _dict_pprinter_factory('mappingproxy({', '})')
853 _dict_pprinter_factory('mappingproxy({', '})')
854 _type_pprinters[slice] = _repr_pprint
854 _type_pprinters[slice] = _repr_pprint
855
855
856 _type_pprinters[range] = _repr_pprint
856 _type_pprinters[range] = _repr_pprint
857 _type_pprinters[bytes] = _repr_pprint
857 _type_pprinters[bytes] = _repr_pprint
858
858
859 #: printers for types specified by name
859 #: printers for types specified by name
860 _deferred_type_pprinters = {
860 _deferred_type_pprinters = {
861 }
861 }
862
862
863 def for_type(typ, func):
863 def for_type(typ, func):
864 """
864 """
865 Add a pretty printer for a given type.
865 Add a pretty printer for a given type.
866 """
866 """
867 oldfunc = _type_pprinters.get(typ, None)
867 oldfunc = _type_pprinters.get(typ, None)
868 if func is not None:
868 if func is not None:
869 # To support easy restoration of old pprinters, we need to ignore Nones.
869 # To support easy restoration of old pprinters, we need to ignore Nones.
870 _type_pprinters[typ] = func
870 _type_pprinters[typ] = func
871 return oldfunc
871 return oldfunc
872
872
873 def for_type_by_name(type_module, type_name, func):
873 def for_type_by_name(type_module, type_name, func):
874 """
874 """
875 Add a pretty printer for a type specified by the module and name of a type
875 Add a pretty printer for a type specified by the module and name of a type
876 rather than the type object itself.
876 rather than the type object itself.
877 """
877 """
878 key = (type_module, type_name)
878 key = (type_module, type_name)
879 oldfunc = _deferred_type_pprinters.get(key, None)
879 oldfunc = _deferred_type_pprinters.get(key, None)
880 if func is not None:
880 if func is not None:
881 # To support easy restoration of old pprinters, we need to ignore Nones.
881 # To support easy restoration of old pprinters, we need to ignore Nones.
882 _deferred_type_pprinters[key] = func
882 _deferred_type_pprinters[key] = func
883 return oldfunc
883 return oldfunc
884
884
885
885
886 #: printers for the default singletons
886 #: printers for the default singletons
887 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
887 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
888 NotImplemented]), _repr_pprint)
888 NotImplemented]), _repr_pprint)
889
889
890
890
891 def _defaultdict_pprint(obj, p, cycle):
891 def _defaultdict_pprint(obj, p, cycle):
892 cls_ctor = CallExpression.factory(obj.__class__.__name__)
892 cls_ctor = CallExpression.factory(obj.__class__.__name__)
893 if cycle:
893 if cycle:
894 p.pretty(cls_ctor(RawText("...")))
894 p.pretty(cls_ctor(RawText("...")))
895 else:
895 else:
896 p.pretty(cls_ctor(obj.default_factory, dict(obj)))
896 p.pretty(cls_ctor(obj.default_factory, dict(obj)))
897
897
898 def _ordereddict_pprint(obj, p, cycle):
898 def _ordereddict_pprint(obj, p, cycle):
899 cls_ctor = CallExpression.factory(obj.__class__.__name__)
899 cls_ctor = CallExpression.factory(obj.__class__.__name__)
900 if cycle:
900 if cycle:
901 p.pretty(cls_ctor(RawText("...")))
901 p.pretty(cls_ctor(RawText("...")))
902 elif len(obj):
902 elif len(obj):
903 p.pretty(cls_ctor(list(obj.items())))
903 p.pretty(cls_ctor(list(obj.items())))
904 else:
904 else:
905 p.pretty(cls_ctor())
905 p.pretty(cls_ctor())
906
906
907 def _deque_pprint(obj, p, cycle):
907 def _deque_pprint(obj, p, cycle):
908 cls_ctor = CallExpression.factory(obj.__class__.__name__)
908 cls_ctor = CallExpression.factory(obj.__class__.__name__)
909 if cycle:
909 if cycle:
910 p.pretty(cls_ctor(RawText("...")))
910 p.pretty(cls_ctor(RawText("...")))
911 elif obj.maxlen is not None:
911 elif obj.maxlen is not None:
912 p.pretty(cls_ctor(list(obj), maxlen=obj.maxlen))
912 p.pretty(cls_ctor(list(obj), maxlen=obj.maxlen))
913 else:
913 else:
914 p.pretty(cls_ctor(list(obj)))
914 p.pretty(cls_ctor(list(obj)))
915
915
916 def _counter_pprint(obj, p, cycle):
916 def _counter_pprint(obj, p, cycle):
917 cls_ctor = CallExpression.factory(obj.__class__.__name__)
917 cls_ctor = CallExpression.factory(obj.__class__.__name__)
918 if cycle:
918 if cycle:
919 p.pretty(cls_ctor(RawText("...")))
919 p.pretty(cls_ctor(RawText("...")))
920 elif len(obj):
920 elif len(obj):
921 p.pretty(cls_ctor(dict(obj)))
921 p.pretty(cls_ctor(dict(sorted(obj.items(), key=lambda x: x[1], reverse=True))))
922 else:
922 else:
923 p.pretty(cls_ctor())
923 p.pretty(cls_ctor())
924
924
925
925
926 def _userlist_pprint(obj, p, cycle):
926 def _userlist_pprint(obj, p, cycle):
927 cls_ctor = CallExpression.factory(obj.__class__.__name__)
927 cls_ctor = CallExpression.factory(obj.__class__.__name__)
928 if cycle:
928 if cycle:
929 p.pretty(cls_ctor(RawText("...")))
929 p.pretty(cls_ctor(RawText("...")))
930 else:
930 else:
931 p.pretty(cls_ctor(obj.data))
931 p.pretty(cls_ctor(obj.data))
932
932
933
933
934 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
934 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
935 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
935 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
936 for_type_by_name('collections', 'deque', _deque_pprint)
936 for_type_by_name('collections', 'deque', _deque_pprint)
937 for_type_by_name('collections', 'Counter', _counter_pprint)
937 for_type_by_name('collections', 'Counter', _counter_pprint)
938 for_type_by_name("collections", "UserList", _userlist_pprint)
938 for_type_by_name("collections", "UserList", _userlist_pprint)
939
939
940 if __name__ == '__main__':
940 if __name__ == '__main__':
941 from random import randrange
941 from random import randrange
942 class Foo(object):
942 class Foo(object):
943 def __init__(self):
943 def __init__(self):
944 self.foo = 1
944 self.foo = 1
945 self.bar = re.compile(r'\s+')
945 self.bar = re.compile(r'\s+')
946 self.blub = dict.fromkeys(range(30), randrange(1, 40))
946 self.blub = dict.fromkeys(range(30), randrange(1, 40))
947 self.hehe = 23424.234234
947 self.hehe = 23424.234234
948 self.list = ["blub", "blah", self]
948 self.list = ["blub", "blah", self]
949
949
950 def get_foo(self):
950 def get_foo(self):
951 print("foo")
951 print("foo")
952
952
953 pprint(Foo(), verbose=True)
953 pprint(Foo(), verbose=True)
@@ -1,539 +1,540 b''
1 # coding: utf-8
1 # coding: utf-8
2 """Tests for IPython.lib.pretty."""
2 """Tests for IPython.lib.pretty."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from collections import Counter, defaultdict, deque, OrderedDict, UserList
8 from collections import Counter, defaultdict, deque, OrderedDict, UserList
9 import os
9 import os
10 import pytest
10 import pytest
11 import types
11 import types
12 import string
12 import string
13 import sys
13 import sys
14 import unittest
14 import unittest
15
15
16 import pytest
16 import pytest
17
17
18 from IPython.lib import pretty
18 from IPython.lib import pretty
19
19
20 from io import StringIO
20 from io import StringIO
21
21
22
22
23 class MyList(object):
23 class MyList(object):
24 def __init__(self, content):
24 def __init__(self, content):
25 self.content = content
25 self.content = content
26 def _repr_pretty_(self, p, cycle):
26 def _repr_pretty_(self, p, cycle):
27 if cycle:
27 if cycle:
28 p.text("MyList(...)")
28 p.text("MyList(...)")
29 else:
29 else:
30 with p.group(3, "MyList(", ")"):
30 with p.group(3, "MyList(", ")"):
31 for (i, child) in enumerate(self.content):
31 for (i, child) in enumerate(self.content):
32 if i:
32 if i:
33 p.text(",")
33 p.text(",")
34 p.breakable()
34 p.breakable()
35 else:
35 else:
36 p.breakable("")
36 p.breakable("")
37 p.pretty(child)
37 p.pretty(child)
38
38
39
39
40 class MyDict(dict):
40 class MyDict(dict):
41 def _repr_pretty_(self, p, cycle):
41 def _repr_pretty_(self, p, cycle):
42 p.text("MyDict(...)")
42 p.text("MyDict(...)")
43
43
44 class MyObj(object):
44 class MyObj(object):
45 def somemethod(self):
45 def somemethod(self):
46 pass
46 pass
47
47
48
48
49 class Dummy1(object):
49 class Dummy1(object):
50 def _repr_pretty_(self, p, cycle):
50 def _repr_pretty_(self, p, cycle):
51 p.text("Dummy1(...)")
51 p.text("Dummy1(...)")
52
52
53 class Dummy2(Dummy1):
53 class Dummy2(Dummy1):
54 _repr_pretty_ = None
54 _repr_pretty_ = None
55
55
56 class NoModule(object):
56 class NoModule(object):
57 pass
57 pass
58
58
59 NoModule.__module__ = None
59 NoModule.__module__ = None
60
60
61 class Breaking(object):
61 class Breaking(object):
62 def _repr_pretty_(self, p, cycle):
62 def _repr_pretty_(self, p, cycle):
63 with p.group(4,"TG: ",":"):
63 with p.group(4,"TG: ",":"):
64 p.text("Breaking(")
64 p.text("Breaking(")
65 p.break_()
65 p.break_()
66 p.text(")")
66 p.text(")")
67
67
68 class BreakingRepr(object):
68 class BreakingRepr(object):
69 def __repr__(self):
69 def __repr__(self):
70 return "Breaking(\n)"
70 return "Breaking(\n)"
71
71
72 class BadRepr(object):
72 class BadRepr(object):
73 def __repr__(self):
73 def __repr__(self):
74 return 1/0
74 return 1/0
75
75
76
76
77 def test_indentation():
77 def test_indentation():
78 """Test correct indentation in groups"""
78 """Test correct indentation in groups"""
79 count = 40
79 count = 40
80 gotoutput = pretty.pretty(MyList(range(count)))
80 gotoutput = pretty.pretty(MyList(range(count)))
81 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
81 expectedoutput = "MyList(\n" + ",\n".join(" %d" % i for i in range(count)) + ")"
82
82
83 assert gotoutput == expectedoutput
83 assert gotoutput == expectedoutput
84
84
85
85
86 def test_dispatch():
86 def test_dispatch():
87 """
87 """
88 Test correct dispatching: The _repr_pretty_ method for MyDict
88 Test correct dispatching: The _repr_pretty_ method for MyDict
89 must be found before the registered printer for dict.
89 must be found before the registered printer for dict.
90 """
90 """
91 gotoutput = pretty.pretty(MyDict())
91 gotoutput = pretty.pretty(MyDict())
92 expectedoutput = "MyDict(...)"
92 expectedoutput = "MyDict(...)"
93
93
94 assert gotoutput == expectedoutput
94 assert gotoutput == expectedoutput
95
95
96
96
97 def test_callability_checking():
97 def test_callability_checking():
98 """
98 """
99 Test that the _repr_pretty_ method is tested for callability and skipped if
99 Test that the _repr_pretty_ method is tested for callability and skipped if
100 not.
100 not.
101 """
101 """
102 gotoutput = pretty.pretty(Dummy2())
102 gotoutput = pretty.pretty(Dummy2())
103 expectedoutput = "Dummy1(...)"
103 expectedoutput = "Dummy1(...)"
104
104
105 assert gotoutput == expectedoutput
105 assert gotoutput == expectedoutput
106
106
107
107
108 @pytest.mark.parametrize(
108 @pytest.mark.parametrize(
109 "obj,expected_output",
109 "obj,expected_output",
110 zip(
110 zip(
111 [
111 [
112 set(),
112 set(),
113 frozenset(),
113 frozenset(),
114 set([1]),
114 set([1]),
115 frozenset([1]),
115 frozenset([1]),
116 set([1, 2]),
116 set([1, 2]),
117 frozenset([1, 2]),
117 frozenset([1, 2]),
118 set([-1, -2, -3]),
118 set([-1, -2, -3]),
119 ],
119 ],
120 [
120 [
121 "set()",
121 "set()",
122 "frozenset()",
122 "frozenset()",
123 "{1}",
123 "{1}",
124 "frozenset({1})",
124 "frozenset({1})",
125 "{1, 2}",
125 "{1, 2}",
126 "frozenset({1, 2})",
126 "frozenset({1, 2})",
127 "{-3, -2, -1}",
127 "{-3, -2, -1}",
128 ],
128 ],
129 ),
129 ),
130 )
130 )
131 def test_sets(obj, expected_output):
131 def test_sets(obj, expected_output):
132 """
132 """
133 Test that set and frozenset use Python 3 formatting.
133 Test that set and frozenset use Python 3 formatting.
134 """
134 """
135 got_output = pretty.pretty(obj)
135 got_output = pretty.pretty(obj)
136 assert got_output == expected_output
136 assert got_output == expected_output
137
137
138
138
139 def test_pprint_heap_allocated_type():
139 def test_pprint_heap_allocated_type():
140 """
140 """
141 Test that pprint works for heap allocated types.
141 Test that pprint works for heap allocated types.
142 """
142 """
143 module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35"
143 module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35"
144 expected_output = (
144 expected_output = (
145 "xxlimited.Null" if sys.version_info < (3, 10, 6) else "xxlimited_35.Null"
145 "xxlimited.Null" if sys.version_info < (3, 10, 6) else "xxlimited_35.Null"
146 )
146 )
147 xxlimited = pytest.importorskip(module_name)
147 xxlimited = pytest.importorskip(module_name)
148 output = pretty.pretty(xxlimited.Null)
148 output = pretty.pretty(xxlimited.Null)
149 assert output == expected_output
149 assert output == expected_output
150
150
151
151
152 def test_pprint_nomod():
152 def test_pprint_nomod():
153 """
153 """
154 Test that pprint works for classes with no __module__.
154 Test that pprint works for classes with no __module__.
155 """
155 """
156 output = pretty.pretty(NoModule)
156 output = pretty.pretty(NoModule)
157 assert output == "NoModule"
157 assert output == "NoModule"
158
158
159
159
160 def test_pprint_break():
160 def test_pprint_break():
161 """
161 """
162 Test that p.break_ produces expected output
162 Test that p.break_ produces expected output
163 """
163 """
164 output = pretty.pretty(Breaking())
164 output = pretty.pretty(Breaking())
165 expected = "TG: Breaking(\n ):"
165 expected = "TG: Breaking(\n ):"
166 assert output == expected
166 assert output == expected
167
167
168 def test_pprint_break_repr():
168 def test_pprint_break_repr():
169 """
169 """
170 Test that p.break_ is used in repr
170 Test that p.break_ is used in repr
171 """
171 """
172 output = pretty.pretty([[BreakingRepr()]])
172 output = pretty.pretty([[BreakingRepr()]])
173 expected = "[[Breaking(\n )]]"
173 expected = "[[Breaking(\n )]]"
174 assert output == expected
174 assert output == expected
175
175
176 output = pretty.pretty([[BreakingRepr()]*2])
176 output = pretty.pretty([[BreakingRepr()]*2])
177 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
177 expected = "[[Breaking(\n ),\n Breaking(\n )]]"
178 assert output == expected
178 assert output == expected
179
179
180 def test_bad_repr():
180 def test_bad_repr():
181 """Don't catch bad repr errors"""
181 """Don't catch bad repr errors"""
182 with pytest.raises(ZeroDivisionError):
182 with pytest.raises(ZeroDivisionError):
183 pretty.pretty(BadRepr())
183 pretty.pretty(BadRepr())
184
184
185 class BadException(Exception):
185 class BadException(Exception):
186 def __str__(self):
186 def __str__(self):
187 return -1
187 return -1
188
188
189 class ReallyBadRepr(object):
189 class ReallyBadRepr(object):
190 __module__ = 1
190 __module__ = 1
191 @property
191 @property
192 def __class__(self):
192 def __class__(self):
193 raise ValueError("I am horrible")
193 raise ValueError("I am horrible")
194
194
195 def __repr__(self):
195 def __repr__(self):
196 raise BadException()
196 raise BadException()
197
197
198 def test_really_bad_repr():
198 def test_really_bad_repr():
199 with pytest.raises(BadException):
199 with pytest.raises(BadException):
200 pretty.pretty(ReallyBadRepr())
200 pretty.pretty(ReallyBadRepr())
201
201
202
202
203 class SA(object):
203 class SA(object):
204 pass
204 pass
205
205
206 class SB(SA):
206 class SB(SA):
207 pass
207 pass
208
208
209 class TestsPretty(unittest.TestCase):
209 class TestsPretty(unittest.TestCase):
210
210
211 def test_super_repr(self):
211 def test_super_repr(self):
212 # "<super: module_name.SA, None>"
212 # "<super: module_name.SA, None>"
213 output = pretty.pretty(super(SA))
213 output = pretty.pretty(super(SA))
214 self.assertRegex(output, r"<super: \S+.SA, None>")
214 self.assertRegex(output, r"<super: \S+.SA, None>")
215
215
216 # "<super: module_name.SA, <module_name.SB at 0x...>>"
216 # "<super: module_name.SA, <module_name.SB at 0x...>>"
217 sb = SB()
217 sb = SB()
218 output = pretty.pretty(super(SA, sb))
218 output = pretty.pretty(super(SA, sb))
219 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
219 self.assertRegex(output, r"<super: \S+.SA,\s+<\S+.SB at 0x\S+>>")
220
220
221
221
222 def test_long_list(self):
222 def test_long_list(self):
223 lis = list(range(10000))
223 lis = list(range(10000))
224 p = pretty.pretty(lis)
224 p = pretty.pretty(lis)
225 last2 = p.rsplit('\n', 2)[-2:]
225 last2 = p.rsplit('\n', 2)[-2:]
226 self.assertEqual(last2, [' 999,', ' ...]'])
226 self.assertEqual(last2, [' 999,', ' ...]'])
227
227
228 def test_long_set(self):
228 def test_long_set(self):
229 s = set(range(10000))
229 s = set(range(10000))
230 p = pretty.pretty(s)
230 p = pretty.pretty(s)
231 last2 = p.rsplit('\n', 2)[-2:]
231 last2 = p.rsplit('\n', 2)[-2:]
232 self.assertEqual(last2, [' 999,', ' ...}'])
232 self.assertEqual(last2, [' 999,', ' ...}'])
233
233
234 def test_long_tuple(self):
234 def test_long_tuple(self):
235 tup = tuple(range(10000))
235 tup = tuple(range(10000))
236 p = pretty.pretty(tup)
236 p = pretty.pretty(tup)
237 last2 = p.rsplit('\n', 2)[-2:]
237 last2 = p.rsplit('\n', 2)[-2:]
238 self.assertEqual(last2, [' 999,', ' ...)'])
238 self.assertEqual(last2, [' 999,', ' ...)'])
239
239
240 def test_long_dict(self):
240 def test_long_dict(self):
241 d = { n:n for n in range(10000) }
241 d = { n:n for n in range(10000) }
242 p = pretty.pretty(d)
242 p = pretty.pretty(d)
243 last2 = p.rsplit('\n', 2)[-2:]
243 last2 = p.rsplit('\n', 2)[-2:]
244 self.assertEqual(last2, [' 999: 999,', ' ...}'])
244 self.assertEqual(last2, [' 999: 999,', ' ...}'])
245
245
246 def test_unbound_method(self):
246 def test_unbound_method(self):
247 output = pretty.pretty(MyObj.somemethod)
247 output = pretty.pretty(MyObj.somemethod)
248 self.assertIn('MyObj.somemethod', output)
248 self.assertIn('MyObj.somemethod', output)
249
249
250
250
251 class MetaClass(type):
251 class MetaClass(type):
252 def __new__(cls, name):
252 def __new__(cls, name):
253 return type.__new__(cls, name, (object,), {'name': name})
253 return type.__new__(cls, name, (object,), {'name': name})
254
254
255 def __repr__(self):
255 def __repr__(self):
256 return "[CUSTOM REPR FOR CLASS %s]" % self.name
256 return "[CUSTOM REPR FOR CLASS %s]" % self.name
257
257
258
258
259 ClassWithMeta = MetaClass('ClassWithMeta')
259 ClassWithMeta = MetaClass('ClassWithMeta')
260
260
261
261
262 def test_metaclass_repr():
262 def test_metaclass_repr():
263 output = pretty.pretty(ClassWithMeta)
263 output = pretty.pretty(ClassWithMeta)
264 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
264 assert output == "[CUSTOM REPR FOR CLASS ClassWithMeta]"
265
265
266
266
267 def test_unicode_repr():
267 def test_unicode_repr():
268 u = u"üniçodé"
268 u = u"üniçodé"
269 ustr = u
269 ustr = u
270
270
271 class C(object):
271 class C(object):
272 def __repr__(self):
272 def __repr__(self):
273 return ustr
273 return ustr
274
274
275 c = C()
275 c = C()
276 p = pretty.pretty(c)
276 p = pretty.pretty(c)
277 assert p == u
277 assert p == u
278 p = pretty.pretty([c])
278 p = pretty.pretty([c])
279 assert p == "[%s]" % u
279 assert p == "[%s]" % u
280
280
281
281
282 def test_basic_class():
282 def test_basic_class():
283 def type_pprint_wrapper(obj, p, cycle):
283 def type_pprint_wrapper(obj, p, cycle):
284 if obj is MyObj:
284 if obj is MyObj:
285 type_pprint_wrapper.called = True
285 type_pprint_wrapper.called = True
286 return pretty._type_pprint(obj, p, cycle)
286 return pretty._type_pprint(obj, p, cycle)
287 type_pprint_wrapper.called = False
287 type_pprint_wrapper.called = False
288
288
289 stream = StringIO()
289 stream = StringIO()
290 printer = pretty.RepresentationPrinter(stream)
290 printer = pretty.RepresentationPrinter(stream)
291 printer.type_pprinters[type] = type_pprint_wrapper
291 printer.type_pprinters[type] = type_pprint_wrapper
292 printer.pretty(MyObj)
292 printer.pretty(MyObj)
293 printer.flush()
293 printer.flush()
294 output = stream.getvalue()
294 output = stream.getvalue()
295
295
296 assert output == "%s.MyObj" % __name__
296 assert output == "%s.MyObj" % __name__
297 assert type_pprint_wrapper.called is True
297 assert type_pprint_wrapper.called is True
298
298
299
299
300 def test_collections_userlist():
300 def test_collections_userlist():
301 # Create userlist with cycle
301 # Create userlist with cycle
302 a = UserList()
302 a = UserList()
303 a.append(a)
303 a.append(a)
304
304
305 cases = [
305 cases = [
306 (UserList(), "UserList([])"),
306 (UserList(), "UserList([])"),
307 (
307 (
308 UserList(i for i in range(1000, 1020)),
308 UserList(i for i in range(1000, 1020)),
309 "UserList([1000,\n"
309 "UserList([1000,\n"
310 " 1001,\n"
310 " 1001,\n"
311 " 1002,\n"
311 " 1002,\n"
312 " 1003,\n"
312 " 1003,\n"
313 " 1004,\n"
313 " 1004,\n"
314 " 1005,\n"
314 " 1005,\n"
315 " 1006,\n"
315 " 1006,\n"
316 " 1007,\n"
316 " 1007,\n"
317 " 1008,\n"
317 " 1008,\n"
318 " 1009,\n"
318 " 1009,\n"
319 " 1010,\n"
319 " 1010,\n"
320 " 1011,\n"
320 " 1011,\n"
321 " 1012,\n"
321 " 1012,\n"
322 " 1013,\n"
322 " 1013,\n"
323 " 1014,\n"
323 " 1014,\n"
324 " 1015,\n"
324 " 1015,\n"
325 " 1016,\n"
325 " 1016,\n"
326 " 1017,\n"
326 " 1017,\n"
327 " 1018,\n"
327 " 1018,\n"
328 " 1019])",
328 " 1019])",
329 ),
329 ),
330 (a, "UserList([UserList(...)])"),
330 (a, "UserList([UserList(...)])"),
331 ]
331 ]
332 for obj, expected in cases:
332 for obj, expected in cases:
333 assert pretty.pretty(obj) == expected
333 assert pretty.pretty(obj) == expected
334
334
335
335
336 # TODO : pytest.mark.parametrise once nose is gone.
336 # TODO : pytest.mark.parametrise once nose is gone.
337 def test_collections_defaultdict():
337 def test_collections_defaultdict():
338 # Create defaultdicts with cycles
338 # Create defaultdicts with cycles
339 a = defaultdict()
339 a = defaultdict()
340 a.default_factory = a
340 a.default_factory = a
341 b = defaultdict(list)
341 b = defaultdict(list)
342 b['key'] = b
342 b['key'] = b
343
343
344 # Dictionary order cannot be relied on, test against single keys.
344 # Dictionary order cannot be relied on, test against single keys.
345 cases = [
345 cases = [
346 (defaultdict(list), 'defaultdict(list, {})'),
346 (defaultdict(list), 'defaultdict(list, {})'),
347 (defaultdict(list, {'key': '-' * 50}),
347 (defaultdict(list, {'key': '-' * 50}),
348 "defaultdict(list,\n"
348 "defaultdict(list,\n"
349 " {'key': '--------------------------------------------------'})"),
349 " {'key': '--------------------------------------------------'})"),
350 (a, 'defaultdict(defaultdict(...), {})'),
350 (a, 'defaultdict(defaultdict(...), {})'),
351 (b, "defaultdict(list, {'key': defaultdict(...)})"),
351 (b, "defaultdict(list, {'key': defaultdict(...)})"),
352 ]
352 ]
353 for obj, expected in cases:
353 for obj, expected in cases:
354 assert pretty.pretty(obj) == expected
354 assert pretty.pretty(obj) == expected
355
355
356
356
357 # TODO : pytest.mark.parametrise once nose is gone.
357 # TODO : pytest.mark.parametrise once nose is gone.
358 def test_collections_ordereddict():
358 def test_collections_ordereddict():
359 # Create OrderedDict with cycle
359 # Create OrderedDict with cycle
360 a = OrderedDict()
360 a = OrderedDict()
361 a['key'] = a
361 a['key'] = a
362
362
363 cases = [
363 cases = [
364 (OrderedDict(), 'OrderedDict()'),
364 (OrderedDict(), 'OrderedDict()'),
365 (OrderedDict((i, i) for i in range(1000, 1010)),
365 (OrderedDict((i, i) for i in range(1000, 1010)),
366 'OrderedDict([(1000, 1000),\n'
366 'OrderedDict([(1000, 1000),\n'
367 ' (1001, 1001),\n'
367 ' (1001, 1001),\n'
368 ' (1002, 1002),\n'
368 ' (1002, 1002),\n'
369 ' (1003, 1003),\n'
369 ' (1003, 1003),\n'
370 ' (1004, 1004),\n'
370 ' (1004, 1004),\n'
371 ' (1005, 1005),\n'
371 ' (1005, 1005),\n'
372 ' (1006, 1006),\n'
372 ' (1006, 1006),\n'
373 ' (1007, 1007),\n'
373 ' (1007, 1007),\n'
374 ' (1008, 1008),\n'
374 ' (1008, 1008),\n'
375 ' (1009, 1009)])'),
375 ' (1009, 1009)])'),
376 (a, "OrderedDict([('key', OrderedDict(...))])"),
376 (a, "OrderedDict([('key', OrderedDict(...))])"),
377 ]
377 ]
378 for obj, expected in cases:
378 for obj, expected in cases:
379 assert pretty.pretty(obj) == expected
379 assert pretty.pretty(obj) == expected
380
380
381
381
382 # TODO : pytest.mark.parametrise once nose is gone.
382 # TODO : pytest.mark.parametrise once nose is gone.
383 def test_collections_deque():
383 def test_collections_deque():
384 # Create deque with cycle
384 # Create deque with cycle
385 a = deque()
385 a = deque()
386 a.append(a)
386 a.append(a)
387
387
388 cases = [
388 cases = [
389 (deque(), 'deque([])'),
389 (deque(), 'deque([])'),
390 (deque(i for i in range(1000, 1020)),
390 (deque(i for i in range(1000, 1020)),
391 'deque([1000,\n'
391 'deque([1000,\n'
392 ' 1001,\n'
392 ' 1001,\n'
393 ' 1002,\n'
393 ' 1002,\n'
394 ' 1003,\n'
394 ' 1003,\n'
395 ' 1004,\n'
395 ' 1004,\n'
396 ' 1005,\n'
396 ' 1005,\n'
397 ' 1006,\n'
397 ' 1006,\n'
398 ' 1007,\n'
398 ' 1007,\n'
399 ' 1008,\n'
399 ' 1008,\n'
400 ' 1009,\n'
400 ' 1009,\n'
401 ' 1010,\n'
401 ' 1010,\n'
402 ' 1011,\n'
402 ' 1011,\n'
403 ' 1012,\n'
403 ' 1012,\n'
404 ' 1013,\n'
404 ' 1013,\n'
405 ' 1014,\n'
405 ' 1014,\n'
406 ' 1015,\n'
406 ' 1015,\n'
407 ' 1016,\n'
407 ' 1016,\n'
408 ' 1017,\n'
408 ' 1017,\n'
409 ' 1018,\n'
409 ' 1018,\n'
410 ' 1019])'),
410 ' 1019])'),
411 (a, 'deque([deque(...)])'),
411 (a, 'deque([deque(...)])'),
412 ]
412 ]
413 for obj, expected in cases:
413 for obj, expected in cases:
414 assert pretty.pretty(obj) == expected
414 assert pretty.pretty(obj) == expected
415
415
416
416
417 # TODO : pytest.mark.parametrise once nose is gone.
417 # TODO : pytest.mark.parametrise once nose is gone.
418 def test_collections_counter():
418 def test_collections_counter():
419 class MyCounter(Counter):
419 class MyCounter(Counter):
420 pass
420 pass
421 cases = [
421 cases = [
422 (Counter(), 'Counter()'),
422 (Counter(), 'Counter()'),
423 (Counter(a=1), "Counter({'a': 1})"),
423 (Counter(a=1), "Counter({'a': 1})"),
424 (MyCounter(a=1), "MyCounter({'a': 1})"),
424 (MyCounter(a=1), "MyCounter({'a': 1})"),
425 (Counter(a=1, c=22), "Counter({'c': 22, 'a': 1})")
425 ]
426 ]
426 for obj, expected in cases:
427 for obj, expected in cases:
427 assert pretty.pretty(obj) == expected
428 assert pretty.pretty(obj) == expected
428
429
429 # TODO : pytest.mark.parametrise once nose is gone.
430 # TODO : pytest.mark.parametrise once nose is gone.
430 def test_mappingproxy():
431 def test_mappingproxy():
431 MP = types.MappingProxyType
432 MP = types.MappingProxyType
432 underlying_dict = {}
433 underlying_dict = {}
433 mp_recursive = MP(underlying_dict)
434 mp_recursive = MP(underlying_dict)
434 underlying_dict[2] = mp_recursive
435 underlying_dict[2] = mp_recursive
435 underlying_dict[3] = underlying_dict
436 underlying_dict[3] = underlying_dict
436
437
437 cases = [
438 cases = [
438 (MP({}), "mappingproxy({})"),
439 (MP({}), "mappingproxy({})"),
439 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
440 (MP({None: MP({})}), "mappingproxy({None: mappingproxy({})})"),
440 (MP({k: k.upper() for k in string.ascii_lowercase}),
441 (MP({k: k.upper() for k in string.ascii_lowercase}),
441 "mappingproxy({'a': 'A',\n"
442 "mappingproxy({'a': 'A',\n"
442 " 'b': 'B',\n"
443 " 'b': 'B',\n"
443 " 'c': 'C',\n"
444 " 'c': 'C',\n"
444 " 'd': 'D',\n"
445 " 'd': 'D',\n"
445 " 'e': 'E',\n"
446 " 'e': 'E',\n"
446 " 'f': 'F',\n"
447 " 'f': 'F',\n"
447 " 'g': 'G',\n"
448 " 'g': 'G',\n"
448 " 'h': 'H',\n"
449 " 'h': 'H',\n"
449 " 'i': 'I',\n"
450 " 'i': 'I',\n"
450 " 'j': 'J',\n"
451 " 'j': 'J',\n"
451 " 'k': 'K',\n"
452 " 'k': 'K',\n"
452 " 'l': 'L',\n"
453 " 'l': 'L',\n"
453 " 'm': 'M',\n"
454 " 'm': 'M',\n"
454 " 'n': 'N',\n"
455 " 'n': 'N',\n"
455 " 'o': 'O',\n"
456 " 'o': 'O',\n"
456 " 'p': 'P',\n"
457 " 'p': 'P',\n"
457 " 'q': 'Q',\n"
458 " 'q': 'Q',\n"
458 " 'r': 'R',\n"
459 " 'r': 'R',\n"
459 " 's': 'S',\n"
460 " 's': 'S',\n"
460 " 't': 'T',\n"
461 " 't': 'T',\n"
461 " 'u': 'U',\n"
462 " 'u': 'U',\n"
462 " 'v': 'V',\n"
463 " 'v': 'V',\n"
463 " 'w': 'W',\n"
464 " 'w': 'W',\n"
464 " 'x': 'X',\n"
465 " 'x': 'X',\n"
465 " 'y': 'Y',\n"
466 " 'y': 'Y',\n"
466 " 'z': 'Z'})"),
467 " 'z': 'Z'})"),
467 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
468 (mp_recursive, "mappingproxy({2: {...}, 3: {2: {...}, 3: {...}}})"),
468 (underlying_dict,
469 (underlying_dict,
469 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
470 "{2: mappingproxy({2: {...}, 3: {...}}), 3: {...}}"),
470 ]
471 ]
471 for obj, expected in cases:
472 for obj, expected in cases:
472 assert pretty.pretty(obj) == expected
473 assert pretty.pretty(obj) == expected
473
474
474
475
475 # TODO : pytest.mark.parametrise once nose is gone.
476 # TODO : pytest.mark.parametrise once nose is gone.
476 def test_simplenamespace():
477 def test_simplenamespace():
477 SN = types.SimpleNamespace
478 SN = types.SimpleNamespace
478
479
479 sn_recursive = SN()
480 sn_recursive = SN()
480 sn_recursive.first = sn_recursive
481 sn_recursive.first = sn_recursive
481 sn_recursive.second = sn_recursive
482 sn_recursive.second = sn_recursive
482 cases = [
483 cases = [
483 (SN(), "namespace()"),
484 (SN(), "namespace()"),
484 (SN(x=SN()), "namespace(x=namespace())"),
485 (SN(x=SN()), "namespace(x=namespace())"),
485 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
486 (SN(a_long_name=[SN(s=string.ascii_lowercase)]*3, a_short_name=None),
486 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
487 "namespace(a_long_name=[namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
487 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
488 " namespace(s='abcdefghijklmnopqrstuvwxyz'),\n"
488 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
489 " namespace(s='abcdefghijklmnopqrstuvwxyz')],\n"
489 " a_short_name=None)"),
490 " a_short_name=None)"),
490 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
491 (sn_recursive, "namespace(first=namespace(...), second=namespace(...))"),
491 ]
492 ]
492 for obj, expected in cases:
493 for obj, expected in cases:
493 assert pretty.pretty(obj) == expected
494 assert pretty.pretty(obj) == expected
494
495
495
496
496 def test_pretty_environ():
497 def test_pretty_environ():
497 dict_repr = pretty.pretty(dict(os.environ))
498 dict_repr = pretty.pretty(dict(os.environ))
498 # reindent to align with 'environ' prefix
499 # reindent to align with 'environ' prefix
499 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
500 dict_indented = dict_repr.replace('\n', '\n' + (' ' * len('environ')))
500 env_repr = pretty.pretty(os.environ)
501 env_repr = pretty.pretty(os.environ)
501 assert env_repr == "environ" + dict_indented
502 assert env_repr == "environ" + dict_indented
502
503
503
504
504 def test_function_pretty():
505 def test_function_pretty():
505 "Test pretty print of function"
506 "Test pretty print of function"
506 # posixpath is a pure python module, its interface is consistent
507 # posixpath is a pure python module, its interface is consistent
507 # across Python distributions
508 # across Python distributions
508 import posixpath
509 import posixpath
509
510
510 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
511 assert pretty.pretty(posixpath.join) == "<function posixpath.join(a, *p)>"
511
512
512 # custom function
513 # custom function
513 def meaning_of_life(question=None):
514 def meaning_of_life(question=None):
514 if question:
515 if question:
515 return 42
516 return 42
516 return "Don't panic"
517 return "Don't panic"
517
518
518 assert "meaning_of_life(question=None)" in pretty.pretty(meaning_of_life)
519 assert "meaning_of_life(question=None)" in pretty.pretty(meaning_of_life)
519
520
520
521
521 class OrderedCounter(Counter, OrderedDict):
522 class OrderedCounter(Counter, OrderedDict):
522 'Counter that remembers the order elements are first encountered'
523 'Counter that remembers the order elements are first encountered'
523
524
524 def __repr__(self):
525 def __repr__(self):
525 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
526 return '%s(%r)' % (self.__class__.__name__, OrderedDict(self))
526
527
527 def __reduce__(self):
528 def __reduce__(self):
528 return self.__class__, (OrderedDict(self),)
529 return self.__class__, (OrderedDict(self),)
529
530
530 class MySet(set): # Override repr of a basic type
531 class MySet(set): # Override repr of a basic type
531 def __repr__(self):
532 def __repr__(self):
532 return 'mine'
533 return 'mine'
533
534
534 def test_custom_repr():
535 def test_custom_repr():
535 """A custom repr should override a pretty printer for a parent type"""
536 """A custom repr should override a pretty printer for a parent type"""
536 oc = OrderedCounter("abracadabra")
537 oc = OrderedCounter("abracadabra")
537 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
538 assert "OrderedCounter(OrderedDict" in pretty.pretty(oc)
538
539
539 assert pretty.pretty(MySet()) == "mine"
540 assert pretty.pretty(MySet()) == "mine"
General Comments 0
You need to be logged in to leave comments. Login now