##// END OF EJS Templates
Don't introspect __call__ for simple callables...
Thomas Kluyver -
Show More
@@ -1,868 +1,877 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Tools for inspecting Python objects.
3 3
4 4 Uses syntax highlighting for presenting the various information elements.
5 5
6 6 Similar in spirit to the inspect module, but all calls take a name argument to
7 7 reference the name under which an object is being read.
8 8 """
9 9
10 10 #*****************************************************************************
11 11 # Copyright (C) 2001-2004 Fernando Perez <fperez@colorado.edu>
12 12 #
13 13 # Distributed under the terms of the BSD License. The full license is in
14 14 # the file COPYING, distributed as part of this software.
15 15 #*****************************************************************************
16 16 from __future__ import print_function
17 17
18 18 __all__ = ['Inspector','InspectColors']
19 19
20 20 # stdlib modules
21 21 import inspect
22 22 import linecache
23 23 import os
24 24 import types
25 25 import io as stdlib_io
26 26
27 27 try:
28 28 from itertools import izip_longest
29 29 except ImportError:
30 30 from itertools import zip_longest as izip_longest
31 31
32 32 # IPython's own
33 33 from IPython.core import page
34 34 from IPython.testing.skipdoctest import skip_doctest_py3
35 35 from IPython.utils import PyColorize
36 36 from IPython.utils import io
37 37 from IPython.utils import openpy
38 38 from IPython.utils import py3compat
39 39 from IPython.utils.dir2 import safe_hasattr
40 40 from IPython.utils.text import indent
41 41 from IPython.utils.wildcard import list_namespace
42 42 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
43 43 from IPython.utils.py3compat import cast_unicode, string_types, PY3
44 44
45 45 # builtin docstrings to ignore
46 46 _func_call_docstring = types.FunctionType.__call__.__doc__
47 47 _object_init_docstring = object.__init__.__doc__
48 48 _builtin_type_docstrings = {
49 49 t.__doc__ for t in (types.ModuleType, types.MethodType, types.FunctionType)
50 50 }
51
52 _builtin_func_type = type(all)
53 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
51 54 #****************************************************************************
52 55 # Builtin color schemes
53 56
54 57 Colors = TermColors # just a shorthand
55 58
56 59 # Build a few color schemes
57 60 NoColor = ColorScheme(
58 61 'NoColor',{
59 62 'header' : Colors.NoColor,
60 63 'normal' : Colors.NoColor # color off (usu. Colors.Normal)
61 64 } )
62 65
63 66 LinuxColors = ColorScheme(
64 67 'Linux',{
65 68 'header' : Colors.LightRed,
66 69 'normal' : Colors.Normal # color off (usu. Colors.Normal)
67 70 } )
68 71
69 72 LightBGColors = ColorScheme(
70 73 'LightBG',{
71 74 'header' : Colors.Red,
72 75 'normal' : Colors.Normal # color off (usu. Colors.Normal)
73 76 } )
74 77
75 78 # Build table of color schemes (needed by the parser)
76 79 InspectColors = ColorSchemeTable([NoColor,LinuxColors,LightBGColors],
77 80 'Linux')
78 81
79 82 #****************************************************************************
80 83 # Auxiliary functions and objects
81 84
82 85 # See the messaging spec for the definition of all these fields. This list
83 86 # effectively defines the order of display
84 87 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
85 88 'length', 'file', 'definition', 'docstring', 'source',
86 89 'init_definition', 'class_docstring', 'init_docstring',
87 90 'call_def', 'call_docstring',
88 91 # These won't be printed but will be used to determine how to
89 92 # format the object
90 93 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
91 94 ]
92 95
93 96
94 97 def object_info(**kw):
95 98 """Make an object info dict with all fields present."""
96 99 infodict = dict(izip_longest(info_fields, [None]))
97 100 infodict.update(kw)
98 101 return infodict
99 102
100 103
101 104 def get_encoding(obj):
102 105 """Get encoding for python source file defining obj
103 106
104 107 Returns None if obj is not defined in a sourcefile.
105 108 """
106 109 ofile = find_file(obj)
107 110 # run contents of file through pager starting at line where the object
108 111 # is defined, as long as the file isn't binary and is actually on the
109 112 # filesystem.
110 113 if ofile is None:
111 114 return None
112 115 elif ofile.endswith(('.so', '.dll', '.pyd')):
113 116 return None
114 117 elif not os.path.isfile(ofile):
115 118 return None
116 119 else:
117 120 # Print only text files, not extension binaries. Note that
118 121 # getsourcelines returns lineno with 1-offset and page() uses
119 122 # 0-offset, so we must adjust.
120 123 buffer = stdlib_io.open(ofile, 'rb') # Tweaked to use io.open for Python 2
121 124 encoding, lines = openpy.detect_encoding(buffer.readline)
122 125 return encoding
123 126
124 127 def getdoc(obj):
125 128 """Stable wrapper around inspect.getdoc.
126 129
127 130 This can't crash because of attribute problems.
128 131
129 132 It also attempts to call a getdoc() method on the given object. This
130 133 allows objects which provide their docstrings via non-standard mechanisms
131 134 (like Pyro proxies) to still be inspected by ipython's ? system."""
132 135 # Allow objects to offer customized documentation via a getdoc method:
133 136 try:
134 137 ds = obj.getdoc()
135 138 except Exception:
136 139 pass
137 140 else:
138 141 # if we get extra info, we add it to the normal docstring.
139 142 if isinstance(ds, string_types):
140 143 return inspect.cleandoc(ds)
141 144
142 145 try:
143 146 docstr = inspect.getdoc(obj)
144 147 encoding = get_encoding(obj)
145 148 return py3compat.cast_unicode(docstr, encoding=encoding)
146 149 except Exception:
147 150 # Harden against an inspect failure, which can occur with
148 151 # SWIG-wrapped extensions.
149 152 raise
150 153 return None
151 154
152 155
153 156 def getsource(obj,is_binary=False):
154 157 """Wrapper around inspect.getsource.
155 158
156 159 This can be modified by other projects to provide customized source
157 160 extraction.
158 161
159 162 Inputs:
160 163
161 164 - obj: an object whose source code we will attempt to extract.
162 165
163 166 Optional inputs:
164 167
165 168 - is_binary: whether the object is known to come from a binary source.
166 169 This implementation will skip returning any output for binary objects, but
167 170 custom extractors may know how to meaningfully process them."""
168 171
169 172 if is_binary:
170 173 return None
171 174 else:
172 175 # get source if obj was decorated with @decorator
173 176 if hasattr(obj,"__wrapped__"):
174 177 obj = obj.__wrapped__
175 178 try:
176 179 src = inspect.getsource(obj)
177 180 except TypeError:
178 181 if hasattr(obj,'__class__'):
179 182 src = inspect.getsource(obj.__class__)
180 183 encoding = get_encoding(obj)
181 184 return cast_unicode(src, encoding=encoding)
182 185
186
187 def is_simple_callable(obj):
188 """True if obj is a function ()"""
189 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
190 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
191
192
183 193 def getargspec(obj):
184 194 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
185 195 :func:inspect.getargspec` on Python 2.
186 196
187 197 In addition to functions and methods, this can also handle objects with a
188 198 ``__call__`` attribute.
189 199 """
190 if not (inspect.isfunction(obj) or inspect.ismethod(obj)) \
191 and safe_hasattr(obj, '__call__'):
200 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
192 201 obj = obj.__call__
193 202
194 203 return inspect.getfullargspec(obj) if PY3 else inspect.getargspec(obj)
195 204
196 205
197 206 def format_argspec(argspec):
198 207 """Format argspect, convenience wrapper around inspect's.
199 208
200 209 This takes a dict instead of ordered arguments and calls
201 210 inspect.format_argspec with the arguments in the necessary order.
202 211 """
203 212 return inspect.formatargspec(argspec['args'], argspec['varargs'],
204 213 argspec['varkw'], argspec['defaults'])
205 214
206 215
207 216 def call_tip(oinfo, format_call=True):
208 217 """Extract call tip data from an oinfo dict.
209 218
210 219 Parameters
211 220 ----------
212 221 oinfo : dict
213 222
214 223 format_call : bool, optional
215 224 If True, the call line is formatted and returned as a string. If not, a
216 225 tuple of (name, argspec) is returned.
217 226
218 227 Returns
219 228 -------
220 229 call_info : None, str or (str, dict) tuple.
221 230 When format_call is True, the whole call information is formattted as a
222 231 single string. Otherwise, the object's name and its argspec dict are
223 232 returned. If no call information is available, None is returned.
224 233
225 234 docstring : str or None
226 235 The most relevant docstring for calling purposes is returned, if
227 236 available. The priority is: call docstring for callable instances, then
228 237 constructor docstring for classes, then main object's docstring otherwise
229 238 (regular functions).
230 239 """
231 240 # Get call definition
232 241 argspec = oinfo.get('argspec')
233 242 if argspec is None:
234 243 call_line = None
235 244 else:
236 245 # Callable objects will have 'self' as their first argument, prune
237 246 # it out if it's there for clarity (since users do *not* pass an
238 247 # extra first argument explicitly).
239 248 try:
240 249 has_self = argspec['args'][0] == 'self'
241 250 except (KeyError, IndexError):
242 251 pass
243 252 else:
244 253 if has_self:
245 254 argspec['args'] = argspec['args'][1:]
246 255
247 256 call_line = oinfo['name']+format_argspec(argspec)
248 257
249 258 # Now get docstring.
250 259 # The priority is: call docstring, constructor docstring, main one.
251 260 doc = oinfo.get('call_docstring')
252 261 if doc is None:
253 262 doc = oinfo.get('init_docstring')
254 263 if doc is None:
255 264 doc = oinfo.get('docstring','')
256 265
257 266 return call_line, doc
258 267
259 268
260 269 def find_file(obj):
261 270 """Find the absolute path to the file where an object was defined.
262 271
263 272 This is essentially a robust wrapper around `inspect.getabsfile`.
264 273
265 274 Returns None if no file can be found.
266 275
267 276 Parameters
268 277 ----------
269 278 obj : any Python object
270 279
271 280 Returns
272 281 -------
273 282 fname : str
274 283 The absolute path to the file where the object was defined.
275 284 """
276 285 # get source if obj was decorated with @decorator
277 286 if safe_hasattr(obj, '__wrapped__'):
278 287 obj = obj.__wrapped__
279 288
280 289 fname = None
281 290 try:
282 291 fname = inspect.getabsfile(obj)
283 292 except TypeError:
284 293 # For an instance, the file that matters is where its class was
285 294 # declared.
286 295 if hasattr(obj, '__class__'):
287 296 try:
288 297 fname = inspect.getabsfile(obj.__class__)
289 298 except TypeError:
290 299 # Can happen for builtins
291 300 pass
292 301 except:
293 302 pass
294 303 return cast_unicode(fname)
295 304
296 305
297 306 def find_source_lines(obj):
298 307 """Find the line number in a file where an object was defined.
299 308
300 309 This is essentially a robust wrapper around `inspect.getsourcelines`.
301 310
302 311 Returns None if no file can be found.
303 312
304 313 Parameters
305 314 ----------
306 315 obj : any Python object
307 316
308 317 Returns
309 318 -------
310 319 lineno : int
311 320 The line number where the object definition starts.
312 321 """
313 322 # get source if obj was decorated with @decorator
314 323 if safe_hasattr(obj, '__wrapped__'):
315 324 obj = obj.__wrapped__
316 325
317 326 try:
318 327 try:
319 328 lineno = inspect.getsourcelines(obj)[1]
320 329 except TypeError:
321 330 # For instances, try the class object like getsource() does
322 331 if hasattr(obj, '__class__'):
323 332 lineno = inspect.getsourcelines(obj.__class__)[1]
324 333 else:
325 334 lineno = None
326 335 except:
327 336 return None
328 337
329 338 return lineno
330 339
331 340
332 341 class Inspector:
333 342 def __init__(self, color_table=InspectColors,
334 343 code_color_table=PyColorize.ANSICodeColors,
335 344 scheme='NoColor',
336 345 str_detail_level=0):
337 346 self.color_table = color_table
338 347 self.parser = PyColorize.Parser(code_color_table,out='str')
339 348 self.format = self.parser.format
340 349 self.str_detail_level = str_detail_level
341 350 self.set_active_scheme(scheme)
342 351
343 352 def _getdef(self,obj,oname=''):
344 353 """Return the call signature for any callable object.
345 354
346 355 If any exception is generated, None is returned instead and the
347 356 exception is suppressed."""
348 357 try:
349 358 hdef = oname + inspect.formatargspec(*getargspec(obj))
350 359 return cast_unicode(hdef)
351 360 except:
352 361 return None
353 362
354 363 def __head(self,h):
355 364 """Return a header string with proper colors."""
356 365 return '%s%s%s' % (self.color_table.active_colors.header,h,
357 366 self.color_table.active_colors.normal)
358 367
359 368 def set_active_scheme(self, scheme):
360 369 self.color_table.set_active_scheme(scheme)
361 370 self.parser.color_table.set_active_scheme(scheme)
362 371
363 372 def noinfo(self, msg, oname):
364 373 """Generic message when no information is found."""
365 374 print('No %s found' % msg, end=' ')
366 375 if oname:
367 376 print('for %s' % oname)
368 377 else:
369 378 print()
370 379
371 380 def pdef(self, obj, oname=''):
372 381 """Print the call signature for any callable object.
373 382
374 383 If the object is a class, print the constructor information."""
375 384
376 385 if not callable(obj):
377 386 print('Object is not callable.')
378 387 return
379 388
380 389 header = ''
381 390
382 391 if inspect.isclass(obj):
383 392 header = self.__head('Class constructor information:\n')
384 393 obj = obj.__init__
385 394 elif (not py3compat.PY3) and type(obj) is types.InstanceType:
386 395 obj = obj.__call__
387 396
388 397 output = self._getdef(obj,oname)
389 398 if output is None:
390 399 self.noinfo('definition header',oname)
391 400 else:
392 401 print(header,self.format(output), end=' ', file=io.stdout)
393 402
394 403 # In Python 3, all classes are new-style, so they all have __init__.
395 404 @skip_doctest_py3
396 405 def pdoc(self,obj,oname='',formatter = None):
397 406 """Print the docstring for any object.
398 407
399 408 Optional:
400 409 -formatter: a function to run the docstring through for specially
401 410 formatted docstrings.
402 411
403 412 Examples
404 413 --------
405 414
406 415 In [1]: class NoInit:
407 416 ...: pass
408 417
409 418 In [2]: class NoDoc:
410 419 ...: def __init__(self):
411 420 ...: pass
412 421
413 422 In [3]: %pdoc NoDoc
414 423 No documentation found for NoDoc
415 424
416 425 In [4]: %pdoc NoInit
417 426 No documentation found for NoInit
418 427
419 428 In [5]: obj = NoInit()
420 429
421 430 In [6]: %pdoc obj
422 431 No documentation found for obj
423 432
424 433 In [5]: obj2 = NoDoc()
425 434
426 435 In [6]: %pdoc obj2
427 436 No documentation found for obj2
428 437 """
429 438
430 439 head = self.__head # For convenience
431 440 lines = []
432 441 ds = getdoc(obj)
433 442 if formatter:
434 443 ds = formatter(ds)
435 444 if ds:
436 445 lines.append(head("Class Docstring:"))
437 446 lines.append(indent(ds))
438 447 if inspect.isclass(obj) and hasattr(obj, '__init__'):
439 448 init_ds = getdoc(obj.__init__)
440 449 if init_ds is not None:
441 450 lines.append(head("Constructor Docstring:"))
442 451 lines.append(indent(init_ds))
443 452 elif hasattr(obj,'__call__'):
444 453 call_ds = getdoc(obj.__call__)
445 454 if call_ds:
446 455 lines.append(head("Calling Docstring:"))
447 456 lines.append(indent(call_ds))
448 457
449 458 if not lines:
450 459 self.noinfo('documentation',oname)
451 460 else:
452 461 page.page('\n'.join(lines))
453 462
454 463 def psource(self,obj,oname=''):
455 464 """Print the source code for an object."""
456 465
457 466 # Flush the source cache because inspect can return out-of-date source
458 467 linecache.checkcache()
459 468 try:
460 469 src = getsource(obj)
461 470 except:
462 471 self.noinfo('source',oname)
463 472 else:
464 473 page.page(self.format(src))
465 474
466 475 def pfile(self, obj, oname=''):
467 476 """Show the whole file where an object was defined."""
468 477
469 478 lineno = find_source_lines(obj)
470 479 if lineno is None:
471 480 self.noinfo('file', oname)
472 481 return
473 482
474 483 ofile = find_file(obj)
475 484 # run contents of file through pager starting at line where the object
476 485 # is defined, as long as the file isn't binary and is actually on the
477 486 # filesystem.
478 487 if ofile.endswith(('.so', '.dll', '.pyd')):
479 488 print('File %r is binary, not printing.' % ofile)
480 489 elif not os.path.isfile(ofile):
481 490 print('File %r does not exist, not printing.' % ofile)
482 491 else:
483 492 # Print only text files, not extension binaries. Note that
484 493 # getsourcelines returns lineno with 1-offset and page() uses
485 494 # 0-offset, so we must adjust.
486 495 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
487 496
488 497 def _format_fields(self, fields, title_width=12):
489 498 """Formats a list of fields for display.
490 499
491 500 Parameters
492 501 ----------
493 502 fields : list
494 503 A list of 2-tuples: (field_title, field_content)
495 504 title_width : int
496 505 How many characters to pad titles to. Default 12.
497 506 """
498 507 out = []
499 508 header = self.__head
500 509 for title, content in fields:
501 510 if len(content.splitlines()) > 1:
502 511 title = header(title + ":") + "\n"
503 512 else:
504 513 title = header((title+":").ljust(title_width))
505 514 out.append(cast_unicode(title) + cast_unicode(content))
506 515 return "\n".join(out)
507 516
508 517 # The fields to be displayed by pinfo: (fancy_name, key_in_info_dict)
509 518 pinfo_fields1 = [("Type", "type_name"),
510 519 ]
511 520
512 521 pinfo_fields2 = [("String Form", "string_form"),
513 522 ]
514 523
515 524 pinfo_fields3 = [("Length", "length"),
516 525 ("File", "file"),
517 526 ("Definition", "definition"),
518 527 ]
519 528
520 529 pinfo_fields_obj = [("Class Docstring", "class_docstring"),
521 530 ("Constructor Docstring","init_docstring"),
522 531 ("Call def", "call_def"),
523 532 ("Call docstring", "call_docstring")]
524 533
525 534 def pinfo(self,obj,oname='',formatter=None,info=None,detail_level=0):
526 535 """Show detailed information about an object.
527 536
528 537 Optional arguments:
529 538
530 539 - oname: name of the variable pointing to the object.
531 540
532 541 - formatter: special formatter for docstrings (see pdoc)
533 542
534 543 - info: a structure with some information fields which may have been
535 544 precomputed already.
536 545
537 546 - detail_level: if set to 1, more information is given.
538 547 """
539 548 info = self.info(obj, oname=oname, formatter=formatter,
540 549 info=info, detail_level=detail_level)
541 550 displayfields = []
542 551 def add_fields(fields):
543 552 for title, key in fields:
544 553 field = info[key]
545 554 if field is not None:
546 555 displayfields.append((title, field.rstrip()))
547 556
548 557 add_fields(self.pinfo_fields1)
549 558
550 559 # Base class for old-style instances
551 560 if (not py3compat.PY3) and isinstance(obj, types.InstanceType) and info['base_class']:
552 561 displayfields.append(("Base Class", info['base_class'].rstrip()))
553 562
554 563 add_fields(self.pinfo_fields2)
555 564
556 565 # Namespace
557 566 if info['namespace'] != 'Interactive':
558 567 displayfields.append(("Namespace", info['namespace'].rstrip()))
559 568
560 569 add_fields(self.pinfo_fields3)
561 570
562 571 # Source or docstring, depending on detail level and whether
563 572 # source found.
564 573 if detail_level > 0 and info['source'] is not None:
565 574 displayfields.append(("Source",
566 575 self.format(cast_unicode(info['source']))))
567 576 elif info['docstring'] is not None:
568 577 displayfields.append(("Docstring", info["docstring"]))
569 578
570 579 # Constructor info for classes
571 580 if info['isclass']:
572 581 if info['init_definition'] or info['init_docstring']:
573 582 displayfields.append(("Constructor information", ""))
574 583 if info['init_definition'] is not None:
575 584 displayfields.append((" Definition",
576 585 info['init_definition'].rstrip()))
577 586 if info['init_docstring'] is not None:
578 587 displayfields.append((" Docstring",
579 588 indent(info['init_docstring'])))
580 589
581 590 # Info for objects:
582 591 else:
583 592 add_fields(self.pinfo_fields_obj)
584 593
585 594 # Finally send to printer/pager:
586 595 if displayfields:
587 596 page.page(self._format_fields(displayfields))
588 597
589 598 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
590 599 """Compute a dict with detailed information about an object.
591 600
592 601 Optional arguments:
593 602
594 603 - oname: name of the variable pointing to the object.
595 604
596 605 - formatter: special formatter for docstrings (see pdoc)
597 606
598 607 - info: a structure with some information fields which may have been
599 608 precomputed already.
600 609
601 610 - detail_level: if set to 1, more information is given.
602 611 """
603 612
604 613 obj_type = type(obj)
605 614
606 615 if info is None:
607 616 ismagic = 0
608 617 isalias = 0
609 618 ospace = ''
610 619 else:
611 620 ismagic = info.ismagic
612 621 isalias = info.isalias
613 622 ospace = info.namespace
614 623
615 624 # Get docstring, special-casing aliases:
616 625 if isalias:
617 626 if not callable(obj):
618 627 try:
619 628 ds = "Alias to the system command:\n %s" % obj[1]
620 629 except:
621 630 ds = "Alias: " + str(obj)
622 631 else:
623 632 ds = "Alias to " + str(obj)
624 633 if obj.__doc__:
625 634 ds += "\nDocstring:\n" + obj.__doc__
626 635 else:
627 636 ds = getdoc(obj)
628 637 if ds is None:
629 638 ds = '<no docstring>'
630 639 if formatter is not None:
631 640 ds = formatter(ds)
632 641
633 642 # store output in a dict, we initialize it here and fill it as we go
634 643 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
635 644
636 645 string_max = 200 # max size of strings to show (snipped if longer)
637 646 shalf = int((string_max -5)/2)
638 647
639 648 if ismagic:
640 649 obj_type_name = 'Magic function'
641 650 elif isalias:
642 651 obj_type_name = 'System alias'
643 652 else:
644 653 obj_type_name = obj_type.__name__
645 654 out['type_name'] = obj_type_name
646 655
647 656 try:
648 657 bclass = obj.__class__
649 658 out['base_class'] = str(bclass)
650 659 except: pass
651 660
652 661 # String form, but snip if too long in ? form (full in ??)
653 662 if detail_level >= self.str_detail_level:
654 663 try:
655 664 ostr = str(obj)
656 665 str_head = 'string_form'
657 666 if not detail_level and len(ostr)>string_max:
658 667 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
659 668 ostr = ("\n" + " " * len(str_head.expandtabs())).\
660 669 join(q.strip() for q in ostr.split("\n"))
661 670 out[str_head] = ostr
662 671 except:
663 672 pass
664 673
665 674 if ospace:
666 675 out['namespace'] = ospace
667 676
668 677 # Length (for strings and lists)
669 678 try:
670 679 out['length'] = str(len(obj))
671 680 except: pass
672 681
673 682 # Filename where object was defined
674 683 binary_file = False
675 684 fname = find_file(obj)
676 685 if fname is None:
677 686 # if anything goes wrong, we don't want to show source, so it's as
678 687 # if the file was binary
679 688 binary_file = True
680 689 else:
681 690 if fname.endswith(('.so', '.dll', '.pyd')):
682 691 binary_file = True
683 692 elif fname.endswith('<string>'):
684 693 fname = 'Dynamically generated function. No source code available.'
685 694 out['file'] = fname
686 695
687 696 # reconstruct the function definition and print it:
688 697 defln = self._getdef(obj, oname)
689 698 if defln:
690 699 out['definition'] = self.format(defln)
691 700
692 701 # Docstrings only in detail 0 mode, since source contains them (we
693 702 # avoid repetitions). If source fails, we add them back, see below.
694 703 if ds and detail_level == 0:
695 704 out['docstring'] = ds
696 705
697 706 # Original source code for any callable
698 707 if detail_level:
699 708 # Flush the source cache because inspect can return out-of-date
700 709 # source
701 710 linecache.checkcache()
702 711 source = None
703 712 try:
704 713 try:
705 714 source = getsource(obj, binary_file)
706 715 except TypeError:
707 716 if hasattr(obj, '__class__'):
708 717 source = getsource(obj.__class__, binary_file)
709 718 if source is not None:
710 719 out['source'] = source.rstrip()
711 720 except Exception:
712 721 pass
713 722
714 723 if ds and source is None:
715 724 out['docstring'] = ds
716 725
717 726
718 727 # Constructor docstring for classes
719 728 if inspect.isclass(obj):
720 729 out['isclass'] = True
721 730 # reconstruct the function definition and print it:
722 731 try:
723 732 obj_init = obj.__init__
724 733 except AttributeError:
725 734 init_def = init_ds = None
726 735 else:
727 736 init_def = self._getdef(obj_init,oname)
728 737 init_ds = getdoc(obj_init)
729 738 # Skip Python's auto-generated docstrings
730 739 if init_ds == _object_init_docstring:
731 740 init_ds = None
732 741
733 742 if init_def or init_ds:
734 743 if init_def:
735 744 out['init_definition'] = self.format(init_def)
736 745 if init_ds:
737 746 out['init_docstring'] = init_ds
738 747
739 748 # and class docstring for instances:
740 749 else:
741 750 # First, check whether the instance docstring is identical to the
742 751 # class one, and print it separately if they don't coincide. In
743 752 # most cases they will, but it's nice to print all the info for
744 753 # objects which use instance-customized docstrings.
745 754 if ds:
746 755 try:
747 756 cls = getattr(obj,'__class__')
748 757 except:
749 758 class_ds = None
750 759 else:
751 760 class_ds = getdoc(cls)
752 761 # Skip Python's auto-generated docstrings
753 762 if class_ds in _builtin_type_docstrings:
754 763 class_ds = None
755 764 if class_ds and ds != class_ds:
756 765 out['class_docstring'] = class_ds
757 766
758 767 # Next, try to show constructor docstrings
759 768 try:
760 769 init_ds = getdoc(obj.__init__)
761 770 # Skip Python's auto-generated docstrings
762 771 if init_ds == _object_init_docstring:
763 772 init_ds = None
764 773 except AttributeError:
765 774 init_ds = None
766 775 if init_ds:
767 776 out['init_docstring'] = init_ds
768 777
769 778 # Call form docstring for callable instances
770 if safe_hasattr(obj, '__call__'):
779 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
771 780 call_def = self._getdef(obj.__call__, oname)
772 781 if call_def is not None:
773 782 out['call_def'] = self.format(call_def)
774 783 call_ds = getdoc(obj.__call__)
775 784 # Skip Python's auto-generated docstrings
776 785 if call_ds == _func_call_docstring:
777 786 call_ds = None
778 787 if call_ds:
779 788 out['call_docstring'] = call_ds
780 789
781 790 # Compute the object's argspec as a callable. The key is to decide
782 791 # whether to pull it from the object itself, from its __init__ or
783 792 # from its __call__ method.
784 793
785 794 if inspect.isclass(obj):
786 795 # Old-style classes need not have an __init__
787 796 callable_obj = getattr(obj, "__init__", None)
788 797 elif callable(obj):
789 798 callable_obj = obj
790 799 else:
791 800 callable_obj = None
792 801
793 802 if callable_obj:
794 803 try:
795 804 argspec = getargspec(callable_obj)
796 805 except (TypeError, AttributeError):
797 806 # For extensions/builtins we can't retrieve the argspec
798 807 pass
799 808 else:
800 809 # named tuples' _asdict() method returns an OrderedDict, but we
801 810 # we want a normal
802 811 out['argspec'] = argspec_dict = dict(argspec._asdict())
803 812 # We called this varkw before argspec became a named tuple.
804 813 # With getfullargspec it's also called varkw.
805 814 if 'varkw' not in argspec_dict:
806 815 argspec_dict['varkw'] = argspec_dict.pop('keywords')
807 816
808 817 return object_info(**out)
809 818
810 819
811 820 def psearch(self,pattern,ns_table,ns_search=[],
812 821 ignore_case=False,show_all=False):
813 822 """Search namespaces with wildcards for objects.
814 823
815 824 Arguments:
816 825
817 826 - pattern: string containing shell-like wildcards to use in namespace
818 827 searches and optionally a type specification to narrow the search to
819 828 objects of that type.
820 829
821 830 - ns_table: dict of name->namespaces for search.
822 831
823 832 Optional arguments:
824 833
825 834 - ns_search: list of namespace names to include in search.
826 835
827 836 - ignore_case(False): make the search case-insensitive.
828 837
829 838 - show_all(False): show all names, including those starting with
830 839 underscores.
831 840 """
832 841 #print 'ps pattern:<%r>' % pattern # dbg
833 842
834 843 # defaults
835 844 type_pattern = 'all'
836 845 filter = ''
837 846
838 847 cmds = pattern.split()
839 848 len_cmds = len(cmds)
840 849 if len_cmds == 1:
841 850 # Only filter pattern given
842 851 filter = cmds[0]
843 852 elif len_cmds == 2:
844 853 # Both filter and type specified
845 854 filter,type_pattern = cmds
846 855 else:
847 856 raise ValueError('invalid argument string for psearch: <%s>' %
848 857 pattern)
849 858
850 859 # filter search namespaces
851 860 for name in ns_search:
852 861 if name not in ns_table:
853 862 raise ValueError('invalid namespace <%s>. Valid names: %s' %
854 863 (name,ns_table.keys()))
855 864
856 865 #print 'type_pattern:',type_pattern # dbg
857 866 search_result, namespaces_seen = set(), set()
858 867 for ns_name in ns_search:
859 868 ns = ns_table[ns_name]
860 869 # Normally, locals and globals are the same, so we just check one.
861 870 if id(ns) in namespaces_seen:
862 871 continue
863 872 namespaces_seen.add(id(ns))
864 873 tmp_res = list_namespace(ns, type_pattern, filter,
865 874 ignore_case=ignore_case, show_all=show_all)
866 875 search_result.update(tmp_res)
867 876
868 877 page.page('\n'.join(sorted(search_result)))
@@ -1,314 +1,325 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
20 20 # Third-party imports
21 21 import nose.tools as nt
22 22
23 23 # Our own imports
24 24 from .. import oinspect
25 25 from IPython.core.magic import (Magics, magics_class, line_magic,
26 26 cell_magic, line_cell_magic,
27 27 register_line_magic, register_cell_magic,
28 28 register_line_cell_magic)
29 29 from IPython.external.decorator import decorator
30 30 from IPython.testing.decorators import skipif
31 31 from IPython.utils import py3compat
32 32
33 33
34 34 #-----------------------------------------------------------------------------
35 35 # Globals and constants
36 36 #-----------------------------------------------------------------------------
37 37
38 38 inspector = oinspect.Inspector()
39 39 ip = get_ipython()
40 40
41 41 #-----------------------------------------------------------------------------
42 42 # Local utilities
43 43 #-----------------------------------------------------------------------------
44 44
45 45 # WARNING: since this test checks the line number where a function is
46 46 # defined, if any code is inserted above, the following line will need to be
47 47 # updated. Do NOT insert any whitespace between the next line and the function
48 48 # definition below.
49 49 THIS_LINE_NUMBER = 49 # Put here the actual number of this line
50 50 def test_find_source_lines():
51 51 nt.assert_equal(oinspect.find_source_lines(test_find_source_lines),
52 52 THIS_LINE_NUMBER+1)
53 53
54 54
55 55 # A couple of utilities to ensure these tests work the same from a source or a
56 56 # binary install
57 57 def pyfile(fname):
58 58 return os.path.normcase(re.sub('.py[co]$', '.py', fname))
59 59
60 60
61 61 def match_pyfiles(f1, f2):
62 62 nt.assert_equal(pyfile(f1), pyfile(f2))
63 63
64 64
65 65 def test_find_file():
66 66 match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__))
67 67
68 68
69 69 def test_find_file_decorated1():
70 70
71 71 @decorator
72 72 def noop1(f):
73 73 def wrapper():
74 74 return f(*a, **kw)
75 75 return wrapper
76 76
77 77 @noop1
78 78 def f(x):
79 79 "My docstring"
80 80
81 81 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
82 82 nt.assert_equal(f.__doc__, "My docstring")
83 83
84 84
85 85 def test_find_file_decorated2():
86 86
87 87 @decorator
88 88 def noop2(f, *a, **kw):
89 89 return f(*a, **kw)
90 90
91 91 @noop2
92 92 def f(x):
93 93 "My docstring 2"
94 94
95 95 match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__))
96 96 nt.assert_equal(f.__doc__, "My docstring 2")
97 97
98 98
99 99 def test_find_file_magic():
100 100 run = ip.find_line_magic('run')
101 101 nt.assert_not_equal(oinspect.find_file(run), None)
102 102
103 103
104 104 # A few generic objects we can then inspect in the tests below
105 105
106 106 class Call(object):
107 107 """This is the class docstring."""
108 108
109 109 def __init__(self, x, y=1):
110 110 """This is the constructor docstring."""
111 111
112 112 def __call__(self, *a, **kw):
113 113 """This is the call docstring."""
114 114
115 115 def method(self, x, z=2):
116 116 """Some method's docstring"""
117 117
118 class SimpleClass(object):
119 def method(self, x, z=2):
120 """Some method's docstring"""
121
118 122
119 123 class OldStyle:
120 124 """An old-style class for testing."""
121 125 pass
122 126
123 127
124 128 def f(x, y=2, *a, **kw):
125 129 """A simple function."""
126 130
127 131
128 132 def g(y, z=3, *a, **kw):
129 133 pass # no docstring
130 134
131 135
132 136 @register_line_magic
133 137 def lmagic(line):
134 138 "A line magic"
135 139
136 140
137 141 @register_cell_magic
138 142 def cmagic(line, cell):
139 143 "A cell magic"
140 144
141 145
142 146 @register_line_cell_magic
143 147 def lcmagic(line, cell=None):
144 148 "A line/cell magic"
145 149
146 150
147 151 @magics_class
148 152 class SimpleMagics(Magics):
149 153 @line_magic
150 154 def Clmagic(self, cline):
151 155 "A class-based line magic"
152 156
153 157 @cell_magic
154 158 def Ccmagic(self, cline, ccell):
155 159 "A class-based cell magic"
156 160
157 161 @line_cell_magic
158 162 def Clcmagic(self, cline, ccell=None):
159 163 "A class-based line/cell magic"
160 164
161 165
162 166 class Awkward(object):
163 167 def __getattr__(self, name):
164 168 raise Exception(name)
165 169
166 170
167 171 def check_calltip(obj, name, call, docstring):
168 172 """Generic check pattern all calltip tests will use"""
169 173 info = inspector.info(obj, name)
170 174 call_line, ds = oinspect.call_tip(info)
171 175 nt.assert_equal(call_line, call)
172 176 nt.assert_equal(ds, docstring)
173 177
174 178 #-----------------------------------------------------------------------------
175 179 # Tests
176 180 #-----------------------------------------------------------------------------
177 181
178 182 def test_calltip_class():
179 183 check_calltip(Call, 'Call', 'Call(x, y=1)', Call.__init__.__doc__)
180 184
181 185
182 186 def test_calltip_instance():
183 187 c = Call(1)
184 188 check_calltip(c, 'c', 'c(*a, **kw)', c.__call__.__doc__)
185 189
186 190
187 191 def test_calltip_method():
188 192 c = Call(1)
189 193 check_calltip(c.method, 'c.method', 'c.method(x, z=2)', c.method.__doc__)
190 194
191 195
192 196 def test_calltip_function():
193 197 check_calltip(f, 'f', 'f(x, y=2, *a, **kw)', f.__doc__)
194 198
195 199
196 200 def test_calltip_function2():
197 201 check_calltip(g, 'g', 'g(y, z=3, *a, **kw)', '<no docstring>')
198 202
199 203
200 204 def test_calltip_builtin():
201 205 check_calltip(sum, 'sum', None, sum.__doc__)
202 206
203 207
204 208 def test_calltip_line_magic():
205 209 check_calltip(lmagic, 'lmagic', 'lmagic(line)', "A line magic")
206 210
207 211
208 212 def test_calltip_cell_magic():
209 213 check_calltip(cmagic, 'cmagic', 'cmagic(line, cell)', "A cell magic")
210 214
211 215
212 216 def test_calltip_line_cell_magic():
213 217 check_calltip(lcmagic, 'lcmagic', 'lcmagic(line, cell=None)',
214 218 "A line/cell magic")
215 219
216 220
217 221 def test_class_magics():
218 222 cm = SimpleMagics(ip)
219 223 ip.register_magics(cm)
220 224 check_calltip(cm.Clmagic, 'Clmagic', 'Clmagic(cline)',
221 225 "A class-based line magic")
222 226 check_calltip(cm.Ccmagic, 'Ccmagic', 'Ccmagic(cline, ccell)',
223 227 "A class-based cell magic")
224 228 check_calltip(cm.Clcmagic, 'Clcmagic', 'Clcmagic(cline, ccell=None)',
225 229 "A class-based line/cell magic")
226 230
227 231
228 232 def test_info():
229 233 "Check that Inspector.info fills out various fields as expected."
230 234 i = inspector.info(Call, oname='Call')
231 235 nt.assert_equal(i['type_name'], 'type')
232 236 expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'>
233 237 nt.assert_equal(i['base_class'], expted_class)
234 238 nt.assert_equal(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'>")
235 239 fname = __file__
236 240 if fname.endswith(".pyc"):
237 241 fname = fname[:-1]
238 242 # case-insensitive comparison needed on some filesystems
239 243 # e.g. Windows:
240 244 nt.assert_equal(i['file'].lower(), fname.lower())
241 245 nt.assert_equal(i['definition'], 'Call(self, *a, **kw)\n')
242 246 nt.assert_equal(i['docstring'], Call.__doc__)
243 247 nt.assert_equal(i['source'], None)
244 248 nt.assert_true(i['isclass'])
245 249 nt.assert_equal(i['init_definition'], "Call(self, x, y=1)\n")
246 250 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
247 251
248 252 i = inspector.info(Call, detail_level=1)
249 253 nt.assert_not_equal(i['source'], None)
250 254 nt.assert_equal(i['docstring'], None)
251 255
252 256 c = Call(1)
253 257 c.__doc__ = "Modified instance docstring"
254 258 i = inspector.info(c)
255 259 nt.assert_equal(i['type_name'], 'Call')
256 260 nt.assert_equal(i['docstring'], "Modified instance docstring")
257 261 nt.assert_equal(i['class_docstring'], Call.__doc__)
258 262 nt.assert_equal(i['init_docstring'], Call.__init__.__doc__)
259 263 nt.assert_equal(i['call_docstring'], c.__call__.__doc__)
260 264
261 265 # Test old-style classes, which for example may not have an __init__ method.
262 266 if not py3compat.PY3:
263 267 i = inspector.info(OldStyle)
264 268 nt.assert_equal(i['type_name'], 'classobj')
265 269
266 270 i = inspector.info(OldStyle())
267 271 nt.assert_equal(i['type_name'], 'instance')
268 272 nt.assert_equal(i['docstring'], OldStyle.__doc__)
269 273
270 274 def test_info_awkward():
271 275 # Just test that this doesn't throw an error.
272 276 i = inspector.info(Awkward())
273 277
278 def test_calldef_none():
279 # We should ignore __call__ for all of these.
280 for obj in [f, SimpleClass().method, any, str.upper]:
281 print(obj)
282 i = inspector.info(obj)
283 nt.assert_is(i['call_def'], None)
284
274 285 if py3compat.PY3:
275 286 exec("def f_kwarg(pos, *, kwonly): pass")
276 287
277 288 @skipif(not py3compat.PY3)
278 289 def test_definition_kwonlyargs():
279 290 i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore
280 291 nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)\n")
281 292
282 293 def test_getdoc():
283 294 class A(object):
284 295 """standard docstring"""
285 296 pass
286 297
287 298 class B(object):
288 299 """standard docstring"""
289 300 def getdoc(self):
290 301 return "custom docstring"
291 302
292 303 class C(object):
293 304 """standard docstring"""
294 305 def getdoc(self):
295 306 return None
296 307
297 308 a = A()
298 309 b = B()
299 310 c = C()
300 311
301 312 nt.assert_equal(oinspect.getdoc(a), "standard docstring")
302 313 nt.assert_equal(oinspect.getdoc(b), "custom docstring")
303 314 nt.assert_equal(oinspect.getdoc(c), "standard docstring")
304 315
305 316 def test_pdef():
306 317 # See gh-1914
307 318 def foo(): pass
308 319 inspector.pdef(foo, 'foo')
309 320
310 321 def test_pinfo_nonascii():
311 322 # See gh-1177
312 323 from . import nonascii2
313 324 ip.user_ns['nonascii2'] = nonascii2
314 325 ip._inspect('pinfo', 'nonascii2', detail_level=1)
General Comments 0
You need to be logged in to leave comments. Login now