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