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