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