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