##// END OF EJS Templates
Life, the Universe, and Everything
Paul Ivanov -
Show More
@@ -1,454 +1,454 b''
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 import os
8 import os
9 import re
9 import re
10 import sys
10 import sys
11
11
12 import nose.tools as nt
12 import nose.tools as nt
13
13
14 from .. import oinspect
14 from .. import oinspect
15 from IPython.core.magic import (Magics, magics_class, line_magic,
15 from IPython.core.magic import (Magics, magics_class, line_magic,
16 cell_magic, line_cell_magic,
16 cell_magic, line_cell_magic,
17 register_line_magic, register_cell_magic,
17 register_line_magic, register_cell_magic,
18 register_line_cell_magic)
18 register_line_cell_magic)
19 from decorator import decorator
19 from decorator import decorator
20 from IPython.testing.decorators import skipif
20 from IPython.testing.decorators import skipif
21 from IPython.testing.tools import AssertPrints
21 from IPython.testing.tools import AssertPrints
22 from IPython.utils.path import compress_user
22 from IPython.utils.path import compress_user
23 from IPython.utils import py3compat
23 from IPython.utils import py3compat
24 from IPython.utils.signatures import Signature, Parameter
24 from IPython.utils.signatures import Signature, Parameter
25
25
26
26
27 #-----------------------------------------------------------------------------
27 #-----------------------------------------------------------------------------
28 # Globals and constants
28 # Globals and constants
29 #-----------------------------------------------------------------------------
29 #-----------------------------------------------------------------------------
30
30
31 inspector = oinspect.Inspector()
31 inspector = oinspect.Inspector()
32 ip = get_ipython()
32 ip = get_ipython()
33
33
34 #-----------------------------------------------------------------------------
34 #-----------------------------------------------------------------------------
35 # Local utilities
35 # Local utilities
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37
37
38 # WARNING: since this test checks the line number where a function is
38 # WARNING: since this test checks the line number where a function is
39 # defined, if any code is inserted above, the following line will need to be
39 # defined, if any code is inserted above, the following line will need to be
40 # updated. Do NOT insert any whitespace between the next line and the function
40 # updated. Do NOT insert any whitespace between the next line and the function
41 # definition below.
41 # definition below.
42 THIS_LINE_NUMBER = 43 # Put here the actual number of this line
42 THIS_LINE_NUMBER = 42 # Put here the actual number of this line
43
43
44 from unittest import TestCase
44 from unittest import TestCase
45
45
46 class Test(TestCase):
46 class Test(TestCase):
47
47
48 def test_find_source_lines(self):
48 def test_find_source_lines(self):
49 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
49 self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines),
50 THIS_LINE_NUMBER+6)
50 THIS_LINE_NUMBER+6)
51
51
52
52
53 # A couple of utilities to ensure these tests work the same from a source or a
53 # A couple of utilities to ensure these tests work the same from a source or a
54 # binary install
54 # binary install
55 def pyfile(fname):
55 def pyfile(fname):
56 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
56 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
57
57
58
58
59 def match_pyfiles(f1, f2):
59 def match_pyfiles(f1, f2):
60 nt.assert_equal(pyfile(f1), pyfile(f2))
60 nt.assert_equal(pyfile(f1), pyfile(f2))
61
61
62
62
63 def test_find_file():
63 def test_find_file():
64 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
64 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
65
65
66
66
67 def test_find_file_decorated1():
67 def test_find_file_decorated1():
68
68
69 @decorator
69 @decorator
70 def noop1(f):
70 def noop1(f):
71 def wrapper():
71 def wrapper():
72 return f(*a, **kw)
72 return f(*a, **kw)
73 return wrapper
73 return wrapper
74
74
75 @noop1
75 @noop1
76 def f(x):
76 def f(x):
77 "My docstring"
77 "My docstring"
78
78
79 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
79 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
80 nt.assert_equal(f.__doc__, "My docstring")
80 nt.assert_equal(f.__doc__, "My docstring")
81
81
82
82
83 def test_find_file_decorated2():
83 def test_find_file_decorated2():
84
84
85 @decorator
85 @decorator
86 def noop2(f, *a, **kw):
86 def noop2(f, *a, **kw):
87 return f(*a, **kw)
87 return f(*a, **kw)
88
88
89 @noop2
89 @noop2
90 @noop2
90 @noop2
91 @noop2
91 @noop2
92 def f(x):
92 def f(x):
93 "My docstring 2"
93 "My docstring 2"
94
94
95 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
95 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
96 nt.assert_equal(f.__doc__, "My docstring 2")
96 nt.assert_equal(f.__doc__, "My docstring 2")
97
97
98
98
99 def test_find_file_magic():
99 def test_find_file_magic():
100 run = ip.find_line_magic('run')
100 run = ip.find_line_magic('run')
101 nt.assert_not_equal(oinspect.find_file(run), None)
101 nt.assert_not_equal(oinspect.find_file(run), None)
102
102
103
103
104 # A few generic objects we can then inspect in the tests below
104 # A few generic objects we can then inspect in the tests below
105
105
106 class Call(object):
106 class Call(object):
107 """This is the class docstring."""
107 """This is the class docstring."""
108
108
109 def __init__(self, x, y=1):
109 def __init__(self, x, y=1):
110 """This is the constructor docstring."""
110 """This is the constructor docstring."""
111
111
112 def __call__(self, *a, **kw):
112 def __call__(self, *a, **kw):
113 """This is the call docstring."""
113 """This is the call docstring."""
114
114
115 def method(self, x, z=2):
115 def method(self, x, z=2):
116 """Some method's docstring"""
116 """Some method's docstring"""
117
117
118 class HasSignature(object):
118 class HasSignature(object):
119 """This is the class docstring."""
119 """This is the class docstring."""
120 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
120 __signature__ = Signature([Parameter('test', Parameter.POSITIONAL_OR_KEYWORD)])
121
121
122 def __init__(self, *args):
122 def __init__(self, *args):
123 """This is the init docstring"""
123 """This is the init docstring"""
124
124
125
125
126 class SimpleClass(object):
126 class SimpleClass(object):
127 def method(self, x, z=2):
127 def method(self, x, z=2):
128 """Some method's docstring"""
128 """Some method's docstring"""
129
129
130
130
131 class OldStyle:
131 class OldStyle:
132 """An old-style class for testing."""
132 """An old-style class for testing."""
133 pass
133 pass
134
134
135
135
136 def f(x, y=2, *a, **kw):
136 def f(x, y=2, *a, **kw):
137 """A simple function."""
137 """A simple function."""
138
138
139
139
140 def g(y, z=3, *a, **kw):
140 def g(y, z=3, *a, **kw):
141 pass # no docstring
141 pass # no docstring
142
142
143
143
144 @register_line_magic
144 @register_line_magic
145 def lmagic(line):
145 def lmagic(line):
146 "A line magic"
146 "A line magic"
147
147
148
148
149 @register_cell_magic
149 @register_cell_magic
150 def cmagic(line, cell):
150 def cmagic(line, cell):
151 "A cell magic"
151 "A cell magic"
152
152
153
153
154 @register_line_cell_magic
154 @register_line_cell_magic
155 def lcmagic(line, cell=None):
155 def lcmagic(line, cell=None):
156 "A line/cell magic"
156 "A line/cell magic"
157
157
158
158
159 @magics_class
159 @magics_class
160 class SimpleMagics(Magics):
160 class SimpleMagics(Magics):
161 @line_magic
161 @line_magic
162 def Clmagic(self, cline):
162 def Clmagic(self, cline):
163 "A class-based line magic"
163 "A class-based line magic"
164
164
165 @cell_magic
165 @cell_magic
166 def Ccmagic(self, cline, ccell):
166 def Ccmagic(self, cline, ccell):
167 "A class-based cell magic"
167 "A class-based cell magic"
168
168
169 @line_cell_magic
169 @line_cell_magic
170 def Clcmagic(self, cline, ccell=None):
170 def Clcmagic(self, cline, ccell=None):
171 "A class-based line/cell magic"
171 "A class-based line/cell magic"
172
172
173
173
174 class Awkward(object):
174 class Awkward(object):
175 def __getattr__(self, name):
175 def __getattr__(self, name):
176 raise Exception(name)
176 raise Exception(name)
177
177
178 class NoBoolCall:
178 class NoBoolCall:
179 """
179 """
180 callable with `__bool__` raising should still be inspect-able.
180 callable with `__bool__` raising should still be inspect-able.
181 """
181 """
182
182
183 def __call__(self):
183 def __call__(self):
184 """does nothing"""
184 """does nothing"""
185 pass
185 pass
186
186
187 def __bool__(self):
187 def __bool__(self):
188 """just raise NotImplemented"""
188 """just raise NotImplemented"""
189 raise NotImplementedError('Must be implemented')
189 raise NotImplementedError('Must be implemented')
190
190
191
191
192 class SerialLiar(object):
192 class SerialLiar(object):
193 """Attribute accesses always get another copy of the same class.
193 """Attribute accesses always get another copy of the same class.
194
194
195 unittest.mock.call does something similar, but it's not ideal for testing
195 unittest.mock.call does something similar, but it's not ideal for testing
196 as the failure mode is to eat all your RAM. This gives up after 10k levels.
196 as the failure mode is to eat all your RAM. This gives up after 10k levels.
197 """
197 """
198 def __init__(self, max_fibbing_twig, lies_told=0):
198 def __init__(self, max_fibbing_twig, lies_told=0):
199 if lies_told > 10000:
199 if lies_told > 10000:
200 raise RuntimeError('Nose too long, honesty is the best policy')
200 raise RuntimeError('Nose too long, honesty is the best policy')
201 self.max_fibbing_twig = max_fibbing_twig
201 self.max_fibbing_twig = max_fibbing_twig
202 self.lies_told = lies_told
202 self.lies_told = lies_told
203 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
203 max_fibbing_twig[0] = max(max_fibbing_twig[0], lies_told)
204
204
205 def __getattr__(self, item):
205 def __getattr__(self, item):
206 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
206 return SerialLiar(self.max_fibbing_twig, self.lies_told + 1)
207
207
208
208
209 def check_calltip(obj, name, call, docstring):
209 def check_calltip(obj, name, call, docstring):
210 """Generic check pattern all calltip tests will use"""
210 """Generic check pattern all calltip tests will use"""
211 info = inspector.info(obj, name)
211 info = inspector.info(obj, name)
212 call_line, ds = oinspect.call_tip(info)
212 call_line, ds = oinspect.call_tip(info)
213 nt.assert_equal(call_line, call)
213 nt.assert_equal(call_line, call)
214 nt.assert_equal(ds, docstring)
214 nt.assert_equal(ds, docstring)
215
215
216 #-----------------------------------------------------------------------------
216 #-----------------------------------------------------------------------------
217 # Tests
217 # Tests
218 #-----------------------------------------------------------------------------
218 #-----------------------------------------------------------------------------
219
219
220 def test_calltip_class():
220 def test_calltip_class():
221 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
221 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
222
222
223
223
224 def test_calltip_instance():
224 def test_calltip_instance():
225 c = Call(1)
225 c = Call(1)
226 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
226 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
227
227
228
228
229 def test_calltip_method():
229 def test_calltip_method():
230 c = Call(1)
230 c = Call(1)
231 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
231 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
232
232
233
233
234 def test_calltip_function():
234 def test_calltip_function():
235 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
235 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
236
236
237
237
238 def test_calltip_function2():
238 def test_calltip_function2():
239 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
239 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
240
240
241
241
242 @skipif(sys.version_info >= (3, 5))
242 @skipif(sys.version_info >= (3, 5))
243 def test_calltip_builtin():
243 def test_calltip_builtin():
244 check_calltip(sum, 'sum', None, sum.__doc__)
244 check_calltip(sum, 'sum', None, sum.__doc__)
245
245
246
246
247 def test_calltip_line_magic():
247 def test_calltip_line_magic():
248 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
248 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
249
249
250
250
251 def test_calltip_cell_magic():
251 def test_calltip_cell_magic():
252 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
252 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
253
253
254
254
255 def test_calltip_line_cell_magic():
255 def test_calltip_line_cell_magic():
256 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
256 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
257 "A line/cell magic")
257 "A line/cell magic")
258
258
259
259
260 def test_class_magics():
260 def test_class_magics():
261 cm = SimpleMagics(ip)
261 cm = SimpleMagics(ip)
262 ip.register_magics(cm)
262 ip.register_magics(cm)
263 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
263 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
264 "A class-based line magic")
264 "A class-based line magic")
265 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
265 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
266 "A class-based cell magic")
266 "A class-based cell magic")
267 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
267 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
268 "A class-based line/cell magic")
268 "A class-based line/cell magic")
269
269
270
270
271 def test_info():
271 def test_info():
272 "Check that Inspector.info fills out various fields as expected."
272 "Check that Inspector.info fills out various fields as expected."
273 i = inspector.info(Call, oname='Call')
273 i = inspector.info(Call, oname='Call')
274 nt.assert_equal(i['type_name'], 'type')
274 nt.assert_equal(i['type_name'], 'type')
275 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
275 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
276 nt.assert_equal(i['base_class'], expted_class)
276 nt.assert_equal(i['base_class'], expted_class)
277 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
277 nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>")
278 fname = __file__
278 fname = __file__
279 if fname.endswith(".pyc"):
279 if fname.endswith(".pyc"):
280 fname = fname[:-1]
280 fname = fname[:-1]
281 # case-insensitive comparison needed on some filesystems
281 # case-insensitive comparison needed on some filesystems
282 # e.g. Windows:
282 # e.g. Windows:
283 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
283 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
284 nt.assert_equal(i['definition'], None)
284 nt.assert_equal(i['definition'], None)
285 nt.assert_equal(i['docstring'], Call.__doc__)
285 nt.assert_equal(i['docstring'], Call.__doc__)
286 nt.assert_equal(i['source'], None)
286 nt.assert_equal(i['source'], None)
287 nt.assert_true(i['isclass'])
287 nt.assert_true(i['isclass'])
288 _self_py2 = '' if py3compat.PY3 else 'self, '
288 _self_py2 = '' if py3compat.PY3 else 'self, '
289 nt.assert_equal(i['init_definition'], "Call(%sx, y=1)" % _self_py2)
289 nt.assert_equal(i['init_definition'], "Call(%sx, y=1)" % _self_py2)
290 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
290 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
291
291
292 i = inspector.info(Call, detail_level=1)
292 i = inspector.info(Call, detail_level=1)
293 nt.assert_not_equal(i['source'], None)
293 nt.assert_not_equal(i['source'], None)
294 nt.assert_equal(i['docstring'], None)
294 nt.assert_equal(i['docstring'], None)
295
295
296 c = Call(1)
296 c = Call(1)
297 c.__doc__ = "Modified instance docstring"
297 c.__doc__ = "Modified instance docstring"
298 i = inspector.info(c)
298 i = inspector.info(c)
299 nt.assert_equal(i['type_name'], 'Call')
299 nt.assert_equal(i['type_name'], 'Call')
300 nt.assert_equal(i['docstring'], "Modified instance docstring")
300 nt.assert_equal(i['docstring'], "Modified instance docstring")
301 nt.assert_equal(i['class_docstring'], Call.__doc__)
301 nt.assert_equal(i['class_docstring'], Call.__doc__)
302 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
302 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
303 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
303 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
304
304
305 # Test old-style classes, which for example may not have an __init__ method.
305 # Test old-style classes, which for example may not have an __init__ method.
306 if not py3compat.PY3:
306 if not py3compat.PY3:
307 i = inspector.info(OldStyle)
307 i = inspector.info(OldStyle)
308 nt.assert_equal(i['type_name'], 'classobj')
308 nt.assert_equal(i['type_name'], 'classobj')
309
309
310 i = inspector.info(OldStyle())
310 i = inspector.info(OldStyle())
311 nt.assert_equal(i['type_name'], 'instance')
311 nt.assert_equal(i['type_name'], 'instance')
312 nt.assert_equal(i['docstring'], OldStyle.__doc__)
312 nt.assert_equal(i['docstring'], OldStyle.__doc__)
313
313
314 def test_class_signature():
314 def test_class_signature():
315 info = inspector.info(HasSignature, 'HasSignature')
315 info = inspector.info(HasSignature, 'HasSignature')
316 nt.assert_equal(info['init_definition'], "HasSignature(test)")
316 nt.assert_equal(info['init_definition'], "HasSignature(test)")
317 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
317 nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__)
318
318
319 def test_info_awkward():
319 def test_info_awkward():
320 # Just test that this doesn't throw an error.
320 # Just test that this doesn't throw an error.
321 inspector.info(Awkward())
321 inspector.info(Awkward())
322
322
323 def test_bool_raise():
323 def test_bool_raise():
324 inspector.info(NoBoolCall())
324 inspector.info(NoBoolCall())
325
325
326 def test_info_serialliar():
326 def test_info_serialliar():
327 fib_tracker = [0]
327 fib_tracker = [0]
328 inspector.info(SerialLiar(fib_tracker))
328 inspector.info(SerialLiar(fib_tracker))
329
329
330 # Nested attribute access should be cut off at 100 levels deep to avoid
330 # Nested attribute access should be cut off at 100 levels deep to avoid
331 # infinite loops: https://github.com/ipython/ipython/issues/9122
331 # infinite loops: https://github.com/ipython/ipython/issues/9122
332 nt.assert_less(fib_tracker[0], 9000)
332 nt.assert_less(fib_tracker[0], 9000)
333
333
334 def test_calldef_none():
334 def test_calldef_none():
335 # We should ignore __call__ for all of these.
335 # We should ignore __call__ for all of these.
336 for obj in [f, SimpleClass().method, any, str.upper]:
336 for obj in [f, SimpleClass().method, any, str.upper]:
337 print(obj)
337 print(obj)
338 i = inspector.info(obj)
338 i = inspector.info(obj)
339 nt.assert_is(i['call_def'], None)
339 nt.assert_is(i['call_def'], None)
340
340
341 def f_kwarg(pos, *, kwonly):
341 def f_kwarg(pos, *, kwonly):
342 pass
342 pass
343
343
344 def test_definition_kwonlyargs():
344 def test_definition_kwonlyargs():
345 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
345 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
346 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
346 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)")
347
347
348 def test_getdoc():
348 def test_getdoc():
349 class A(object):
349 class A(object):
350 """standard docstring"""
350 """standard docstring"""
351 pass
351 pass
352
352
353 class B(object):
353 class B(object):
354 """standard docstring"""
354 """standard docstring"""
355 def getdoc(self):
355 def getdoc(self):
356 return "custom docstring"
356 return "custom docstring"
357
357
358 class C(object):
358 class C(object):
359 """standard docstring"""
359 """standard docstring"""
360 def getdoc(self):
360 def getdoc(self):
361 return None
361 return None
362
362
363 a = A()
363 a = A()
364 b = B()
364 b = B()
365 c = C()
365 c = C()
366
366
367 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
367 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
368 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
368 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
369 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
369 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
370
370
371
371
372 def test_empty_property_has_no_source():
372 def test_empty_property_has_no_source():
373 i = inspector.info(property(), detail_level=1)
373 i = inspector.info(property(), detail_level=1)
374 nt.assert_is(i['source'], None)
374 nt.assert_is(i['source'], None)
375
375
376
376
377 def test_property_sources():
377 def test_property_sources():
378 import zlib
378 import zlib
379
379
380 class A(object):
380 class A(object):
381 @property
381 @property
382 def foo(self):
382 def foo(self):
383 return 'bar'
383 return 'bar'
384
384
385 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
385 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
386
386
387 id = property(id)
387 id = property(id)
388 compress = property(zlib.compress)
388 compress = property(zlib.compress)
389
389
390 i = inspector.info(A.foo, detail_level=1)
390 i = inspector.info(A.foo, detail_level=1)
391 nt.assert_in('def foo(self):', i['source'])
391 nt.assert_in('def foo(self):', i['source'])
392 nt.assert_in('lambda self, v:', i['source'])
392 nt.assert_in('lambda self, v:', i['source'])
393
393
394 i = inspector.info(A.id, detail_level=1)
394 i = inspector.info(A.id, detail_level=1)
395 nt.assert_in('fget = <function id>', i['source'])
395 nt.assert_in('fget = <function id>', i['source'])
396
396
397 i = inspector.info(A.compress, detail_level=1)
397 i = inspector.info(A.compress, detail_level=1)
398 nt.assert_in('fget = <function zlib.compress>', i['source'])
398 nt.assert_in('fget = <function zlib.compress>', i['source'])
399
399
400
400
401 def test_property_docstring_is_in_info_for_detail_level_0():
401 def test_property_docstring_is_in_info_for_detail_level_0():
402 class A(object):
402 class A(object):
403 @property
403 @property
404 def foobar(self):
404 def foobar(self):
405 """This is `foobar` property."""
405 """This is `foobar` property."""
406 pass
406 pass
407
407
408 ip.user_ns['a_obj'] = A()
408 ip.user_ns['a_obj'] = A()
409 nt.assert_equals(
409 nt.assert_equals(
410 'This is `foobar` property.',
410 'This is `foobar` property.',
411 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
411 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
412
412
413 ip.user_ns['a_cls'] = A
413 ip.user_ns['a_cls'] = A
414 nt.assert_equals(
414 nt.assert_equals(
415 'This is `foobar` property.',
415 'This is `foobar` property.',
416 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
416 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
417
417
418
418
419 def test_pdef():
419 def test_pdef():
420 # See gh-1914
420 # See gh-1914
421 def foo(): pass
421 def foo(): pass
422 inspector.pdef(foo, 'foo')
422 inspector.pdef(foo, 'foo')
423
423
424
424
425 def test_pinfo_nonascii():
425 def test_pinfo_nonascii():
426 # See gh-1177
426 # See gh-1177
427 from . import nonascii2
427 from . import nonascii2
428 ip.user_ns['nonascii2'] = nonascii2
428 ip.user_ns['nonascii2'] = nonascii2
429 ip._inspect('pinfo', 'nonascii2', detail_level=1)
429 ip._inspect('pinfo', 'nonascii2', detail_level=1)
430
430
431
431
432 def test_pinfo_magic():
432 def test_pinfo_magic():
433 with AssertPrints('Docstring:'):
433 with AssertPrints('Docstring:'):
434 ip._inspect('pinfo', 'lsmagic', detail_level=0)
434 ip._inspect('pinfo', 'lsmagic', detail_level=0)
435
435
436 with AssertPrints('Source:'):
436 with AssertPrints('Source:'):
437 ip._inspect('pinfo', 'lsmagic', detail_level=1)
437 ip._inspect('pinfo', 'lsmagic', detail_level=1)
438
438
439
439
440 def test_init_colors():
440 def test_init_colors():
441 # ensure colors are not present in signature info
441 # ensure colors are not present in signature info
442 info = inspector.info(HasSignature)
442 info = inspector.info(HasSignature)
443 init_def = info['init_definition']
443 init_def = info['init_definition']
444 nt.assert_not_in('[0m', init_def)
444 nt.assert_not_in('[0m', init_def)
445
445
446
446
447 def test_builtin_init():
447 def test_builtin_init():
448 info = inspector.info(list)
448 info = inspector.info(list)
449 init_def = info['init_definition']
449 init_def = info['init_definition']
450 # Python < 3.4 can't get init definition from builtins,
450 # Python < 3.4 can't get init definition from builtins,
451 # but still exercise the inspection in case of error-raising bugs.
451 # but still exercise the inspection in case of error-raising bugs.
452 if sys.version_info >= (3,4):
452 if sys.version_info >= (3,4):
453 nt.assert_is_not_none(init_def)
453 nt.assert_is_not_none(init_def)
454
454
General Comments 0
You need to be logged in to leave comments. Login now