##// END OF EJS Templates
Skip test that builtin signature can't be inspected...
Thomas Kluyver -
Show More
@@ -1,382 +1,383 b''
1 """Tests for the object inspection functionality.
1 """Tests for the object inspection functionality.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (C) 2010-2011 The IPython Development Team.
4 # Copyright (C) 2010-2011 The IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the BSD License.
6 # Distributed under the terms of the BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14 from __future__ import print_function
14 from __future__ import print_function
15
15
16 # Stdlib imports
16 # Stdlib imports
17 import os
17 import os
18 import re
18 import re
19
19
20 # Third-party imports
20 # Third-party imports
21 import nose.tools as nt
21 import nose.tools as nt
22
22
23 # Our own imports
23 # Our own imports
24 from .. import oinspect
24 from .. import oinspect
25 from IPython.core.magic import (Magics, magics_class, line_magic,
25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 cell_magic, line_cell_magic,
26 cell_magic, line_cell_magic,
27 register_line_magic, register_cell_magic,
27 register_line_magic, register_cell_magic,
28 register_line_cell_magic)
28 register_line_cell_magic)
29 from decorator import decorator
29 from decorator import decorator
30 from IPython.testing.decorators import skipif
30 from IPython.testing.decorators import skipif
31 from IPython.testing.tools import AssertPrints
31 from IPython.testing.tools import AssertPrints
32 from IPython.utils.path import compress_user
32 from IPython.utils.path import compress_user
33 from IPython.utils import py3compat
33 from IPython.utils import py3compat
34
34
35
35
36 #-----------------------------------------------------------------------------
36 #-----------------------------------------------------------------------------
37 # Globals and constants
37 # Globals and constants
38 #-----------------------------------------------------------------------------
38 #-----------------------------------------------------------------------------
39
39
40 inspector = oinspect.Inspector()
40 inspector = oinspect.Inspector()
41 ip = get_ipython()
41 ip = get_ipython()
42
42
43 #-----------------------------------------------------------------------------
43 #-----------------------------------------------------------------------------
44 # Local utilities
44 # Local utilities
45 #-----------------------------------------------------------------------------
45 #-----------------------------------------------------------------------------
46
46
47 # WARNING: since this test checks the line number where a function is
47 # WARNING: since this test checks the line number where a function is
48 # defined, if any code is inserted above, the following line will need to be
48 # defined, if any code is inserted above, the following line will need to be
49 # updated. Do NOT insert any whitespace between the next line and the function
49 # updated. Do NOT insert any whitespace between the next line and the function
50 # definition below.
50 # definition below.
51 THIS_LINE_NUMBER = 51 # Put here the actual number of this line
51 THIS_LINE_NUMBER = 51 # Put here the actual number of this line
52 def test_find_source_lines():
52 def test_find_source_lines():
53 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
53 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
54 THIS_LINE_NUMBER+1)
54 THIS_LINE_NUMBER+1)
55
55
56
56
57 # A couple of utilities to ensure these tests work the same from a source or a
57 # A couple of utilities to ensure these tests work the same from a source or a
58 # binary install
58 # binary install
59 def pyfile(fname):
59 def pyfile(fname):
60 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
60 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
61
61
62
62
63 def match_pyfiles(f1, f2):
63 def match_pyfiles(f1, f2):
64 nt.assert_equal(pyfile(f1), pyfile(f2))
64 nt.assert_equal(pyfile(f1), pyfile(f2))
65
65
66
66
67 def test_find_file():
67 def test_find_file():
68 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
68 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
69
69
70
70
71 def test_find_file_decorated1():
71 def test_find_file_decorated1():
72
72
73 @decorator
73 @decorator
74 def noop1(f):
74 def noop1(f):
75 def wrapper():
75 def wrapper():
76 return f(*a, **kw)
76 return f(*a, **kw)
77 return wrapper
77 return wrapper
78
78
79 @noop1
79 @noop1
80 def f(x):
80 def f(x):
81 "My docstring"
81 "My docstring"
82
82
83 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
83 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
84 nt.assert_equal(f.__doc__, "My docstring")
84 nt.assert_equal(f.__doc__, "My docstring")
85
85
86
86
87 def test_find_file_decorated2():
87 def test_find_file_decorated2():
88
88
89 @decorator
89 @decorator
90 def noop2(f, *a, **kw):
90 def noop2(f, *a, **kw):
91 return f(*a, **kw)
91 return f(*a, **kw)
92
92
93 @noop2
93 @noop2
94 def f(x):
94 def f(x):
95 "My docstring 2"
95 "My docstring 2"
96
96
97 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
97 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
98 nt.assert_equal(f.__doc__, "My docstring 2")
98 nt.assert_equal(f.__doc__, "My docstring 2")
99
99
100
100
101 def test_find_file_magic():
101 def test_find_file_magic():
102 run = ip.find_line_magic('run')
102 run = ip.find_line_magic('run')
103 nt.assert_not_equal(oinspect.find_file(run), None)
103 nt.assert_not_equal(oinspect.find_file(run), None)
104
104
105
105
106 # A few generic objects we can then inspect in the tests below
106 # A few generic objects we can then inspect in the tests below
107
107
108 class Call(object):
108 class Call(object):
109 """This is the class docstring."""
109 """This is the class docstring."""
110
110
111 def __init__(self, x, y=1):
111 def __init__(self, x, y=1):
112 """This is the constructor docstring."""
112 """This is the constructor docstring."""
113
113
114 def __call__(self, *a, **kw):
114 def __call__(self, *a, **kw):
115 """This is the call docstring."""
115 """This is the call docstring."""
116
116
117 def method(self, x, z=2):
117 def method(self, x, z=2):
118 """Some method's docstring"""
118 """Some method's docstring"""
119
119
120 class SimpleClass(object):
120 class SimpleClass(object):
121 def method(self, x, z=2):
121 def method(self, x, z=2):
122 """Some method's docstring"""
122 """Some method's docstring"""
123
123
124
124
125 class OldStyle:
125 class OldStyle:
126 """An old-style class for testing."""
126 """An old-style class for testing."""
127 pass
127 pass
128
128
129
129
130 def f(x, y=2, *a, **kw):
130 def f(x, y=2, *a, **kw):
131 """A simple function."""
131 """A simple function."""
132
132
133
133
134 def g(y, z=3, *a, **kw):
134 def g(y, z=3, *a, **kw):
135 pass # no docstring
135 pass # no docstring
136
136
137
137
138 @register_line_magic
138 @register_line_magic
139 def lmagic(line):
139 def lmagic(line):
140 "A line magic"
140 "A line magic"
141
141
142
142
143 @register_cell_magic
143 @register_cell_magic
144 def cmagic(line, cell):
144 def cmagic(line, cell):
145 "A cell magic"
145 "A cell magic"
146
146
147
147
148 @register_line_cell_magic
148 @register_line_cell_magic
149 def lcmagic(line, cell=None):
149 def lcmagic(line, cell=None):
150 "A line/cell magic"
150 "A line/cell magic"
151
151
152
152
153 @magics_class
153 @magics_class
154 class SimpleMagics(Magics):
154 class SimpleMagics(Magics):
155 @line_magic
155 @line_magic
156 def Clmagic(self, cline):
156 def Clmagic(self, cline):
157 "A class-based line magic"
157 "A class-based line magic"
158
158
159 @cell_magic
159 @cell_magic
160 def Ccmagic(self, cline, ccell):
160 def Ccmagic(self, cline, ccell):
161 "A class-based cell magic"
161 "A class-based cell magic"
162
162
163 @line_cell_magic
163 @line_cell_magic
164 def Clcmagic(self, cline, ccell=None):
164 def Clcmagic(self, cline, ccell=None):
165 "A class-based line/cell magic"
165 "A class-based line/cell magic"
166
166
167
167
168 class Awkward(object):
168 class Awkward(object):
169 def __getattr__(self, name):
169 def __getattr__(self, name):
170 raise Exception(name)
170 raise Exception(name)
171
171
172
172
173 def check_calltip(obj, name, call, docstring):
173 def check_calltip(obj, name, call, docstring):
174 """Generic check pattern all calltip tests will use"""
174 """Generic check pattern all calltip tests will use"""
175 info = inspector.info(obj, name)
175 info = inspector.info(obj, name)
176 call_line, ds = oinspect.call_tip(info)
176 call_line, ds = oinspect.call_tip(info)
177 nt.assert_equal(call_line, call)
177 nt.assert_equal(call_line, call)
178 nt.assert_equal(ds, docstring)
178 nt.assert_equal(ds, docstring)
179
179
180 #-----------------------------------------------------------------------------
180 #-----------------------------------------------------------------------------
181 # Tests
181 # Tests
182 #-----------------------------------------------------------------------------
182 #-----------------------------------------------------------------------------
183
183
184 def test_calltip_class():
184 def test_calltip_class():
185 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
185 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
186
186
187
187
188 def test_calltip_instance():
188 def test_calltip_instance():
189 c = Call(1)
189 c = Call(1)
190 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
190 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
191
191
192
192
193 def test_calltip_method():
193 def test_calltip_method():
194 c = Call(1)
194 c = Call(1)
195 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
195 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
196
196
197
197
198 def test_calltip_function():
198 def test_calltip_function():
199 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
199 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
200
200
201
201
202 def test_calltip_function2():
202 def test_calltip_function2():
203 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
203 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
204
204
205
205
206 @skipif(sys.version_info >= (3, 5))
206 def test_calltip_builtin():
207 def test_calltip_builtin():
207 check_calltip(sum, 'sum', None, sum.__doc__)
208 check_calltip(sum, 'sum', None, sum.__doc__)
208
209
209
210
210 def test_calltip_line_magic():
211 def test_calltip_line_magic():
211 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
212 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
212
213
213
214
214 def test_calltip_cell_magic():
215 def test_calltip_cell_magic():
215 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
216 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
216
217
217
218
218 def test_calltip_line_cell_magic():
219 def test_calltip_line_cell_magic():
219 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
220 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
220 "A line/cell magic")
221 "A line/cell magic")
221
222
222
223
223 def test_class_magics():
224 def test_class_magics():
224 cm = SimpleMagics(ip)
225 cm = SimpleMagics(ip)
225 ip.register_magics(cm)
226 ip.register_magics(cm)
226 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
227 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
227 "A class-based line magic")
228 "A class-based line magic")
228 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
229 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
229 "A class-based cell magic")
230 "A class-based cell magic")
230 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
231 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
231 "A class-based line/cell magic")
232 "A class-based line/cell magic")
232
233
233
234
234 def test_info():
235 def test_info():
235 "Check that Inspector.info fills out various fields as expected."
236 "Check that Inspector.info fills out various fields as expected."
236 i = inspector.info(Call, oname='Call')
237 i = inspector.info(Call, oname='Call')
237 nt.assert_equal(i['type_name'], 'type')
238 nt.assert_equal(i['type_name'], 'type')
238 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
239 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
239 nt.assert_equal(i['base_class'], expted_class)
240 nt.assert_equal(i['base_class'], expted_class)
240 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
241 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
241 fname = __file__
242 fname = __file__
242 if fname.endswith(".pyc"):
243 if fname.endswith(".pyc"):
243 fname = fname[:-1]
244 fname = fname[:-1]
244 # case-insensitive comparison needed on some filesystems
245 # case-insensitive comparison needed on some filesystems
245 # e.g. Windows:
246 # e.g. Windows:
246 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
247 nt.assert_equal(i['file'].lower(), compress_user(fname).lower())
247 nt.assert_equal(i['definition'], None)
248 nt.assert_equal(i['definition'], None)
248 nt.assert_equal(i['docstring'], Call.__doc__)
249 nt.assert_equal(i['docstring'], Call.__doc__)
249 nt.assert_equal(i['source'], None)
250 nt.assert_equal(i['source'], None)
250 nt.assert_true(i['isclass'])
251 nt.assert_true(i['isclass'])
251 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
252 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
252 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
253 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
253
254
254 i = inspector.info(Call, detail_level=1)
255 i = inspector.info(Call, detail_level=1)
255 nt.assert_not_equal(i['source'], None)
256 nt.assert_not_equal(i['source'], None)
256 nt.assert_equal(i['docstring'], None)
257 nt.assert_equal(i['docstring'], None)
257
258
258 c = Call(1)
259 c = Call(1)
259 c.__doc__ = "Modified instance docstring"
260 c.__doc__ = "Modified instance docstring"
260 i = inspector.info(c)
261 i = inspector.info(c)
261 nt.assert_equal(i['type_name'], 'Call')
262 nt.assert_equal(i['type_name'], 'Call')
262 nt.assert_equal(i['docstring'], "Modified instance docstring")
263 nt.assert_equal(i['docstring'], "Modified instance docstring")
263 nt.assert_equal(i['class_docstring'], Call.__doc__)
264 nt.assert_equal(i['class_docstring'], Call.__doc__)
264 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
265 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
265 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
266 nt.assert_equal(i['call_docstring'], Call.__call__.__doc__)
266
267
267 # Test old-style classes, which for example may not have an __init__ method.
268 # Test old-style classes, which for example may not have an __init__ method.
268 if not py3compat.PY3:
269 if not py3compat.PY3:
269 i = inspector.info(OldStyle)
270 i = inspector.info(OldStyle)
270 nt.assert_equal(i['type_name'], 'classobj')
271 nt.assert_equal(i['type_name'], 'classobj')
271
272
272 i = inspector.info(OldStyle())
273 i = inspector.info(OldStyle())
273 nt.assert_equal(i['type_name'], 'instance')
274 nt.assert_equal(i['type_name'], 'instance')
274 nt.assert_equal(i['docstring'], OldStyle.__doc__)
275 nt.assert_equal(i['docstring'], OldStyle.__doc__)
275
276
276 def test_info_awkward():
277 def test_info_awkward():
277 # Just test that this doesn't throw an error.
278 # Just test that this doesn't throw an error.
278 i = inspector.info(Awkward())
279 i = inspector.info(Awkward())
279
280
280 def test_calldef_none():
281 def test_calldef_none():
281 # We should ignore __call__ for all of these.
282 # We should ignore __call__ for all of these.
282 for obj in [f, SimpleClass().method, any, str.upper]:
283 for obj in [f, SimpleClass().method, any, str.upper]:
283 print(obj)
284 print(obj)
284 i = inspector.info(obj)
285 i = inspector.info(obj)
285 nt.assert_is(i['call_def'], None)
286 nt.assert_is(i['call_def'], None)
286
287
287 if py3compat.PY3:
288 if py3compat.PY3:
288 exec("def f_kwarg(pos, *, kwonly): pass")
289 exec("def f_kwarg(pos, *, kwonly): pass")
289
290
290 @skipif(not py3compat.PY3)
291 @skipif(not py3compat.PY3)
291 def test_definition_kwonlyargs():
292 def test_definition_kwonlyargs():
292 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
293 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
293 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)\n")
294 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)\n")
294
295
295 def test_getdoc():
296 def test_getdoc():
296 class A(object):
297 class A(object):
297 """standard docstring"""
298 """standard docstring"""
298 pass
299 pass
299
300
300 class B(object):
301 class B(object):
301 """standard docstring"""
302 """standard docstring"""
302 def getdoc(self):
303 def getdoc(self):
303 return "custom docstring"
304 return "custom docstring"
304
305
305 class C(object):
306 class C(object):
306 """standard docstring"""
307 """standard docstring"""
307 def getdoc(self):
308 def getdoc(self):
308 return None
309 return None
309
310
310 a = A()
311 a = A()
311 b = B()
312 b = B()
312 c = C()
313 c = C()
313
314
314 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
315 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
315 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
316 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
316 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
317 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
317
318
318
319
319 def test_empty_property_has_no_source():
320 def test_empty_property_has_no_source():
320 i = inspector.info(property(), detail_level=1)
321 i = inspector.info(property(), detail_level=1)
321 nt.assert_is(i['source'], None)
322 nt.assert_is(i['source'], None)
322
323
323
324
324 def test_property_sources():
325 def test_property_sources():
325 import zlib
326 import zlib
326
327
327 class A(object):
328 class A(object):
328 @property
329 @property
329 def foo(self):
330 def foo(self):
330 return 'bar'
331 return 'bar'
331
332
332 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
333 foo = foo.setter(lambda self, v: setattr(self, 'bar', v))
333
334
334 id = property(id)
335 id = property(id)
335 compress = property(zlib.compress)
336 compress = property(zlib.compress)
336
337
337 i = inspector.info(A.foo, detail_level=1)
338 i = inspector.info(A.foo, detail_level=1)
338 nt.assert_in('def foo(self):', i['source'])
339 nt.assert_in('def foo(self):', i['source'])
339 nt.assert_in('lambda self, v:', i['source'])
340 nt.assert_in('lambda self, v:', i['source'])
340
341
341 i = inspector.info(A.id, detail_level=1)
342 i = inspector.info(A.id, detail_level=1)
342 nt.assert_in('fget = <function id>', i['source'])
343 nt.assert_in('fget = <function id>', i['source'])
343
344
344 i = inspector.info(A.compress, detail_level=1)
345 i = inspector.info(A.compress, detail_level=1)
345 nt.assert_in('fget = <function zlib.compress>', i['source'])
346 nt.assert_in('fget = <function zlib.compress>', i['source'])
346
347
347
348
348 def test_property_docstring_is_in_info_for_detail_level_0():
349 def test_property_docstring_is_in_info_for_detail_level_0():
349 class A(object):
350 class A(object):
350 @property
351 @property
351 def foobar():
352 def foobar():
352 """This is `foobar` property."""
353 """This is `foobar` property."""
353 pass
354 pass
354
355
355 ip.user_ns['a_obj'] = A()
356 ip.user_ns['a_obj'] = A()
356 nt.assert_equals(
357 nt.assert_equals(
357 'This is `foobar` property.',
358 'This is `foobar` property.',
358 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
359 ip.object_inspect('a_obj.foobar', detail_level=0)['docstring'])
359
360
360 ip.user_ns['a_cls'] = A
361 ip.user_ns['a_cls'] = A
361 nt.assert_equals(
362 nt.assert_equals(
362 'This is `foobar` property.',
363 'This is `foobar` property.',
363 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
364 ip.object_inspect('a_cls.foobar', detail_level=0)['docstring'])
364
365
365
366
366 def test_pdef():
367 def test_pdef():
367 # See gh-1914
368 # See gh-1914
368 def foo(): pass
369 def foo(): pass
369 inspector.pdef(foo, 'foo')
370 inspector.pdef(foo, 'foo')
370
371
371 def test_pinfo_nonascii():
372 def test_pinfo_nonascii():
372 # See gh-1177
373 # See gh-1177
373 from . import nonascii2
374 from . import nonascii2
374 ip.user_ns['nonascii2'] = nonascii2
375 ip.user_ns['nonascii2'] = nonascii2
375 ip._inspect('pinfo', 'nonascii2', detail_level=1)
376 ip._inspect('pinfo', 'nonascii2', detail_level=1)
376
377
377 def test_pinfo_magic():
378 def test_pinfo_magic():
378 with AssertPrints('Docstring:'):
379 with AssertPrints('Docstring:'):
379 ip._inspect('pinfo', 'lsmagic', detail_level=0)
380 ip._inspect('pinfo', 'lsmagic', detail_level=0)
380
381
381 with AssertPrints('Source:'):
382 with AssertPrints('Source:'):
382 ip._inspect('pinfo', 'lsmagic', detail_level=1)
383 ip._inspect('pinfo', 'lsmagic', detail_level=1)
General Comments 0
You need to be logged in to leave comments. Login now