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