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