##// END OF EJS Templates
Merge pull request #10863 from Madhu94/add-function-signature-display...
Thomas Kluyver -
r24032:dc9d1c67 merge
parent child Browse files
Show More
@@ -1,432 +1,437
1 """Tests for the object inspection functionality.
1 """Tests for the object inspection functionality.
2 """
2 """
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 inspect import Signature, Parameter
8 from inspect import Signature, Parameter
9 import os
9 import os
10 import re
10 import re
11 import sys
11 import sys
12
12
13 import nose.tools as nt
13 import nose.tools as nt
14
14
15 from .. import oinspect
15 from .. import oinspect
16 from IPython.core.magic import (Magics, magics_class, line_magic,
16 from IPython.core.magic import (Magics, magics_class, line_magic,
17 cell_magic, line_cell_magic,
17 cell_magic, line_cell_magic,
18 register_line_magic, register_cell_magic,
18 register_line_magic, register_cell_magic,
19 register_line_cell_magic)
19 register_line_cell_magic)
20 from decorator import decorator
20 from decorator import decorator
21 from IPython import get_ipython
21 from IPython import get_ipython
22 from IPython.testing.tools import AssertPrints, AssertNotPrints
22 from IPython.testing.tools import AssertPrints, AssertNotPrints
23 from IPython.utils.path import compress_user
23 from IPython.utils.path import compress_user
24
24
25
25
26 #-----------------------------------------------------------------------------
26 #-----------------------------------------------------------------------------
27 # Globals and constants
27 # Globals and constants
28 #-----------------------------------------------------------------------------
28 #-----------------------------------------------------------------------------
29
29
30 inspector = oinspect.Inspector()
30 inspector = oinspect.Inspector()
31 ip = get_ipython()
31 ip = get_ipython()
32
32
33 #-----------------------------------------------------------------------------
33 #-----------------------------------------------------------------------------
34 # Local utilities
34 # Local utilities
35 #-----------------------------------------------------------------------------
35 #-----------------------------------------------------------------------------
36
36
37 # WARNING: since this test checks the line number where a function is
37 # WARNING: since this test checks the line number where a function is
38 # defined, if any code is inserted above, the following line will need to be
38 # defined, if any code is inserted above, the following line will need to be
39 # updated. Do NOT insert any whitespace between the next line and the function
39 # updated. Do NOT insert any whitespace between the next line and the function
40 # definition below.
40 # definition below.
41 THIS_LINE_NUMBER = 41 # Put here the actual number of this line
41 THIS_LINE_NUMBER = 41 # Put here the actual number of this line
42
42
43 from unittest import TestCase
43 from unittest import TestCase
44
44
45 class Test(TestCase):
45 class Test(TestCase):
46
46
47 def test_find_source_lines(self):
47 def test_find_source_lines(self):
48 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
48 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
49 THIS_LINE_NUMBER+6)
49 THIS_LINE_NUMBER+6)
50
50
51
51
52 # A couple of utilities to ensure these tests work the same from a source or a
52 # A couple of utilities to ensure these tests work the same from a source or a
53 # binary install
53 # binary install
54 def pyfile(fname):
54 def pyfile(fname):
55 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
55 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
56
56
57
57
58 def match_pyfiles(f1, f2):
58 def match_pyfiles(f1, f2):
59 nt.assert_equal(pyfile(f1), pyfile(f2))
59 nt.assert_equal(pyfile(f1), pyfile(f2))
60
60
61
61
62 def test_find_file():
62 def test_find_file():
63 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
63 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
64
64
65
65
66 def test_find_file_decorated1():
66 def test_find_file_decorated1():
67
67
68 @decorator
68 @decorator
69 def noop1(f):
69 def noop1(f):
70 def wrapper(*a, **kw):
70 def wrapper(*a, **kw):
71 return f(*a, **kw)
71 return f(*a, **kw)
72 return wrapper
72 return wrapper
73
73
74 @noop1
74 @noop1
75 def f(x):
75 def f(x):
76 "My docstring"
76 "My docstring"
77
77
78 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
78 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
79 nt.assert_equal(f.__doc__, "My docstring")
79 nt.assert_equal(f.__doc__, "My docstring")
80
80
81
81
82 def test_find_file_decorated2():
82 def test_find_file_decorated2():
83
83
84 @decorator
84 @decorator
85 def noop2(f, *a, **kw):
85 def noop2(f, *a, **kw):
86 return f(*a, **kw)
86 return f(*a, **kw)
87
87
88 @noop2
88 @noop2
89 @noop2
89 @noop2
90 @noop2
90 @noop2
91 def f(x):
91 def f(x):
92 "My docstring 2"
92 "My docstring 2"
93
93
94 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
94 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 nt.assert_equal(f.__doc__, "My docstring 2")
95 nt.assert_equal(f.__doc__, "My docstring 2")
96
96
97
97
98 def test_find_file_magic():
98 def test_find_file_magic():
99 run = ip.find_line_magic('run')
99 run = ip.find_line_magic('run')
100 nt.assert_not_equal(oinspect.find_file(run), None)
100 nt.assert_not_equal(oinspect.find_file(run), None)
101
101
102
102
103 # A few generic objects we can then inspect in the tests below
103 # A few generic objects we can then inspect in the tests below
104
104
105 class Call(object):
105 class Call(object):
106 """This is the class docstring."""
106 """This is the class docstring."""
107
107
108 def __init__(self, x, y=1):
108 def __init__(self, x, y=1):
109 """This is the constructor docstring."""
109 """This is the constructor docstring."""
110
110
111 def __call__(self, *a, **kw):
111 def __call__(self, *a, **kw):
112 """This is the call docstring."""
112 """This is the call docstring."""
113
113
114 def method(self, x, z=2):
114 def method(self, x, z=2):
115 """Some method's docstring"""
115 """Some method's docstring"""
116
116
117 class HasSignature(object):
117 class HasSignature(object):
118 """This is the class docstring."""
118 """This is the class docstring."""
119 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
119 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
120
120
121 def __init__(self, *args):
121 def __init__(self, *args):
122 """This is the init docstring"""
122 """This is the init docstring"""
123
123
124
124
125 class SimpleClass(object):
125 class SimpleClass(object):
126 def method(self, x, z=2):
126 def method(self, x, z=2):
127 """Some method's docstring"""
127 """Some method's docstring"""
128
128
129
129
130 class OldStyle:
130 class OldStyle:
131 """An old-style class for testing."""
131 """An old-style class for testing."""
132 pass
132 pass
133
133
134
134
135 def f(x, y=2, *a, **kw):
135 def f(x, y=2, *a, **kw):
136 """A simple function."""
136 """A simple function."""
137
137
138
138
139 def g(y, z=3, *a, **kw):
139 def g(y, z=3, *a, **kw):
140 pass # no docstring
140 pass # no docstring
141
141
142
142
143 @register_line_magic
143 @register_line_magic
144 def lmagic(line):
144 def lmagic(line):
145 "A line magic"
145 "A line magic"
146
146
147
147
148 @register_cell_magic
148 @register_cell_magic
149 def cmagic(line, cell):
149 def cmagic(line, cell):
150 "A cell magic"
150 "A cell magic"
151
151
152
152
153 @register_line_cell_magic
153 @register_line_cell_magic
154 def lcmagic(line, cell=None):
154 def lcmagic(line, cell=None):
155 "A line/cell magic"
155 "A line/cell magic"
156
156
157
157
158 @magics_class
158 @magics_class
159 class SimpleMagics(Magics):
159 class SimpleMagics(Magics):
160 @line_magic
160 @line_magic
161 def Clmagic(self, cline):
161 def Clmagic(self, cline):
162 "A class-based line magic"
162 "A class-based line magic"
163
163
164 @cell_magic
164 @cell_magic
165 def Ccmagic(self, cline, ccell):
165 def Ccmagic(self, cline, ccell):
166 "A class-based cell magic"
166 "A class-based cell magic"
167
167
168 @line_cell_magic
168 @line_cell_magic
169 def Clcmagic(self, cline, ccell=None):
169 def Clcmagic(self, cline, ccell=None):
170 "A class-based line/cell magic"
170 "A class-based line/cell magic"
171
171
172
172
173 class Awkward(object):
173 class Awkward(object):
174 def __getattr__(self, name):
174 def __getattr__(self, name):
175 raise Exception(name)
175 raise Exception(name)
176
176
177 class NoBoolCall:
177 class NoBoolCall:
178 """
178 """
179 callable with `__bool__` raising should still be inspect-able.
179 callable with `__bool__` raising should still be inspect-able.
180 """
180 """
181
181
182 def __call__(self):
182 def __call__(self):
183 """does nothing"""
183 """does nothing"""
184 pass
184 pass
185
185
186 def __bool__(self):
186 def __bool__(self):
187 """just raise NotImplemented"""
187 """just raise NotImplemented"""
188 raise NotImplementedError('Must be implemented')
188 raise NotImplementedError('Must be implemented')
189
189
190
190
191 class SerialLiar(object):
191 class SerialLiar(object):
192 """Attribute accesses always get another copy of the same class.
192 """Attribute accesses always get another copy of the same class.
193
193
194 unittest.mock.call does something similar, but it's not ideal for testing
194 unittest.mock.call does something similar, but it's not ideal for testing
195 as the failure mode is to eat all your RAM. This gives up after 10k levels.
195 as the failure mode is to eat all your RAM. This gives up after 10k levels.
196 """
196 """
197 def __init__(self, max_fibbing_twig, lies_told=0):
197 def __init__(self, max_fibbing_twig, lies_told=0):
198 if lies_told > 10000:
198 if lies_told > 10000:
199 raise RuntimeError('Nose too long, honesty is the best policy')
199 raise RuntimeError('Nose too long, honesty is the best policy')
200 self.max_fibbing_twig = max_fibbing_twig
200 self.max_fibbing_twig = max_fibbing_twig
201 self.lies_told = lies_told
201 self.lies_told = lies_told
202 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
202 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
203
203
204 def __getattr__(self, item):
204 def __getattr__(self, item):
205 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
205 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
206
206
207 #-----------------------------------------------------------------------------
207 #-----------------------------------------------------------------------------
208 # Tests
208 # Tests
209 #-----------------------------------------------------------------------------
209 #-----------------------------------------------------------------------------
210
210
211 def test_info():
211 def test_info():
212 "Check that Inspector.info fills out various fields as expected."
212 "Check that Inspector.info fills out various fields as expected."
213 i = inspector.info(Call, oname='Call')
213 i = inspector.info(Call, oname='Call')
214 nt.assert_equal(i['type_name'], 'type')
214 nt.assert_equal(i['type_name'], 'type')
215 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
215 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
216 nt.assert_equal(i['base_class'], expted_class)
216 nt.assert_equal(i['base_class'], expted_class)
217 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
217 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
218 fname = __file__
218 fname = __file__
219 if fname.endswith(".pyc"):
219 if fname.endswith(".pyc"):
220 fname = fname[:-1]
220 fname = fname[:-1]
221 # case-insensitive comparison needed on some filesystems
221 # case-insensitive comparison needed on some filesystems
222 # e.g. Windows:
222 # e.g. Windows:
223 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
223 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
224 nt.assert_equal(i['definition'], None)
224 nt.assert_equal(i['definition'], None)
225 nt.assert_equal(i['docstring'], Call.__doc__)
225 nt.assert_equal(i['docstring'], Call.__doc__)
226 nt.assert_equal(i['source'], None)
226 nt.assert_equal(i['source'], None)
227 nt.assert_true(i['isclass'])
227 nt.assert_true(i['isclass'])
228 nt.assert_equal(i['init_definition'], "Call(x, y=1)")
228 nt.assert_equal(i['init_definition'], "Call(x, y=1)")
229 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
229 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
230
230
231 i = inspector.info(Call, detail_level=1)
231 i = inspector.info(Call, detail_level=1)
232 nt.assert_not_equal(i['source'], None)
232 nt.assert_not_equal(i['source'], None)
233 nt.assert_equal(i['docstring'], None)
233 nt.assert_equal(i['docstring'], None)
234
234
235 c = Call(1)
235 c = Call(1)
236 c.__doc__ = "Modified instance docstring"
236 c.__doc__ = "Modified instance docstring"
237 i = inspector.info(c)
237 i = inspector.info(c)
238 nt.assert_equal(i['type_name'], 'Call')
238 nt.assert_equal(i['type_name'], 'Call')
239 nt.assert_equal(i['docstring'], "Modified instance docstring")
239 nt.assert_equal(i['docstring'], "Modified instance docstring")
240 nt.assert_equal(i['class_docstring'], Call.__doc__)
240 nt.assert_equal(i['class_docstring'], Call.__doc__)
241 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
241 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
242 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
242 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
243
243
244 def test_class_signature():
244 def test_class_signature():
245 info = inspector.info(HasSignature, 'HasSignature')
245 info = inspector.info(HasSignature, 'HasSignature')
246 nt.assert_equal(info['init_definition'], "HasSignature(test)")
246 nt.assert_equal(info['init_definition'], "HasSignature(test)")
247 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
247 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
248
248
249 def test_info_awkward():
249 def test_info_awkward():
250 # Just test that this doesn't throw an error.
250 # Just test that this doesn't throw an error.
251 inspector.info(Awkward())
251 inspector.info(Awkward())
252
252
253 def test_bool_raise():
253 def test_bool_raise():
254 inspector.info(NoBoolCall())
254 inspector.info(NoBoolCall())
255
255
256 def test_info_serialliar():
256 def test_info_serialliar():
257 fib_tracker = [0]
257 fib_tracker = [0]
258 inspector.info(SerialLiar(fib_tracker))
258 inspector.info(SerialLiar(fib_tracker))
259
259
260 # Nested attribute access should be cut off at 100 levels deep to avoid
260 # Nested attribute access should be cut off at 100 levels deep to avoid
261 # infinite loops: https://github.com/ipython/ipython/issues/9122
261 # infinite loops: https://github.com/ipython/ipython/issues/9122
262 nt.assert_less(fib_tracker[0], 9000)
262 nt.assert_less(fib_tracker[0], 9000)
263
263
264 def test_calldef_none():
264 def test_calldef_none():
265 # We should ignore __call__ for all of these.
265 # We should ignore __call__ for all of these.
266 for obj in [f, SimpleClass().method, any, str.upper]:
266 for obj in [f, SimpleClass().method, any, str.upper]:
267 print(obj)
267 print(obj)
268 i = inspector.info(obj)
268 i = inspector.info(obj)
269 nt.assert_is(i['call_def'], None)
269 nt.assert_is(i['call_def'], None)
270
270
271 def f_kwarg(pos, *, kwonly):
271 def f_kwarg(pos, *, kwonly):
272 pass
272 pass
273
273
274 def test_definition_kwonlyargs():
274 def test_definition_kwonlyargs():
275 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
275 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
276 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
276 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
277
277
278 def test_getdoc():
278 def test_getdoc():
279 class A(object):
279 class A(object):
280 """standard docstring"""
280 """standard docstring"""
281 pass
281 pass
282
282
283 class B(object):
283 class B(object):
284 """standard docstring"""
284 """standard docstring"""
285 def getdoc(self):
285 def getdoc(self):
286 return "custom docstring"
286 return "custom docstring"
287
287
288 class C(object):
288 class C(object):
289 """standard docstring"""
289 """standard docstring"""
290 def getdoc(self):
290 def getdoc(self):
291 return None
291 return None
292
292
293 a = A()
293 a = A()
294 b = B()
294 b = B()
295 c = C()
295 c = C()
296
296
297 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
297 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
298 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
298 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
299 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
299 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
300
300
301
301
302 def test_empty_property_has_no_source():
302 def test_empty_property_has_no_source():
303 i = inspector.info(property(), detail_level=1)
303 i = inspector.info(property(), detail_level=1)
304 nt.assert_is(i['source'], None)
304 nt.assert_is(i['source'], None)
305
305
306
306
307 def test_property_sources():
307 def test_property_sources():
308 import zlib
308 import posixpath
309
309 # A simple adder whose source and signature stays
310 # the same across Python distributions
311 def simple_add(a, b):
312 "Adds two numbers"
313 return a + b
314
310 class A(object):
315 class A(object):
311 @property
316 @property
312 def foo(self):
317 def foo(self):
313 return 'bar'
318 return 'bar'
314
319
315 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
320 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
316
321
317 id = property(id)
322 dname = property(posixpath.dirname)
318 compress = property(zlib.compress)
323 adder = property(simple_add)
319
324
320 i = inspector.info(A.foo, detail_level=1)
325 i = inspector.info(A.foo, detail_level=1)
321 nt.assert_in('def foo(self):', i['source'])
326 nt.assert_in('def foo(self):', i['source'])
322 nt.assert_in('lambda self, v:', i['source'])
327 nt.assert_in('lambda self, v:', i['source'])
323
328
324 i = inspector.info(A.id, detail_level=1)
329 i = inspector.info(A.dname, detail_level=1)
325 nt.assert_in('fget = <function id>', i['source'])
330 nt.assert_in('def dirname(p)', i['source'])
326
331
327 i = inspector.info(A.compress, detail_level=1)
332 i = inspector.info(A.adder, detail_level=1)
328 nt.assert_in('fget = <function zlib.compress>', i['source'])
333 nt.assert_in('def simple_add(a, b)', i['source'])
329
334
330
335
331 def test_property_docstring_is_in_info_for_detail_level_0():
336 def test_property_docstring_is_in_info_for_detail_level_0():
332 class A(object):
337 class A(object):
333 @property
338 @property
334 def foobar(self):
339 def foobar(self):
335 """This is `foobar` property."""
340 """This is `foobar` property."""
336 pass
341 pass
337
342
338 ip.user_ns['a_obj'] = A()
343 ip.user_ns['a_obj'] = A()
339 nt.assert_equal(
344 nt.assert_equal(
340 'This is `foobar` property.',
345 'This is `foobar` property.',
341 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
346 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
342
347
343 ip.user_ns['a_cls'] = A
348 ip.user_ns['a_cls'] = A
344 nt.assert_equal(
349 nt.assert_equal(
345 'This is `foobar` property.',
350 'This is `foobar` property.',
346 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
351 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
347
352
348
353
349 def test_pdef():
354 def test_pdef():
350 # See gh-1914
355 # See gh-1914
351 def foo(): pass
356 def foo(): pass
352 inspector.pdef(foo, 'foo')
357 inspector.pdef(foo, 'foo')
353
358
354
359
355 def test_pinfo_nonascii():
360 def test_pinfo_nonascii():
356 # See gh-1177
361 # See gh-1177
357 from . import nonascii2
362 from . import nonascii2
358 ip.user_ns['nonascii2'] = nonascii2
363 ip.user_ns['nonascii2'] = nonascii2
359 ip._inspect('pinfo', 'nonascii2', detail_level=1)
364 ip._inspect('pinfo', 'nonascii2', detail_level=1)
360
365
361
366
362 def test_pinfo_docstring_no_source():
367 def test_pinfo_docstring_no_source():
363 """Docstring should be included with detail_level=1 if there is no source"""
368 """Docstring should be included with detail_level=1 if there is no source"""
364 with AssertPrints('Docstring:'):
369 with AssertPrints('Docstring:'):
365 ip._inspect('pinfo', 'str.format', detail_level=0)
370 ip._inspect('pinfo', 'str.format', detail_level=0)
366 with AssertPrints('Docstring:'):
371 with AssertPrints('Docstring:'):
367 ip._inspect('pinfo', 'str.format', detail_level=1)
372 ip._inspect('pinfo', 'str.format', detail_level=1)
368
373
369
374
370 def test_pinfo_no_docstring_if_source():
375 def test_pinfo_no_docstring_if_source():
371 """Docstring should not be included with detail_level=1 if source is found"""
376 """Docstring should not be included with detail_level=1 if source is found"""
372 def foo():
377 def foo():
373 """foo has a docstring"""
378 """foo has a docstring"""
374
379
375 ip.user_ns['foo'] = foo
380 ip.user_ns['foo'] = foo
376
381
377 with AssertPrints('Docstring:'):
382 with AssertPrints('Docstring:'):
378 ip._inspect('pinfo', 'foo', detail_level=0)
383 ip._inspect('pinfo', 'foo', detail_level=0)
379 with AssertPrints('Source:'):
384 with AssertPrints('Source:'):
380 ip._inspect('pinfo', 'foo', detail_level=1)
385 ip._inspect('pinfo', 'foo', detail_level=1)
381 with AssertNotPrints('Docstring:'):
386 with AssertNotPrints('Docstring:'):
382 ip._inspect('pinfo', 'foo', detail_level=1)
387 ip._inspect('pinfo', 'foo', detail_level=1)
383
388
384
389
385 def test_pinfo_docstring_if_detail_and_no_source():
390 def test_pinfo_docstring_if_detail_and_no_source():
386 """ Docstring should be displayed if source info not available """
391 """ Docstring should be displayed if source info not available """
387 obj_def = '''class Foo(object):
392 obj_def = '''class Foo(object):
388 """ This is a docstring for Foo """
393 """ This is a docstring for Foo """
389 def bar(self):
394 def bar(self):
390 """ This is a docstring for Foo.bar """
395 """ This is a docstring for Foo.bar """
391 pass
396 pass
392 '''
397 '''
393
398
394 ip.run_cell(obj_def)
399 ip.run_cell(obj_def)
395 ip.run_cell('foo = Foo()')
400 ip.run_cell('foo = Foo()')
396
401
397 with AssertNotPrints("Source:"):
402 with AssertNotPrints("Source:"):
398 with AssertPrints('Docstring:'):
403 with AssertPrints('Docstring:'):
399 ip._inspect('pinfo', 'foo', detail_level=0)
404 ip._inspect('pinfo', 'foo', detail_level=0)
400 with AssertPrints('Docstring:'):
405 with AssertPrints('Docstring:'):
401 ip._inspect('pinfo', 'foo', detail_level=1)
406 ip._inspect('pinfo', 'foo', detail_level=1)
402 with AssertPrints('Docstring:'):
407 with AssertPrints('Docstring:'):
403 ip._inspect('pinfo', 'foo.bar', detail_level=0)
408 ip._inspect('pinfo', 'foo.bar', detail_level=0)
404
409
405 with AssertNotPrints('Docstring:'):
410 with AssertNotPrints('Docstring:'):
406 with AssertPrints('Source:'):
411 with AssertPrints('Source:'):
407 ip._inspect('pinfo', 'foo.bar', detail_level=1)
412 ip._inspect('pinfo', 'foo.bar', detail_level=1)
408
413
409
414
410 def test_pinfo_magic():
415 def test_pinfo_magic():
411 with AssertPrints('Docstring:'):
416 with AssertPrints('Docstring:'):
412 ip._inspect('pinfo', 'lsmagic', detail_level=0)
417 ip._inspect('pinfo', 'lsmagic', detail_level=0)
413
418
414 with AssertPrints('Source:'):
419 with AssertPrints('Source:'):
415 ip._inspect('pinfo', 'lsmagic', detail_level=1)
420 ip._inspect('pinfo', 'lsmagic', detail_level=1)
416
421
417
422
418 def test_init_colors():
423 def test_init_colors():
419 # ensure colors are not present in signature info
424 # ensure colors are not present in signature info
420 info = inspector.info(HasSignature)
425 info = inspector.info(HasSignature)
421 init_def = info['init_definition']
426 init_def = info['init_definition']
422 nt.assert_not_in('[0m', init_def)
427 nt.assert_not_in('[0m', init_def)
423
428
424
429
425 def test_builtin_init():
430 def test_builtin_init():
426 info = inspector.info(list)
431 info = inspector.info(list)
427 init_def = info['init_definition']
432 init_def = info['init_definition']
428 # Python < 3.4 can't get init definition from builtins,
433 # Python < 3.4 can't get init definition from builtins,
429 # but still exercise the inspection in case of error-raising bugs.
434 # but still exercise the inspection in case of error-raising bugs.
430 if sys.version_info >= (3,4):
435 if sys.version_info >= (3,4):
431 nt.assert_is_not_none(init_def)
436 nt.assert_is_not_none(init_def)
432
437
@@ -1,867 +1,871
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
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 _re_pattern_type = type(re.compile(''))
98 _re_pattern_type = type(re.compile(''))
99
99
100 def _safe_getattr(obj, attr, default=None):
100 def _safe_getattr(obj, attr, default=None):
101 """Safe version of getattr.
101 """Safe version of getattr.
102
102
103 Same as getattr, but will return ``default`` on any Exception,
103 Same as getattr, but will return ``default`` on any Exception,
104 rather than raising.
104 rather than raising.
105 """
105 """
106 try:
106 try:
107 return getattr(obj, attr, default)
107 return getattr(obj, attr, default)
108 except Exception:
108 except Exception:
109 return default
109 return default
110
110
111 @undoc
111 @undoc
112 class CUnicodeIO(StringIO):
112 class CUnicodeIO(StringIO):
113 def __init__(self, *args, **kwargs):
113 def __init__(self, *args, **kwargs):
114 super().__init__(*args, **kwargs)
114 super().__init__(*args, **kwargs)
115 warn(("CUnicodeIO is deprecated since IPython 6.0. "
115 warn(("CUnicodeIO is deprecated since IPython 6.0. "
116 "Please use io.StringIO instead."),
116 "Please use io.StringIO instead."),
117 DeprecationWarning, stacklevel=2)
117 DeprecationWarning, stacklevel=2)
118
118
119 def _sorted_for_pprint(items):
119 def _sorted_for_pprint(items):
120 """
120 """
121 Sort the given items for pretty printing. Since some predictable
121 Sort the given items for pretty printing. Since some predictable
122 sorting is better than no sorting at all, we sort on the string
122 sorting is better than no sorting at all, we sort on the string
123 representation if normal sorting fails.
123 representation if normal sorting fails.
124 """
124 """
125 items = list(items)
125 items = list(items)
126 try:
126 try:
127 return sorted(items)
127 return sorted(items)
128 except Exception:
128 except Exception:
129 try:
129 try:
130 return sorted(items, key=str)
130 return sorted(items, key=str)
131 except Exception:
131 except Exception:
132 return items
132 return items
133
133
134 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
134 def pretty(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
135 """
135 """
136 Pretty print the object's representation.
136 Pretty print the object's representation.
137 """
137 """
138 stream = StringIO()
138 stream = StringIO()
139 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
139 printer = RepresentationPrinter(stream, verbose, max_width, newline, max_seq_length=max_seq_length)
140 printer.pretty(obj)
140 printer.pretty(obj)
141 printer.flush()
141 printer.flush()
142 return stream.getvalue()
142 return stream.getvalue()
143
143
144
144
145 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
145 def pprint(obj, verbose=False, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
146 """
146 """
147 Like `pretty` but print to stdout.
147 Like `pretty` but print to stdout.
148 """
148 """
149 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
149 printer = RepresentationPrinter(sys.stdout, verbose, max_width, newline, max_seq_length=max_seq_length)
150 printer.pretty(obj)
150 printer.pretty(obj)
151 printer.flush()
151 printer.flush()
152 sys.stdout.write(newline)
152 sys.stdout.write(newline)
153 sys.stdout.flush()
153 sys.stdout.flush()
154
154
155 class _PrettyPrinterBase(object):
155 class _PrettyPrinterBase(object):
156
156
157 @contextmanager
157 @contextmanager
158 def indent(self, indent):
158 def indent(self, indent):
159 """with statement support for indenting/dedenting."""
159 """with statement support for indenting/dedenting."""
160 self.indentation += indent
160 self.indentation += indent
161 try:
161 try:
162 yield
162 yield
163 finally:
163 finally:
164 self.indentation -= indent
164 self.indentation -= indent
165
165
166 @contextmanager
166 @contextmanager
167 def group(self, indent=0, open='', close=''):
167 def group(self, indent=0, open='', close=''):
168 """like begin_group / end_group but for the with statement."""
168 """like begin_group / end_group but for the with statement."""
169 self.begin_group(indent, open)
169 self.begin_group(indent, open)
170 try:
170 try:
171 yield
171 yield
172 finally:
172 finally:
173 self.end_group(indent, close)
173 self.end_group(indent, close)
174
174
175 class PrettyPrinter(_PrettyPrinterBase):
175 class PrettyPrinter(_PrettyPrinterBase):
176 """
176 """
177 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
177 Baseclass for the `RepresentationPrinter` prettyprinter that is used to
178 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
178 generate pretty reprs of objects. Contrary to the `RepresentationPrinter`
179 this printer knows nothing about the default pprinters or the `_repr_pretty_`
179 this printer knows nothing about the default pprinters or the `_repr_pretty_`
180 callback method.
180 callback method.
181 """
181 """
182
182
183 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
183 def __init__(self, output, max_width=79, newline='\n', max_seq_length=MAX_SEQ_LENGTH):
184 self.output = output
184 self.output = output
185 self.max_width = max_width
185 self.max_width = max_width
186 self.newline = newline
186 self.newline = newline
187 self.max_seq_length = max_seq_length
187 self.max_seq_length = max_seq_length
188 self.output_width = 0
188 self.output_width = 0
189 self.buffer_width = 0
189 self.buffer_width = 0
190 self.buffer = deque()
190 self.buffer = deque()
191
191
192 root_group = Group(0)
192 root_group = Group(0)
193 self.group_stack = [root_group]
193 self.group_stack = [root_group]
194 self.group_queue = GroupQueue(root_group)
194 self.group_queue = GroupQueue(root_group)
195 self.indentation = 0
195 self.indentation = 0
196
196
197 def _break_outer_groups(self):
197 def _break_outer_groups(self):
198 while self.max_width < self.output_width + self.buffer_width:
198 while self.max_width < self.output_width + self.buffer_width:
199 group = self.group_queue.deq()
199 group = self.group_queue.deq()
200 if not group:
200 if not group:
201 return
201 return
202 while group.breakables:
202 while group.breakables:
203 x = self.buffer.popleft()
203 x = self.buffer.popleft()
204 self.output_width = x.output(self.output, self.output_width)
204 self.output_width = x.output(self.output, self.output_width)
205 self.buffer_width -= x.width
205 self.buffer_width -= x.width
206 while self.buffer and isinstance(self.buffer[0], Text):
206 while self.buffer and isinstance(self.buffer[0], Text):
207 x = self.buffer.popleft()
207 x = self.buffer.popleft()
208 self.output_width = x.output(self.output, self.output_width)
208 self.output_width = x.output(self.output, self.output_width)
209 self.buffer_width -= x.width
209 self.buffer_width -= x.width
210
210
211 def text(self, obj):
211 def text(self, obj):
212 """Add literal text to the output."""
212 """Add literal text to the output."""
213 width = len(obj)
213 width = len(obj)
214 if self.buffer:
214 if self.buffer:
215 text = self.buffer[-1]
215 text = self.buffer[-1]
216 if not isinstance(text, Text):
216 if not isinstance(text, Text):
217 text = Text()
217 text = Text()
218 self.buffer.append(text)
218 self.buffer.append(text)
219 text.add(obj, width)
219 text.add(obj, width)
220 self.buffer_width += width
220 self.buffer_width += width
221 self._break_outer_groups()
221 self._break_outer_groups()
222 else:
222 else:
223 self.output.write(obj)
223 self.output.write(obj)
224 self.output_width += width
224 self.output_width += width
225
225
226 def breakable(self, sep=' '):
226 def breakable(self, sep=' '):
227 """
227 """
228 Add a breakable separator to the output. This does not mean that it
228 Add a breakable separator to the output. This does not mean that it
229 will automatically break here. If no breaking on this position takes
229 will automatically break here. If no breaking on this position takes
230 place the `sep` is inserted which default to one space.
230 place the `sep` is inserted which default to one space.
231 """
231 """
232 width = len(sep)
232 width = len(sep)
233 group = self.group_stack[-1]
233 group = self.group_stack[-1]
234 if group.want_break:
234 if group.want_break:
235 self.flush()
235 self.flush()
236 self.output.write(self.newline)
236 self.output.write(self.newline)
237 self.output.write(' ' * self.indentation)
237 self.output.write(' ' * self.indentation)
238 self.output_width = self.indentation
238 self.output_width = self.indentation
239 self.buffer_width = 0
239 self.buffer_width = 0
240 else:
240 else:
241 self.buffer.append(Breakable(sep, width, self))
241 self.buffer.append(Breakable(sep, width, self))
242 self.buffer_width += width
242 self.buffer_width += width
243 self._break_outer_groups()
243 self._break_outer_groups()
244
244
245 def break_(self):
245 def break_(self):
246 """
246 """
247 Explicitly insert a newline into the output, maintaining correct indentation.
247 Explicitly insert a newline into the output, maintaining correct indentation.
248 """
248 """
249 self.flush()
249 self.flush()
250 self.output.write(self.newline)
250 self.output.write(self.newline)
251 self.output.write(' ' * self.indentation)
251 self.output.write(' ' * self.indentation)
252 self.output_width = self.indentation
252 self.output_width = self.indentation
253 self.buffer_width = 0
253 self.buffer_width = 0
254
254
255
255
256 def begin_group(self, indent=0, open=''):
256 def begin_group(self, indent=0, open=''):
257 """
257 """
258 Begin a group. If you want support for python < 2.5 which doesn't has
258 Begin a group. If you want support for python < 2.5 which doesn't has
259 the with statement this is the preferred way:
259 the with statement this is the preferred way:
260
260
261 p.begin_group(1, '{')
261 p.begin_group(1, '{')
262 ...
262 ...
263 p.end_group(1, '}')
263 p.end_group(1, '}')
264
264
265 The python 2.5 expression would be this:
265 The python 2.5 expression would be this:
266
266
267 with p.group(1, '{', '}'):
267 with p.group(1, '{', '}'):
268 ...
268 ...
269
269
270 The first parameter specifies the indentation for the next line (usually
270 The first parameter specifies the indentation for the next line (usually
271 the width of the opening text), the second the opening text. All
271 the width of the opening text), the second the opening text. All
272 parameters are optional.
272 parameters are optional.
273 """
273 """
274 if open:
274 if open:
275 self.text(open)
275 self.text(open)
276 group = Group(self.group_stack[-1].depth + 1)
276 group = Group(self.group_stack[-1].depth + 1)
277 self.group_stack.append(group)
277 self.group_stack.append(group)
278 self.group_queue.enq(group)
278 self.group_queue.enq(group)
279 self.indentation += indent
279 self.indentation += indent
280
280
281 def _enumerate(self, seq):
281 def _enumerate(self, seq):
282 """like enumerate, but with an upper limit on the number of items"""
282 """like enumerate, but with an upper limit on the number of items"""
283 for idx, x in enumerate(seq):
283 for idx, x in enumerate(seq):
284 if self.max_seq_length and idx >= self.max_seq_length:
284 if self.max_seq_length and idx >= self.max_seq_length:
285 self.text(',')
285 self.text(',')
286 self.breakable()
286 self.breakable()
287 self.text('...')
287 self.text('...')
288 return
288 return
289 yield idx, x
289 yield idx, x
290
290
291 def end_group(self, dedent=0, close=''):
291 def end_group(self, dedent=0, close=''):
292 """End a group. See `begin_group` for more details."""
292 """End a group. See `begin_group` for more details."""
293 self.indentation -= dedent
293 self.indentation -= dedent
294 group = self.group_stack.pop()
294 group = self.group_stack.pop()
295 if not group.breakables:
295 if not group.breakables:
296 self.group_queue.remove(group)
296 self.group_queue.remove(group)
297 if close:
297 if close:
298 self.text(close)
298 self.text(close)
299
299
300 def flush(self):
300 def flush(self):
301 """Flush data that is left in the buffer."""
301 """Flush data that is left in the buffer."""
302 for data in self.buffer:
302 for data in self.buffer:
303 self.output_width += data.output(self.output, self.output_width)
303 self.output_width += data.output(self.output, self.output_width)
304 self.buffer.clear()
304 self.buffer.clear()
305 self.buffer_width = 0
305 self.buffer_width = 0
306
306
307
307
308 def _get_mro(obj_class):
308 def _get_mro(obj_class):
309 """ Get a reasonable method resolution order of a class and its superclasses
309 """ Get a reasonable method resolution order of a class and its superclasses
310 for both old-style and new-style classes.
310 for both old-style and new-style classes.
311 """
311 """
312 if not hasattr(obj_class, '__mro__'):
312 if not hasattr(obj_class, '__mro__'):
313 # Old-style class. Mix in object to make a fake new-style class.
313 # Old-style class. Mix in object to make a fake new-style class.
314 try:
314 try:
315 obj_class = type(obj_class.__name__, (obj_class, object), {})
315 obj_class = type(obj_class.__name__, (obj_class, object), {})
316 except TypeError:
316 except TypeError:
317 # Old-style extension type that does not descend from object.
317 # Old-style extension type that does not descend from object.
318 # FIXME: try to construct a more thorough MRO.
318 # FIXME: try to construct a more thorough MRO.
319 mro = [obj_class]
319 mro = [obj_class]
320 else:
320 else:
321 mro = obj_class.__mro__[1:-1]
321 mro = obj_class.__mro__[1:-1]
322 else:
322 else:
323 mro = obj_class.__mro__
323 mro = obj_class.__mro__
324 return mro
324 return mro
325
325
326
326
327 class RepresentationPrinter(PrettyPrinter):
327 class RepresentationPrinter(PrettyPrinter):
328 """
328 """
329 Special pretty printer that has a `pretty` method that calls the pretty
329 Special pretty printer that has a `pretty` method that calls the pretty
330 printer for a python object.
330 printer for a python object.
331
331
332 This class stores processing data on `self` so you must *never* use
332 This class stores processing data on `self` so you must *never* use
333 this class in a threaded environment. Always lock it or reinstanciate
333 this class in a threaded environment. Always lock it or reinstanciate
334 it.
334 it.
335
335
336 Instances also have a verbose flag callbacks can access to control their
336 Instances also have a verbose flag callbacks can access to control their
337 output. For example the default instance repr prints all attributes and
337 output. For example the default instance repr prints all attributes and
338 methods that are not prefixed by an underscore if the printer is in
338 methods that are not prefixed by an underscore if the printer is in
339 verbose mode.
339 verbose mode.
340 """
340 """
341
341
342 def __init__(self, output, verbose=False, max_width=79, newline='\n',
342 def __init__(self, output, verbose=False, max_width=79, newline='\n',
343 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
343 singleton_pprinters=None, type_pprinters=None, deferred_pprinters=None,
344 max_seq_length=MAX_SEQ_LENGTH):
344 max_seq_length=MAX_SEQ_LENGTH):
345
345
346 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
346 PrettyPrinter.__init__(self, output, max_width, newline, max_seq_length=max_seq_length)
347 self.verbose = verbose
347 self.verbose = verbose
348 self.stack = []
348 self.stack = []
349 if singleton_pprinters is None:
349 if singleton_pprinters is None:
350 singleton_pprinters = _singleton_pprinters.copy()
350 singleton_pprinters = _singleton_pprinters.copy()
351 self.singleton_pprinters = singleton_pprinters
351 self.singleton_pprinters = singleton_pprinters
352 if type_pprinters is None:
352 if type_pprinters is None:
353 type_pprinters = _type_pprinters.copy()
353 type_pprinters = _type_pprinters.copy()
354 self.type_pprinters = type_pprinters
354 self.type_pprinters = type_pprinters
355 if deferred_pprinters is None:
355 if deferred_pprinters is None:
356 deferred_pprinters = _deferred_type_pprinters.copy()
356 deferred_pprinters = _deferred_type_pprinters.copy()
357 self.deferred_pprinters = deferred_pprinters
357 self.deferred_pprinters = deferred_pprinters
358
358
359 def pretty(self, obj):
359 def pretty(self, obj):
360 """Pretty print the given object."""
360 """Pretty print the given object."""
361 obj_id = id(obj)
361 obj_id = id(obj)
362 cycle = obj_id in self.stack
362 cycle = obj_id in self.stack
363 self.stack.append(obj_id)
363 self.stack.append(obj_id)
364 self.begin_group()
364 self.begin_group()
365 try:
365 try:
366 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
366 obj_class = _safe_getattr(obj, '__class__', None) or type(obj)
367 # First try to find registered singleton printers for the type.
367 # First try to find registered singleton printers for the type.
368 try:
368 try:
369 printer = self.singleton_pprinters[obj_id]
369 printer = self.singleton_pprinters[obj_id]
370 except (TypeError, KeyError):
370 except (TypeError, KeyError):
371 pass
371 pass
372 else:
372 else:
373 return printer(obj, self, cycle)
373 return printer(obj, self, cycle)
374 # Next walk the mro and check for either:
374 # Next walk the mro and check for either:
375 # 1) a registered printer
375 # 1) a registered printer
376 # 2) a _repr_pretty_ method
376 # 2) a _repr_pretty_ method
377 for cls in _get_mro(obj_class):
377 for cls in _get_mro(obj_class):
378 if cls in self.type_pprinters:
378 if cls in self.type_pprinters:
379 # printer registered in self.type_pprinters
379 # printer registered in self.type_pprinters
380 return self.type_pprinters[cls](obj, self, cycle)
380 return self.type_pprinters[cls](obj, self, cycle)
381 else:
381 else:
382 # deferred printer
382 # deferred printer
383 printer = self._in_deferred_types(cls)
383 printer = self._in_deferred_types(cls)
384 if printer is not None:
384 if printer is not None:
385 return printer(obj, self, cycle)
385 return printer(obj, self, cycle)
386 else:
386 else:
387 # Finally look for special method names.
387 # Finally look for special method names.
388 # Some objects automatically create any requested
388 # Some objects automatically create any requested
389 # attribute. Try to ignore most of them by checking for
389 # attribute. Try to ignore most of them by checking for
390 # callability.
390 # callability.
391 if '_repr_pretty_' in cls.__dict__:
391 if '_repr_pretty_' in cls.__dict__:
392 meth = cls._repr_pretty_
392 meth = cls._repr_pretty_
393 if callable(meth):
393 if callable(meth):
394 return meth(obj, self, cycle)
394 return meth(obj, self, cycle)
395 return _default_pprint(obj, self, cycle)
395 return _default_pprint(obj, self, cycle)
396 finally:
396 finally:
397 self.end_group()
397 self.end_group()
398 self.stack.pop()
398 self.stack.pop()
399
399
400 def _in_deferred_types(self, cls):
400 def _in_deferred_types(self, cls):
401 """
401 """
402 Check if the given class is specified in the deferred type registry.
402 Check if the given class is specified in the deferred type registry.
403
403
404 Returns the printer from the registry if it exists, and None if the
404 Returns the printer from the registry if it exists, and None if the
405 class is not in the registry. Successful matches will be moved to the
405 class is not in the registry. Successful matches will be moved to the
406 regular type registry for future use.
406 regular type registry for future use.
407 """
407 """
408 mod = _safe_getattr(cls, '__module__', None)
408 mod = _safe_getattr(cls, '__module__', None)
409 name = _safe_getattr(cls, '__name__', None)
409 name = _safe_getattr(cls, '__name__', None)
410 key = (mod, name)
410 key = (mod, name)
411 printer = None
411 printer = None
412 if key in self.deferred_pprinters:
412 if key in self.deferred_pprinters:
413 # Move the printer over to the regular registry.
413 # Move the printer over to the regular registry.
414 printer = self.deferred_pprinters.pop(key)
414 printer = self.deferred_pprinters.pop(key)
415 self.type_pprinters[cls] = printer
415 self.type_pprinters[cls] = printer
416 return printer
416 return printer
417
417
418
418
419 class Printable(object):
419 class Printable(object):
420
420
421 def output(self, stream, output_width):
421 def output(self, stream, output_width):
422 return output_width
422 return output_width
423
423
424
424
425 class Text(Printable):
425 class Text(Printable):
426
426
427 def __init__(self):
427 def __init__(self):
428 self.objs = []
428 self.objs = []
429 self.width = 0
429 self.width = 0
430
430
431 def output(self, stream, output_width):
431 def output(self, stream, output_width):
432 for obj in self.objs:
432 for obj in self.objs:
433 stream.write(obj)
433 stream.write(obj)
434 return output_width + self.width
434 return output_width + self.width
435
435
436 def add(self, obj, width):
436 def add(self, obj, width):
437 self.objs.append(obj)
437 self.objs.append(obj)
438 self.width += width
438 self.width += width
439
439
440
440
441 class Breakable(Printable):
441 class Breakable(Printable):
442
442
443 def __init__(self, seq, width, pretty):
443 def __init__(self, seq, width, pretty):
444 self.obj = seq
444 self.obj = seq
445 self.width = width
445 self.width = width
446 self.pretty = pretty
446 self.pretty = pretty
447 self.indentation = pretty.indentation
447 self.indentation = pretty.indentation
448 self.group = pretty.group_stack[-1]
448 self.group = pretty.group_stack[-1]
449 self.group.breakables.append(self)
449 self.group.breakables.append(self)
450
450
451 def output(self, stream, output_width):
451 def output(self, stream, output_width):
452 self.group.breakables.popleft()
452 self.group.breakables.popleft()
453 if self.group.want_break:
453 if self.group.want_break:
454 stream.write(self.pretty.newline)
454 stream.write(self.pretty.newline)
455 stream.write(' ' * self.indentation)
455 stream.write(' ' * self.indentation)
456 return self.indentation
456 return self.indentation
457 if not self.group.breakables:
457 if not self.group.breakables:
458 self.pretty.group_queue.remove(self.group)
458 self.pretty.group_queue.remove(self.group)
459 stream.write(self.obj)
459 stream.write(self.obj)
460 return output_width + self.width
460 return output_width + self.width
461
461
462
462
463 class Group(Printable):
463 class Group(Printable):
464
464
465 def __init__(self, depth):
465 def __init__(self, depth):
466 self.depth = depth
466 self.depth = depth
467 self.breakables = deque()
467 self.breakables = deque()
468 self.want_break = False
468 self.want_break = False
469
469
470
470
471 class GroupQueue(object):
471 class GroupQueue(object):
472
472
473 def __init__(self, *groups):
473 def __init__(self, *groups):
474 self.queue = []
474 self.queue = []
475 for group in groups:
475 for group in groups:
476 self.enq(group)
476 self.enq(group)
477
477
478 def enq(self, group):
478 def enq(self, group):
479 depth = group.depth
479 depth = group.depth
480 while depth > len(self.queue) - 1:
480 while depth > len(self.queue) - 1:
481 self.queue.append([])
481 self.queue.append([])
482 self.queue[depth].append(group)
482 self.queue[depth].append(group)
483
483
484 def deq(self):
484 def deq(self):
485 for stack in self.queue:
485 for stack in self.queue:
486 for idx, group in enumerate(reversed(stack)):
486 for idx, group in enumerate(reversed(stack)):
487 if group.breakables:
487 if group.breakables:
488 del stack[idx]
488 del stack[idx]
489 group.want_break = True
489 group.want_break = True
490 return group
490 return group
491 for group in stack:
491 for group in stack:
492 group.want_break = True
492 group.want_break = True
493 del stack[:]
493 del stack[:]
494
494
495 def remove(self, group):
495 def remove(self, group):
496 try:
496 try:
497 self.queue[group.depth].remove(group)
497 self.queue[group.depth].remove(group)
498 except ValueError:
498 except ValueError:
499 pass
499 pass
500
500
501
501
502 def _default_pprint(obj, p, cycle):
502 def _default_pprint(obj, p, cycle):
503 """
503 """
504 The default print function. Used if an object does not provide one and
504 The default print function. Used if an object does not provide one and
505 it's none of the builtin objects.
505 it's none of the builtin objects.
506 """
506 """
507 klass = _safe_getattr(obj, '__class__', None) or type(obj)
507 klass = _safe_getattr(obj, '__class__', None) or type(obj)
508 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
508 if _safe_getattr(klass, '__repr__', None) is not object.__repr__:
509 # A user-provided repr. Find newlines and replace them with p.break_()
509 # A user-provided repr. Find newlines and replace them with p.break_()
510 _repr_pprint(obj, p, cycle)
510 _repr_pprint(obj, p, cycle)
511 return
511 return
512 p.begin_group(1, '<')
512 p.begin_group(1, '<')
513 p.pretty(klass)
513 p.pretty(klass)
514 p.text(' at 0x%x' % id(obj))
514 p.text(' at 0x%x' % id(obj))
515 if cycle:
515 if cycle:
516 p.text(' ...')
516 p.text(' ...')
517 elif p.verbose:
517 elif p.verbose:
518 first = True
518 first = True
519 for key in dir(obj):
519 for key in dir(obj):
520 if not key.startswith('_'):
520 if not key.startswith('_'):
521 try:
521 try:
522 value = getattr(obj, key)
522 value = getattr(obj, key)
523 except AttributeError:
523 except AttributeError:
524 continue
524 continue
525 if isinstance(value, types.MethodType):
525 if isinstance(value, types.MethodType):
526 continue
526 continue
527 if not first:
527 if not first:
528 p.text(',')
528 p.text(',')
529 p.breakable()
529 p.breakable()
530 p.text(key)
530 p.text(key)
531 p.text('=')
531 p.text('=')
532 step = len(key) + 1
532 step = len(key) + 1
533 p.indentation += step
533 p.indentation += step
534 p.pretty(value)
534 p.pretty(value)
535 p.indentation -= step
535 p.indentation -= step
536 first = False
536 first = False
537 p.end_group(1, '>')
537 p.end_group(1, '>')
538
538
539
539
540 def _seq_pprinter_factory(start, end, basetype):
540 def _seq_pprinter_factory(start, end, basetype):
541 """
541 """
542 Factory that returns a pprint function useful for sequences. Used by
542 Factory that returns a pprint function useful for sequences. Used by
543 the default pprint for tuples, dicts, and lists.
543 the default pprint for tuples, dicts, and lists.
544 """
544 """
545 def inner(obj, p, cycle):
545 def inner(obj, p, cycle):
546 typ = type(obj)
546 typ = type(obj)
547 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
547 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
548 # If the subclass provides its own repr, use it instead.
548 # If the subclass provides its own repr, use it instead.
549 return p.text(typ.__repr__(obj))
549 return p.text(typ.__repr__(obj))
550
550
551 if cycle:
551 if cycle:
552 return p.text(start + '...' + end)
552 return p.text(start + '...' + end)
553 step = len(start)
553 step = len(start)
554 p.begin_group(step, start)
554 p.begin_group(step, start)
555 for idx, x in p._enumerate(obj):
555 for idx, x in p._enumerate(obj):
556 if idx:
556 if idx:
557 p.text(',')
557 p.text(',')
558 p.breakable()
558 p.breakable()
559 p.pretty(x)
559 p.pretty(x)
560 if len(obj) == 1 and type(obj) is tuple:
560 if len(obj) == 1 and type(obj) is tuple:
561 # Special case for 1-item tuples.
561 # Special case for 1-item tuples.
562 p.text(',')
562 p.text(',')
563 p.end_group(step, end)
563 p.end_group(step, end)
564 return inner
564 return inner
565
565
566
566
567 def _set_pprinter_factory(start, end, basetype):
567 def _set_pprinter_factory(start, end, basetype):
568 """
568 """
569 Factory that returns a pprint function useful for sets and frozensets.
569 Factory that returns a pprint function useful for sets and frozensets.
570 """
570 """
571 def inner(obj, p, cycle):
571 def inner(obj, p, cycle):
572 typ = type(obj)
572 typ = type(obj)
573 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
573 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
574 # If the subclass provides its own repr, use it instead.
574 # If the subclass provides its own repr, use it instead.
575 return p.text(typ.__repr__(obj))
575 return p.text(typ.__repr__(obj))
576
576
577 if cycle:
577 if cycle:
578 return p.text(start + '...' + end)
578 return p.text(start + '...' + end)
579 if len(obj) == 0:
579 if len(obj) == 0:
580 # Special case.
580 # Special case.
581 p.text(basetype.__name__ + '()')
581 p.text(basetype.__name__ + '()')
582 else:
582 else:
583 step = len(start)
583 step = len(start)
584 p.begin_group(step, start)
584 p.begin_group(step, start)
585 # Like dictionary keys, we will try to sort the items if there aren't too many
585 # Like dictionary keys, we will try to sort the items if there aren't too many
586 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
586 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
587 items = _sorted_for_pprint(obj)
587 items = _sorted_for_pprint(obj)
588 else:
588 else:
589 items = obj
589 items = obj
590 for idx, x in p._enumerate(items):
590 for idx, x in p._enumerate(items):
591 if idx:
591 if idx:
592 p.text(',')
592 p.text(',')
593 p.breakable()
593 p.breakable()
594 p.pretty(x)
594 p.pretty(x)
595 p.end_group(step, end)
595 p.end_group(step, end)
596 return inner
596 return inner
597
597
598
598
599 def _dict_pprinter_factory(start, end, basetype=None):
599 def _dict_pprinter_factory(start, end, basetype=None):
600 """
600 """
601 Factory that returns a pprint function used by the default pprint of
601 Factory that returns a pprint function used by the default pprint of
602 dicts and dict proxies.
602 dicts and dict proxies.
603 """
603 """
604 def inner(obj, p, cycle):
604 def inner(obj, p, cycle):
605 typ = type(obj)
605 typ = type(obj)
606 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
606 if basetype is not None and typ is not basetype and typ.__repr__ != basetype.__repr__:
607 # If the subclass provides its own repr, use it instead.
607 # If the subclass provides its own repr, use it instead.
608 return p.text(typ.__repr__(obj))
608 return p.text(typ.__repr__(obj))
609
609
610 if cycle:
610 if cycle:
611 return p.text('{...}')
611 return p.text('{...}')
612 step = len(start)
612 step = len(start)
613 p.begin_group(step, start)
613 p.begin_group(step, start)
614 keys = obj.keys()
614 keys = obj.keys()
615 # if dict isn't large enough to be truncated, sort keys before displaying
615 # if dict isn't large enough to be truncated, sort keys before displaying
616 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
616 if not (p.max_seq_length and len(obj) >= p.max_seq_length):
617 keys = _sorted_for_pprint(keys)
617 keys = _sorted_for_pprint(keys)
618 for idx, key in p._enumerate(keys):
618 for idx, key in p._enumerate(keys):
619 if idx:
619 if idx:
620 p.text(',')
620 p.text(',')
621 p.breakable()
621 p.breakable()
622 p.pretty(key)
622 p.pretty(key)
623 p.text(': ')
623 p.text(': ')
624 p.pretty(obj[key])
624 p.pretty(obj[key])
625 p.end_group(step, end)
625 p.end_group(step, end)
626 return inner
626 return inner
627
627
628
628
629 def _super_pprint(obj, p, cycle):
629 def _super_pprint(obj, p, cycle):
630 """The pprint for the super type."""
630 """The pprint for the super type."""
631 p.begin_group(8, '<super: ')
631 p.begin_group(8, '<super: ')
632 p.pretty(obj.__thisclass__)
632 p.pretty(obj.__thisclass__)
633 p.text(',')
633 p.text(',')
634 p.breakable()
634 p.breakable()
635 if PYPY: # In PyPy, super() objects don't have __self__ attributes
635 if PYPY: # In PyPy, super() objects don't have __self__ attributes
636 dself = obj.__repr__.__self__
636 dself = obj.__repr__.__self__
637 p.pretty(None if dself is obj else dself)
637 p.pretty(None if dself is obj else dself)
638 else:
638 else:
639 p.pretty(obj.__self__)
639 p.pretty(obj.__self__)
640 p.end_group(8, '>')
640 p.end_group(8, '>')
641
641
642
642
643 def _re_pattern_pprint(obj, p, cycle):
643 def _re_pattern_pprint(obj, p, cycle):
644 """The pprint function for regular expression patterns."""
644 """The pprint function for regular expression patterns."""
645 p.text('re.compile(')
645 p.text('re.compile(')
646 pattern = repr(obj.pattern)
646 pattern = repr(obj.pattern)
647 if pattern[:1] in 'uU':
647 if pattern[:1] in 'uU':
648 pattern = pattern[1:]
648 pattern = pattern[1:]
649 prefix = 'ur'
649 prefix = 'ur'
650 else:
650 else:
651 prefix = 'r'
651 prefix = 'r'
652 pattern = prefix + pattern.replace('\\\\', '\\')
652 pattern = prefix + pattern.replace('\\\\', '\\')
653 p.text(pattern)
653 p.text(pattern)
654 if obj.flags:
654 if obj.flags:
655 p.text(',')
655 p.text(',')
656 p.breakable()
656 p.breakable()
657 done_one = False
657 done_one = False
658 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
658 for flag in ('TEMPLATE', 'IGNORECASE', 'LOCALE', 'MULTILINE', 'DOTALL',
659 'UNICODE', 'VERBOSE', 'DEBUG'):
659 'UNICODE', 'VERBOSE', 'DEBUG'):
660 if obj.flags & getattr(re, flag):
660 if obj.flags & getattr(re, flag):
661 if done_one:
661 if done_one:
662 p.text('|')
662 p.text('|')
663 p.text('re.' + flag)
663 p.text('re.' + flag)
664 done_one = True
664 done_one = True
665 p.text(')')
665 p.text(')')
666
666
667
667
668 def _type_pprint(obj, p, cycle):
668 def _type_pprint(obj, p, cycle):
669 """The pprint for classes and types."""
669 """The pprint for classes and types."""
670 # Heap allocated types might not have the module attribute,
670 # Heap allocated types might not have the module attribute,
671 # and others may set it to None.
671 # and others may set it to None.
672
672
673 # Checks for a __repr__ override in the metaclass. Can't compare the
673 # Checks for a __repr__ override in the metaclass. Can't compare the
674 # type(obj).__repr__ directly because in PyPy the representation function
674 # type(obj).__repr__ directly because in PyPy the representation function
675 # inherited from type isn't the same type.__repr__
675 # inherited from type isn't the same type.__repr__
676 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
676 if [m for m in _get_mro(type(obj)) if "__repr__" in vars(m)][:1] != [type]:
677 _repr_pprint(obj, p, cycle)
677 _repr_pprint(obj, p, cycle)
678 return
678 return
679
679
680 mod = _safe_getattr(obj, '__module__', None)
680 mod = _safe_getattr(obj, '__module__', None)
681 try:
681 try:
682 name = obj.__qualname__
682 name = obj.__qualname__
683 if not isinstance(name, str):
683 if not isinstance(name, str):
684 # This can happen if the type implements __qualname__ as a property
684 # This can happen if the type implements __qualname__ as a property
685 # or other descriptor in Python 2.
685 # or other descriptor in Python 2.
686 raise Exception("Try __name__")
686 raise Exception("Try __name__")
687 except Exception:
687 except Exception:
688 name = obj.__name__
688 name = obj.__name__
689 if not isinstance(name, str):
689 if not isinstance(name, str):
690 name = '<unknown type>'
690 name = '<unknown type>'
691
691
692 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
692 if mod in (None, '__builtin__', 'builtins', 'exceptions'):
693 p.text(name)
693 p.text(name)
694 else:
694 else:
695 p.text(mod + '.' + name)
695 p.text(mod + '.' + name)
696
696
697
697
698 def _repr_pprint(obj, p, cycle):
698 def _repr_pprint(obj, p, cycle):
699 """A pprint that just redirects to the normal repr function."""
699 """A pprint that just redirects to the normal repr function."""
700 # Find newlines and replace them with p.break_()
700 # Find newlines and replace them with p.break_()
701 output = repr(obj)
701 output = repr(obj)
702 for idx,output_line in enumerate(output.splitlines()):
702 for idx,output_line in enumerate(output.splitlines()):
703 if idx:
703 if idx:
704 p.break_()
704 p.break_()
705 p.text(output_line)
705 p.text(output_line)
706
706
707
707
708 def _function_pprint(obj, p, cycle):
708 def _function_pprint(obj, p, cycle):
709 """Base pprint for all functions and builtin functions."""
709 """Base pprint for all functions and builtin functions."""
710 name = _safe_getattr(obj, '__qualname__', obj.__name__)
710 name = _safe_getattr(obj, '__qualname__', obj.__name__)
711 mod = obj.__module__
711 mod = obj.__module__
712 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
712 if mod and mod not in ('__builtin__', 'builtins', 'exceptions'):
713 name = mod + '.' + name
713 name = mod + '.' + name
714 p.text('<function %s>' % name)
714 try:
715 func_def = name + str(signature(obj))
716 except ValueError:
717 func_def = name
718 p.text('<function %s>' % func_def)
715
719
716
720
717 def _exception_pprint(obj, p, cycle):
721 def _exception_pprint(obj, p, cycle):
718 """Base pprint for all exceptions."""
722 """Base pprint for all exceptions."""
719 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
723 name = getattr(obj.__class__, '__qualname__', obj.__class__.__name__)
720 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
724 if obj.__class__.__module__ not in ('exceptions', 'builtins'):
721 name = '%s.%s' % (obj.__class__.__module__, name)
725 name = '%s.%s' % (obj.__class__.__module__, name)
722 step = len(name) + 1
726 step = len(name) + 1
723 p.begin_group(step, name + '(')
727 p.begin_group(step, name + '(')
724 for idx, arg in enumerate(getattr(obj, 'args', ())):
728 for idx, arg in enumerate(getattr(obj, 'args', ())):
725 if idx:
729 if idx:
726 p.text(',')
730 p.text(',')
727 p.breakable()
731 p.breakable()
728 p.pretty(arg)
732 p.pretty(arg)
729 p.end_group(step, ')')
733 p.end_group(step, ')')
730
734
731
735
732 #: the exception base
736 #: the exception base
733 try:
737 try:
734 _exception_base = BaseException
738 _exception_base = BaseException
735 except NameError:
739 except NameError:
736 _exception_base = Exception
740 _exception_base = Exception
737
741
738
742
739 #: printers for builtin types
743 #: printers for builtin types
740 _type_pprinters = {
744 _type_pprinters = {
741 int: _repr_pprint,
745 int: _repr_pprint,
742 float: _repr_pprint,
746 float: _repr_pprint,
743 str: _repr_pprint,
747 str: _repr_pprint,
744 tuple: _seq_pprinter_factory('(', ')', tuple),
748 tuple: _seq_pprinter_factory('(', ')', tuple),
745 list: _seq_pprinter_factory('[', ']', list),
749 list: _seq_pprinter_factory('[', ']', list),
746 dict: _dict_pprinter_factory('{', '}', dict),
750 dict: _dict_pprinter_factory('{', '}', dict),
747
751
748 set: _set_pprinter_factory('{', '}', set),
752 set: _set_pprinter_factory('{', '}', set),
749 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
753 frozenset: _set_pprinter_factory('frozenset({', '})', frozenset),
750 super: _super_pprint,
754 super: _super_pprint,
751 _re_pattern_type: _re_pattern_pprint,
755 _re_pattern_type: _re_pattern_pprint,
752 type: _type_pprint,
756 type: _type_pprint,
753 types.FunctionType: _function_pprint,
757 types.FunctionType: _function_pprint,
754 types.BuiltinFunctionType: _function_pprint,
758 types.BuiltinFunctionType: _function_pprint,
755 types.MethodType: _repr_pprint,
759 types.MethodType: _repr_pprint,
756
760
757 datetime.datetime: _repr_pprint,
761 datetime.datetime: _repr_pprint,
758 datetime.timedelta: _repr_pprint,
762 datetime.timedelta: _repr_pprint,
759 _exception_base: _exception_pprint
763 _exception_base: _exception_pprint
760 }
764 }
761
765
762 try:
766 try:
763 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
767 # In PyPy, types.DictProxyType is dict, setting the dictproxy printer
764 # using dict.setdefault avoids overwritting the dict printer
768 # using dict.setdefault avoids overwritting the dict printer
765 _type_pprinters.setdefault(types.DictProxyType,
769 _type_pprinters.setdefault(types.DictProxyType,
766 _dict_pprinter_factory('dict_proxy({', '})'))
770 _dict_pprinter_factory('dict_proxy({', '})'))
767 _type_pprinters[types.ClassType] = _type_pprint
771 _type_pprinters[types.ClassType] = _type_pprint
768 _type_pprinters[types.SliceType] = _repr_pprint
772 _type_pprinters[types.SliceType] = _repr_pprint
769 except AttributeError: # Python 3
773 except AttributeError: # Python 3
770 _type_pprinters[types.MappingProxyType] = \
774 _type_pprinters[types.MappingProxyType] = \
771 _dict_pprinter_factory('mappingproxy({', '})')
775 _dict_pprinter_factory('mappingproxy({', '})')
772 _type_pprinters[slice] = _repr_pprint
776 _type_pprinters[slice] = _repr_pprint
773
777
774 try:
778 try:
775 _type_pprinters[long] = _repr_pprint
779 _type_pprinters[long] = _repr_pprint
776 _type_pprinters[unicode] = _repr_pprint
780 _type_pprinters[unicode] = _repr_pprint
777 except NameError:
781 except NameError:
778 _type_pprinters[range] = _repr_pprint
782 _type_pprinters[range] = _repr_pprint
779 _type_pprinters[bytes] = _repr_pprint
783 _type_pprinters[bytes] = _repr_pprint
780
784
781 #: printers for types specified by name
785 #: printers for types specified by name
782 _deferred_type_pprinters = {
786 _deferred_type_pprinters = {
783 }
787 }
784
788
785 def for_type(typ, func):
789 def for_type(typ, func):
786 """
790 """
787 Add a pretty printer for a given type.
791 Add a pretty printer for a given type.
788 """
792 """
789 oldfunc = _type_pprinters.get(typ, None)
793 oldfunc = _type_pprinters.get(typ, None)
790 if func is not None:
794 if func is not None:
791 # To support easy restoration of old pprinters, we need to ignore Nones.
795 # To support easy restoration of old pprinters, we need to ignore Nones.
792 _type_pprinters[typ] = func
796 _type_pprinters[typ] = func
793 return oldfunc
797 return oldfunc
794
798
795 def for_type_by_name(type_module, type_name, func):
799 def for_type_by_name(type_module, type_name, func):
796 """
800 """
797 Add a pretty printer for a type specified by the module and name of a type
801 Add a pretty printer for a type specified by the module and name of a type
798 rather than the type object itself.
802 rather than the type object itself.
799 """
803 """
800 key = (type_module, type_name)
804 key = (type_module, type_name)
801 oldfunc = _deferred_type_pprinters.get(key, None)
805 oldfunc = _deferred_type_pprinters.get(key, None)
802 if func is not None:
806 if func is not None:
803 # To support easy restoration of old pprinters, we need to ignore Nones.
807 # To support easy restoration of old pprinters, we need to ignore Nones.
804 _deferred_type_pprinters[key] = func
808 _deferred_type_pprinters[key] = func
805 return oldfunc
809 return oldfunc
806
810
807
811
808 #: printers for the default singletons
812 #: printers for the default singletons
809 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
813 _singleton_pprinters = dict.fromkeys(map(id, [None, True, False, Ellipsis,
810 NotImplemented]), _repr_pprint)
814 NotImplemented]), _repr_pprint)
811
815
812
816
813 def _defaultdict_pprint(obj, p, cycle):
817 def _defaultdict_pprint(obj, p, cycle):
814 name = obj.__class__.__name__
818 name = obj.__class__.__name__
815 with p.group(len(name) + 1, name + '(', ')'):
819 with p.group(len(name) + 1, name + '(', ')'):
816 if cycle:
820 if cycle:
817 p.text('...')
821 p.text('...')
818 else:
822 else:
819 p.pretty(obj.default_factory)
823 p.pretty(obj.default_factory)
820 p.text(',')
824 p.text(',')
821 p.breakable()
825 p.breakable()
822 p.pretty(dict(obj))
826 p.pretty(dict(obj))
823
827
824 def _ordereddict_pprint(obj, p, cycle):
828 def _ordereddict_pprint(obj, p, cycle):
825 name = obj.__class__.__name__
829 name = obj.__class__.__name__
826 with p.group(len(name) + 1, name + '(', ')'):
830 with p.group(len(name) + 1, name + '(', ')'):
827 if cycle:
831 if cycle:
828 p.text('...')
832 p.text('...')
829 elif len(obj):
833 elif len(obj):
830 p.pretty(list(obj.items()))
834 p.pretty(list(obj.items()))
831
835
832 def _deque_pprint(obj, p, cycle):
836 def _deque_pprint(obj, p, cycle):
833 name = obj.__class__.__name__
837 name = obj.__class__.__name__
834 with p.group(len(name) + 1, name + '(', ')'):
838 with p.group(len(name) + 1, name + '(', ')'):
835 if cycle:
839 if cycle:
836 p.text('...')
840 p.text('...')
837 else:
841 else:
838 p.pretty(list(obj))
842 p.pretty(list(obj))
839
843
840
844
841 def _counter_pprint(obj, p, cycle):
845 def _counter_pprint(obj, p, cycle):
842 name = obj.__class__.__name__
846 name = obj.__class__.__name__
843 with p.group(len(name) + 1, name + '(', ')'):
847 with p.group(len(name) + 1, name + '(', ')'):
844 if cycle:
848 if cycle:
845 p.text('...')
849 p.text('...')
846 elif len(obj):
850 elif len(obj):
847 p.pretty(dict(obj))
851 p.pretty(dict(obj))
848
852
849 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
853 for_type_by_name('collections', 'defaultdict', _defaultdict_pprint)
850 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
854 for_type_by_name('collections', 'OrderedDict', _ordereddict_pprint)
851 for_type_by_name('collections', 'deque', _deque_pprint)
855 for_type_by_name('collections', 'deque', _deque_pprint)
852 for_type_by_name('collections', 'Counter', _counter_pprint)
856 for_type_by_name('collections', 'Counter', _counter_pprint)
853
857
854 if __name__ == '__main__':
858 if __name__ == '__main__':
855 from random import randrange
859 from random import randrange
856 class Foo(object):
860 class Foo(object):
857 def __init__(self):
861 def __init__(self):
858 self.foo = 1
862 self.foo = 1
859 self.bar = re.compile(r'\s+')
863 self.bar = re.compile(r'\s+')
860 self.blub = dict.fromkeys(range(30), randrange(1, 40))
864 self.blub = dict.fromkeys(range(30), randrange(1, 40))
861 self.hehe = 23424.234234
865 self.hehe = 23424.234234
862 self.list = ["blub", "blah", self]
866 self.list = ["blub", "blah", self]
863
867
864 def get_foo(self):
868 def get_foo(self):
865 print("foo")
869 print("foo")
866
870
867 pprint(Foo(), verbose=True)
871 pprint(Foo(), verbose=True)
@@ -1,407 +1,423
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
409 def test_function_pretty():
410 "Test pretty print of function"
411 # posixpath is a pure python module, its interface is consistent
412 # across Python distributions
413 import posixpath
414 nt.assert_equal(pretty.pretty(posixpath.join), '<function posixpath.join(a, *p)>')
415
416 # custom function
417 def meaning_of_life(question=None):
418 if question:
419 return 42
420 return "Don't panic"
421
422 nt.assert_in('meaning_of_life(question=None)', pretty.pretty(meaning_of_life))
423
General Comments 0
You need to be logged in to leave comments. Login now