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