##// END OF EJS Templates
In obj??, display the docstring if it is not in the source....
Antony Lee -
Show More
@@ -1,996 +1,1014 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 # Copyright (c) IPython Development Team.
11 11 # Distributed under the terms of the Modified BSD License.
12 12
13 13 __all__ = ['Inspector','InspectColors']
14 14
15 15 # stdlib modules
16 import ast
16 17 import inspect
17 18 from inspect import signature
18 19 import linecache
19 20 import warnings
20 21 import os
21 22 from textwrap import dedent
22 23 import types
23 24 import io as stdlib_io
24 25 from itertools import zip_longest
25 26
26 27 # IPython's own
27 28 from IPython.core import page
28 29 from IPython.lib.pretty import pretty
29 30 from IPython.testing.skipdoctest import skip_doctest
30 31 from IPython.utils import PyColorize
31 32 from IPython.utils import openpy
32 33 from IPython.utils import py3compat
33 34 from IPython.utils.dir2 import safe_hasattr
34 35 from IPython.utils.path import compress_user
35 36 from IPython.utils.text import indent
36 37 from IPython.utils.wildcard import list_namespace
37 38 from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
38 39 from IPython.utils.py3compat import cast_unicode
39 40 from IPython.utils.colorable import Colorable
40 41 from IPython.utils.decorators import undoc
41 42
42 43 from pygments import highlight
43 44 from pygments.lexers import PythonLexer
44 45 from pygments.formatters import HtmlFormatter
45 46
46 47 def pylight(code):
47 48 return highlight(code, PythonLexer(), HtmlFormatter(noclasses=True))
48 49
49 50 # builtin docstrings to ignore
50 51 _func_call_docstring = types.FunctionType.__call__.__doc__
51 52 _object_init_docstring = object.__init__.__doc__
52 53 _builtin_type_docstrings = {
53 54 inspect.getdoc(t) for t in (types.ModuleType, types.MethodType,
54 55 types.FunctionType, property)
55 56 }
56 57
57 58 _builtin_func_type = type(all)
58 59 _builtin_meth_type = type(str.upper) # Bound methods have the same type as builtin functions
59 60 #****************************************************************************
60 61 # Builtin color schemes
61 62
62 63 Colors = TermColors # just a shorthand
63 64
64 65 InspectColors = PyColorize.ANSICodeColors
65 66
66 67 #****************************************************************************
67 68 # Auxiliary functions and objects
68 69
69 70 # See the messaging spec for the definition of all these fields. This list
70 71 # effectively defines the order of display
71 72 info_fields = ['type_name', 'base_class', 'string_form', 'namespace',
72 73 'length', 'file', 'definition', 'docstring', 'source',
73 74 'init_definition', 'class_docstring', 'init_docstring',
74 75 'call_def', 'call_docstring',
75 76 # These won't be printed but will be used to determine how to
76 77 # format the object
77 78 'ismagic', 'isalias', 'isclass', 'argspec', 'found', 'name'
78 79 ]
79 80
80 81
81 82 def object_info(**kw):
82 83 """Make an object info dict with all fields present."""
83 84 infodict = dict(zip_longest(info_fields, [None]))
84 85 infodict.update(kw)
85 86 return infodict
86 87
87 88
88 89 def get_encoding(obj):
89 90 """Get encoding for python source file defining obj
90 91
91 92 Returns None if obj is not defined in a sourcefile.
92 93 """
93 94 ofile = find_file(obj)
94 95 # run contents of file through pager starting at line where the object
95 96 # is defined, as long as the file isn't binary and is actually on the
96 97 # filesystem.
97 98 if ofile is None:
98 99 return None
99 100 elif ofile.endswith(('.so', '.dll', '.pyd')):
100 101 return None
101 102 elif not os.path.isfile(ofile):
102 103 return None
103 104 else:
104 105 # Print only text files, not extension binaries. Note that
105 106 # getsourcelines returns lineno with 1-offset and page() uses
106 107 # 0-offset, so we must adjust.
107 108 with stdlib_io.open(ofile, 'rb') as buffer: # Tweaked to use io.open for Python 2
108 109 encoding, lines = openpy.detect_encoding(buffer.readline)
109 110 return encoding
110 111
111 112 def getdoc(obj):
112 113 """Stable wrapper around inspect.getdoc.
113 114
114 115 This can't crash because of attribute problems.
115 116
116 117 It also attempts to call a getdoc() method on the given object. This
117 118 allows objects which provide their docstrings via non-standard mechanisms
118 119 (like Pyro proxies) to still be inspected by ipython's ? system.
119 120 """
120 121 # Allow objects to offer customized documentation via a getdoc method:
121 122 try:
122 123 ds = obj.getdoc()
123 124 except Exception:
124 125 pass
125 126 else:
126 127 if isinstance(ds, str):
127 128 return inspect.cleandoc(ds)
128 129 docstr = inspect.getdoc(obj)
129 130 encoding = get_encoding(obj)
130 131 return py3compat.cast_unicode(docstr, encoding=encoding)
131 132
132 133
133 134 def getsource(obj, oname=''):
134 135 """Wrapper around inspect.getsource.
135 136
136 137 This can be modified by other projects to provide customized source
137 138 extraction.
138 139
139 140 Parameters
140 141 ----------
141 142 obj : object
142 143 an object whose source code we will attempt to extract
143 144 oname : str
144 145 (optional) a name under which the object is known
145 146
146 147 Returns
147 148 -------
148 149 src : unicode or None
149 150
150 151 """
151 152
152 153 if isinstance(obj, property):
153 154 sources = []
154 155 for attrname in ['fget', 'fset', 'fdel']:
155 156 fn = getattr(obj, attrname)
156 157 if fn is not None:
157 158 encoding = get_encoding(fn)
158 159 oname_prefix = ('%s.' % oname) if oname else ''
159 160 sources.append(cast_unicode(
160 161 ''.join(('# ', oname_prefix, attrname)),
161 162 encoding=encoding))
162 163 if inspect.isfunction(fn):
163 164 sources.append(dedent(getsource(fn)))
164 165 else:
165 166 # Default str/repr only prints function name,
166 167 # pretty.pretty prints module name too.
167 168 sources.append(cast_unicode(
168 169 '%s%s = %s\n' % (
169 170 oname_prefix, attrname, pretty(fn)),
170 171 encoding=encoding))
171 172 if sources:
172 173 return '\n'.join(sources)
173 174 else:
174 175 return None
175 176
176 177 else:
177 178 # Get source for non-property objects.
178 179
179 180 obj = _get_wrapped(obj)
180 181
181 182 try:
182 183 src = inspect.getsource(obj)
183 184 except TypeError:
184 185 # The object itself provided no meaningful source, try looking for
185 186 # its class definition instead.
186 187 if hasattr(obj, '__class__'):
187 188 try:
188 189 src = inspect.getsource(obj.__class__)
189 190 except TypeError:
190 191 return None
191 192
192 193 encoding = get_encoding(obj)
193 194 return cast_unicode(src, encoding=encoding)
194 195
195 196
196 197 def is_simple_callable(obj):
197 198 """True if obj is a function ()"""
198 199 return (inspect.isfunction(obj) or inspect.ismethod(obj) or \
199 200 isinstance(obj, _builtin_func_type) or isinstance(obj, _builtin_meth_type))
200 201
201 202
202 203 def getargspec(obj):
203 204 """Wrapper around :func:`inspect.getfullargspec` on Python 3, and
204 205 :func:inspect.getargspec` on Python 2.
205 206
206 207 In addition to functions and methods, this can also handle objects with a
207 208 ``__call__`` attribute.
208 209 """
209 210 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
210 211 obj = obj.__call__
211 212
212 213 return inspect.getfullargspec(obj)
213 214
214 215
215 216 def format_argspec(argspec):
216 217 """Format argspect, convenience wrapper around inspect's.
217 218
218 219 This takes a dict instead of ordered arguments and calls
219 220 inspect.format_argspec with the arguments in the necessary order.
220 221 """
221 222 return inspect.formatargspec(argspec['args'], argspec['varargs'],
222 223 argspec['varkw'], argspec['defaults'])
223 224
224 225 @undoc
225 226 def call_tip(oinfo, format_call=True):
226 227 """DEPRECATED. Extract call tip data from an oinfo dict.
227 228 """
228 229 warnings.warn('`call_tip` function is deprecated as of IPython 6.0'
229 230 'and will be removed in future versions.', DeprecationWarning, stacklevel=2)
230 231 # Get call definition
231 232 argspec = oinfo.get('argspec')
232 233 if argspec is None:
233 234 call_line = None
234 235 else:
235 236 # Callable objects will have 'self' as their first argument, prune
236 237 # it out if it's there for clarity (since users do *not* pass an
237 238 # extra first argument explicitly).
238 239 try:
239 240 has_self = argspec['args'][0] == 'self'
240 241 except (KeyError, IndexError):
241 242 pass
242 243 else:
243 244 if has_self:
244 245 argspec['args'] = argspec['args'][1:]
245 246
246 247 call_line = oinfo['name']+format_argspec(argspec)
247 248
248 249 # Now get docstring.
249 250 # The priority is: call docstring, constructor docstring, main one.
250 251 doc = oinfo.get('call_docstring')
251 252 if doc is None:
252 253 doc = oinfo.get('init_docstring')
253 254 if doc is None:
254 255 doc = oinfo.get('docstring','')
255 256
256 257 return call_line, doc
257 258
258 259
259 260 def _get_wrapped(obj):
260 261 """Get the original object if wrapped in one or more @decorators
261 262
262 263 Some objects automatically construct similar objects on any unrecognised
263 264 attribute access (e.g. unittest.mock.call). To protect against infinite loops,
264 265 this will arbitrarily cut off after 100 levels of obj.__wrapped__
265 266 attribute access. --TK, Jan 2016
266 267 """
267 268 orig_obj = obj
268 269 i = 0
269 270 while safe_hasattr(obj, '__wrapped__'):
270 271 obj = obj.__wrapped__
271 272 i += 1
272 273 if i > 100:
273 274 # __wrapped__ is probably a lie, so return the thing we started with
274 275 return orig_obj
275 276 return obj
276 277
277 278 def find_file(obj):
278 279 """Find the absolute path to the file where an object was defined.
279 280
280 281 This is essentially a robust wrapper around `inspect.getabsfile`.
281 282
282 283 Returns None if no file can be found.
283 284
284 285 Parameters
285 286 ----------
286 287 obj : any Python object
287 288
288 289 Returns
289 290 -------
290 291 fname : str
291 292 The absolute path to the file where the object was defined.
292 293 """
293 294 obj = _get_wrapped(obj)
294 295
295 296 fname = None
296 297 try:
297 298 fname = inspect.getabsfile(obj)
298 299 except TypeError:
299 300 # For an instance, the file that matters is where its class was
300 301 # declared.
301 302 if hasattr(obj, '__class__'):
302 303 try:
303 304 fname = inspect.getabsfile(obj.__class__)
304 305 except TypeError:
305 306 # Can happen for builtins
306 307 pass
307 308 except:
308 309 pass
309 310 return cast_unicode(fname)
310 311
311 312
312 313 def find_source_lines(obj):
313 314 """Find the line number in a file where an object was defined.
314 315
315 316 This is essentially a robust wrapper around `inspect.getsourcelines`.
316 317
317 318 Returns None if no file can be found.
318 319
319 320 Parameters
320 321 ----------
321 322 obj : any Python object
322 323
323 324 Returns
324 325 -------
325 326 lineno : int
326 327 The line number where the object definition starts.
327 328 """
328 329 obj = _get_wrapped(obj)
329 330
330 331 try:
331 332 try:
332 333 lineno = inspect.getsourcelines(obj)[1]
333 334 except TypeError:
334 335 # For instances, try the class object like getsource() does
335 336 if hasattr(obj, '__class__'):
336 337 lineno = inspect.getsourcelines(obj.__class__)[1]
337 338 else:
338 339 lineno = None
339 340 except:
340 341 return None
341 342
342 343 return lineno
343 344
344 345 class Inspector(Colorable):
345 346
346 347 def __init__(self, color_table=InspectColors,
347 348 code_color_table=PyColorize.ANSICodeColors,
348 349 scheme=None,
349 350 str_detail_level=0,
350 351 parent=None, config=None):
351 352 super(Inspector, self).__init__(parent=parent, config=config)
352 353 self.color_table = color_table
353 354 self.parser = PyColorize.Parser(out='str', parent=self, style=scheme)
354 355 self.format = self.parser.format
355 356 self.str_detail_level = str_detail_level
356 357 self.set_active_scheme(scheme)
357 358
358 359 def _getdef(self,obj,oname=''):
359 360 """Return the call signature for any callable object.
360 361
361 362 If any exception is generated, None is returned instead and the
362 363 exception is suppressed."""
363 364 try:
364 365 hdef = oname + str(signature(obj))
365 366 return cast_unicode(hdef)
366 367 except:
367 368 return None
368 369
369 370 def __head(self,h):
370 371 """Return a header string with proper colors."""
371 372 return '%s%s%s' % (self.color_table.active_colors.header,h,
372 373 self.color_table.active_colors.normal)
373 374
374 375 def set_active_scheme(self, scheme):
375 376 if scheme is not None:
376 377 self.color_table.set_active_scheme(scheme)
377 378 self.parser.color_table.set_active_scheme(scheme)
378 379
379 380 def noinfo(self, msg, oname):
380 381 """Generic message when no information is found."""
381 382 print('No %s found' % msg, end=' ')
382 383 if oname:
383 384 print('for %s' % oname)
384 385 else:
385 386 print()
386 387
387 388 def pdef(self, obj, oname=''):
388 389 """Print the call signature for any callable object.
389 390
390 391 If the object is a class, print the constructor information."""
391 392
392 393 if not callable(obj):
393 394 print('Object is not callable.')
394 395 return
395 396
396 397 header = ''
397 398
398 399 if inspect.isclass(obj):
399 400 header = self.__head('Class constructor information:\n')
400 401
401 402
402 403 output = self._getdef(obj,oname)
403 404 if output is None:
404 405 self.noinfo('definition header',oname)
405 406 else:
406 407 print(header,self.format(output), end=' ')
407 408
408 409 # In Python 3, all classes are new-style, so they all have __init__.
409 410 @skip_doctest
410 411 def pdoc(self, obj, oname='', formatter=None):
411 412 """Print the docstring for any object.
412 413
413 414 Optional:
414 415 -formatter: a function to run the docstring through for specially
415 416 formatted docstrings.
416 417
417 418 Examples
418 419 --------
419 420
420 421 In [1]: class NoInit:
421 422 ...: pass
422 423
423 424 In [2]: class NoDoc:
424 425 ...: def __init__(self):
425 426 ...: pass
426 427
427 428 In [3]: %pdoc NoDoc
428 429 No documentation found for NoDoc
429 430
430 431 In [4]: %pdoc NoInit
431 432 No documentation found for NoInit
432 433
433 434 In [5]: obj = NoInit()
434 435
435 436 In [6]: %pdoc obj
436 437 No documentation found for obj
437 438
438 439 In [5]: obj2 = NoDoc()
439 440
440 441 In [6]: %pdoc obj2
441 442 No documentation found for obj2
442 443 """
443 444
444 445 head = self.__head # For convenience
445 446 lines = []
446 447 ds = getdoc(obj)
447 448 if formatter:
448 449 ds = formatter(ds).get('plain/text', ds)
449 450 if ds:
450 451 lines.append(head("Class docstring:"))
451 452 lines.append(indent(ds))
452 453 if inspect.isclass(obj) and hasattr(obj, '__init__'):
453 454 init_ds = getdoc(obj.__init__)
454 455 if init_ds is not None:
455 456 lines.append(head("Init docstring:"))
456 457 lines.append(indent(init_ds))
457 458 elif hasattr(obj,'__call__'):
458 459 call_ds = getdoc(obj.__call__)
459 460 if call_ds:
460 461 lines.append(head("Call docstring:"))
461 462 lines.append(indent(call_ds))
462 463
463 464 if not lines:
464 465 self.noinfo('documentation',oname)
465 466 else:
466 467 page.page('\n'.join(lines))
467 468
468 469 def psource(self, obj, oname=''):
469 470 """Print the source code for an object."""
470 471
471 472 # Flush the source cache because inspect can return out-of-date source
472 473 linecache.checkcache()
473 474 try:
474 475 src = getsource(obj, oname=oname)
475 476 except Exception:
476 477 src = None
477 478
478 479 if src is None:
479 480 self.noinfo('source', oname)
480 481 else:
481 482 page.page(self.format(src))
482 483
483 484 def pfile(self, obj, oname=''):
484 485 """Show the whole file where an object was defined."""
485 486
486 487 lineno = find_source_lines(obj)
487 488 if lineno is None:
488 489 self.noinfo('file', oname)
489 490 return
490 491
491 492 ofile = find_file(obj)
492 493 # run contents of file through pager starting at line where the object
493 494 # is defined, as long as the file isn't binary and is actually on the
494 495 # filesystem.
495 496 if ofile.endswith(('.so', '.dll', '.pyd')):
496 497 print('File %r is binary, not printing.' % ofile)
497 498 elif not os.path.isfile(ofile):
498 499 print('File %r does not exist, not printing.' % ofile)
499 500 else:
500 501 # Print only text files, not extension binaries. Note that
501 502 # getsourcelines returns lineno with 1-offset and page() uses
502 503 # 0-offset, so we must adjust.
503 504 page.page(self.format(openpy.read_py_file(ofile, skip_encoding_cookie=False)), lineno - 1)
504 505
505 506 def _format_fields(self, fields, title_width=0):
506 507 """Formats a list of fields for display.
507 508
508 509 Parameters
509 510 ----------
510 511 fields : list
511 512 A list of 2-tuples: (field_title, field_content)
512 513 title_width : int
513 514 How many characters to pad titles to. Default to longest title.
514 515 """
515 516 out = []
516 517 header = self.__head
517 518 if title_width == 0:
518 519 title_width = max(len(title) + 2 for title, _ in fields)
519 520 for title, content in fields:
520 521 if len(content.splitlines()) > 1:
521 522 title = header(title + ':') + '\n'
522 523 else:
523 524 title = header((title + ':').ljust(title_width))
524 525 out.append(cast_unicode(title) + cast_unicode(content))
525 526 return "\n".join(out)
526 527
527 528 def _mime_format(self, text, formatter=None):
528 529 """Return a mime bundle representation of the input text.
529 530
530 531 - if `formatter` is None, the returned mime bundle has
531 532 a `text/plain` field, with the input text.
532 533 a `text/html` field with a `<pre>` tag containing the input text.
533 534
534 535 - if `formatter` is not None, it must be a callable transforming the
535 536 input text into a mime bundle. Default values for `text/plain` and
536 537 `text/html` representations are the ones described above.
537 538
538 539 Note:
539 540
540 541 Formatters returning strings are supported but this behavior is deprecated.
541 542
542 543 """
543 544 text = cast_unicode(text)
544 545 defaults = {
545 546 'text/plain': text,
546 547 'text/html': '<pre>' + text + '</pre>'
547 548 }
548 549
549 550 if formatter is None:
550 551 return defaults
551 552 else:
552 553 formatted = formatter(text)
553 554
554 555 if not isinstance(formatted, dict):
555 556 # Handle the deprecated behavior of a formatter returning
556 557 # a string instead of a mime bundle.
557 558 return {
558 559 'text/plain': formatted,
559 560 'text/html': '<pre>' + formatted + '</pre>'
560 561 }
561 562
562 563 else:
563 564 return dict(defaults, **formatted)
564 565
565 566
566 567 def format_mime(self, bundle):
567 568
568 569 text_plain = bundle['text/plain']
569 570
570 571 text = ''
571 572 heads, bodies = list(zip(*text_plain))
572 573 _len = max(len(h) for h in heads)
573 574
574 575 for head, body in zip(heads, bodies):
575 576 body = body.strip('\n')
576 577 delim = '\n' if '\n' in body else ' '
577 578 text += self.__head(head+':') + (_len - len(head))*' ' +delim + body +'\n'
578 579
579 580 bundle['text/plain'] = text
580 581 return bundle
581 582
582 583 def _get_info(self, obj, oname='', formatter=None, info=None, detail_level=0):
583 584 """Retrieve an info dict and format it.
584 585
585 586 Parameters
586 587 ==========
587 588
588 589 obj: any
589 590 Object to inspect and return info from
590 591 oname: str (default: ''):
591 592 Name of the variable pointing to `obj`.
592 593 formatter: callable
593 594 info:
594 595 already computed information
595 596 detail_level: integer
596 597 Granularity of detail level, if set to 1, give more information.
597 598 """
598 599
599 600 info = self._info(obj, oname=oname, info=info, detail_level=detail_level)
600 601
601 602 _mime = {
602 603 'text/plain': [],
603 604 'text/html': '',
604 605 }
605 606
606 607 def append_field(bundle, title, key, formatter=None):
607 608 field = info[key]
608 609 if field is not None:
609 610 formatted_field = self._mime_format(field, formatter)
610 611 bundle['text/plain'].append((title, formatted_field['text/plain']))
611 612 bundle['text/html'] += '<h1>' + title + '</h1>\n' + formatted_field['text/html'] + '\n'
612 613
613 614 def code_formatter(text):
614 615 return {
615 616 'text/plain': self.format(text),
616 617 'text/html': pylight(text)
617 618 }
618 619
619 620 if info['isalias']:
620 621 append_field(_mime, 'Repr', 'string_form')
621 622
622 623 elif info['ismagic']:
623 624 if detail_level > 0:
624 625 append_field(_mime, 'Source', 'source', code_formatter)
625 626 else:
626 627 append_field(_mime, 'Docstring', 'docstring', formatter)
627 628 append_field(_mime, 'File', 'file')
628 629
629 630 elif info['isclass'] or is_simple_callable(obj):
630 631 # Functions, methods, classes
631 632 append_field(_mime, 'Signature', 'definition', code_formatter)
632 633 append_field(_mime, 'Init signature', 'init_definition', code_formatter)
634 append_field(_mime, 'Docstring', 'docstring', formatter)
633 635 if detail_level > 0 and info['source']:
634 636 append_field(_mime, 'Source', 'source', code_formatter)
635 637 else:
636 append_field(_mime, 'Docstring', 'docstring', formatter)
637 638 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
638 639
639 640 append_field(_mime, 'File', 'file')
640 641 append_field(_mime, 'Type', 'type_name')
641 642
642 643 else:
643 644 # General Python objects
644 645 append_field(_mime, 'Signature', 'definition', code_formatter)
645 646 append_field(_mime, 'Call signature', 'call_def', code_formatter)
646 647 append_field(_mime, 'Type', 'type_name')
647 648 append_field(_mime, 'String form', 'string_form')
648 649
649 650 # Namespace
650 651 if info['namespace'] != 'Interactive':
651 652 append_field(_mime, 'Namespace', 'namespace')
652 653
653 654 append_field(_mime, 'Length', 'length')
654 655 append_field(_mime, 'File', 'file')
655 656
656 657 # Source or docstring, depending on detail level and whether
657 658 # source found.
658 659 if detail_level > 0 and info['source']:
659 660 append_field(_mime, 'Source', 'source', code_formatter)
660 661 else:
661 662 append_field(_mime, 'Docstring', 'docstring', formatter)
662 663
663 664 append_field(_mime, 'Class docstring', 'class_docstring', formatter)
664 665 append_field(_mime, 'Init docstring', 'init_docstring', formatter)
665 666 append_field(_mime, 'Call docstring', 'call_docstring', formatter)
666 667
667 668
668 669 return self.format_mime(_mime)
669 670
670 671 def pinfo(self, obj, oname='', formatter=None, info=None, detail_level=0, enable_html_pager=True):
671 672 """Show detailed information about an object.
672 673
673 674 Optional arguments:
674 675
675 676 - oname: name of the variable pointing to the object.
676 677
677 678 - formatter: callable (optional)
678 679 A special formatter for docstrings.
679 680
680 681 The formatter is a callable that takes a string as an input
681 682 and returns either a formatted string or a mime type bundle
682 683 in the form of a dictionary.
683 684
684 685 Although the support of custom formatter returning a string
685 686 instead of a mime type bundle is deprecated.
686 687
687 688 - info: a structure with some information fields which may have been
688 689 precomputed already.
689 690
690 691 - detail_level: if set to 1, more information is given.
691 692 """
692 693 info = self._get_info(obj, oname, formatter, info, detail_level)
693 694 if not enable_html_pager:
694 695 del info['text/html']
695 696 page.page(info)
696 697
697 698 def info(self, obj, oname='', formatter=None, info=None, detail_level=0):
698 699 """DEPRECATED. Compute a dict with detailed information about an object.
699 700 """
700 701 if formatter is not None:
701 702 warnings.warn('The `formatter` keyword argument to `Inspector.info`'
702 703 'is deprecated as of IPython 5.0 and will have no effects.',
703 704 DeprecationWarning, stacklevel=2)
704 705 return self._info(obj, oname=oname, info=info, detail_level=detail_level)
705 706
706 707 def _info(self, obj, oname='', info=None, detail_level=0) -> dict:
707 708 """Compute a dict with detailed information about an object.
708 709
709 710 Parameters
710 711 ==========
711 712
712 713 obj: any
713 714 An object to find information about
714 715 oname: str (default: ''):
715 716 Name of the variable pointing to `obj`.
716 717 info: (default: None)
717 718 A struct (dict like with attr access) with some information fields
718 719 which may have been precomputed already.
719 720 detail_level: int (default:0)
720 721 If set to 1, more information is given.
721 722
722 723 Returns
723 724 =======
724 725
725 726 An object info dict with known fields from `info_fields`.
726 727 """
727 728
728 729 if info is None:
729 730 ismagic = False
730 731 isalias = False
731 732 ospace = ''
732 733 else:
733 734 ismagic = info.ismagic
734 735 isalias = info.isalias
735 736 ospace = info.namespace
736 737
737 738 # Get docstring, special-casing aliases:
738 739 if isalias:
739 740 if not callable(obj):
740 741 try:
741 742 ds = "Alias to the system command:\n %s" % obj[1]
742 743 except:
743 744 ds = "Alias: " + str(obj)
744 745 else:
745 746 ds = "Alias to " + str(obj)
746 747 if obj.__doc__:
747 748 ds += "\nDocstring:\n" + obj.__doc__
748 749 else:
749 750 ds = getdoc(obj)
750 751 if ds is None:
751 752 ds = '<no docstring>'
752 753
753 754 # store output in a dict, we initialize it here and fill it as we go
754 755 out = dict(name=oname, found=True, isalias=isalias, ismagic=ismagic)
755 756
756 757 string_max = 200 # max size of strings to show (snipped if longer)
757 758 shalf = int((string_max - 5) / 2)
758 759
759 760 if ismagic:
760 761 out['type_name'] = 'Magic function'
761 762 elif isalias:
762 763 out['type_name'] = 'System alias'
763 764 else:
764 765 out['type_name'] = type(obj).__name__
765 766
766 767 try:
767 768 bclass = obj.__class__
768 769 out['base_class'] = str(bclass)
769 770 except:
770 771 pass
771 772
772 773 # String form, but snip if too long in ? form (full in ??)
773 774 if detail_level >= self.str_detail_level:
774 775 try:
775 776 ostr = str(obj)
776 777 str_head = 'string_form'
777 778 if not detail_level and len(ostr)>string_max:
778 779 ostr = ostr[:shalf] + ' <...> ' + ostr[-shalf:]
779 780 ostr = ("\n" + " " * len(str_head.expandtabs())).\
780 781 join(q.strip() for q in ostr.split("\n"))
781 782 out[str_head] = ostr
782 783 except:
783 784 pass
784 785
785 786 if ospace:
786 787 out['namespace'] = ospace
787 788
788 789 # Length (for strings and lists)
789 790 try:
790 791 out['length'] = str(len(obj))
791 792 except Exception:
792 793 pass
793 794
794 795 # Filename where object was defined
795 796 binary_file = False
796 797 fname = find_file(obj)
797 798 if fname is None:
798 799 # if anything goes wrong, we don't want to show source, so it's as
799 800 # if the file was binary
800 801 binary_file = True
801 802 else:
802 803 if fname.endswith(('.so', '.dll', '.pyd')):
803 804 binary_file = True
804 805 elif fname.endswith('<string>'):
805 806 fname = 'Dynamically generated function. No source code available.'
806 807 out['file'] = compress_user(fname)
807 808
808 809 # Original source code for a callable, class or property.
809 810 if detail_level:
810 811 # Flush the source cache because inspect can return out-of-date
811 812 # source
812 813 linecache.checkcache()
813 814 try:
814 815 if isinstance(obj, property) or not binary_file:
815 816 src = getsource(obj, oname)
816 817 if src is not None:
817 818 src = src.rstrip()
818 819 out['source'] = src
819 820
820 821 except Exception:
821 822 pass
822 823
823 824 # Add docstring only if no source is to be shown (avoid repetitions).
824 if ds and out.get('source', None) is None:
825 if ds and not self._source_contains_docstring(out.get('source'), ds):
825 826 out['docstring'] = ds
826 827
827 828 # Constructor docstring for classes
828 829 if inspect.isclass(obj):
829 830 out['isclass'] = True
830 831
831 832 # get the init signature:
832 833 try:
833 834 init_def = self._getdef(obj, oname)
834 835 except AttributeError:
835 836 init_def = None
836 837
837 838 # get the __init__ docstring
838 839 try:
839 840 obj_init = obj.__init__
840 841 except AttributeError:
841 842 init_ds = None
842 843 else:
843 844 if init_def is None:
844 845 # Get signature from init if top-level sig failed.
845 846 # Can happen for built-in types (list, etc.).
846 847 try:
847 848 init_def = self._getdef(obj_init, oname)
848 849 except AttributeError:
849 850 pass
850 851 init_ds = getdoc(obj_init)
851 852 # Skip Python's auto-generated docstrings
852 853 if init_ds == _object_init_docstring:
853 854 init_ds = None
854 855
855 856 if init_def:
856 857 out['init_definition'] = init_def
857 858
858 859 if init_ds:
859 860 out['init_docstring'] = init_ds
860 861
861 862 # and class docstring for instances:
862 863 else:
863 864 # reconstruct the function definition and print it:
864 865 defln = self._getdef(obj, oname)
865 866 if defln:
866 867 out['definition'] = defln
867 868
868 869 # First, check whether the instance docstring is identical to the
869 870 # class one, and print it separately if they don't coincide. In
870 871 # most cases they will, but it's nice to print all the info for
871 872 # objects which use instance-customized docstrings.
872 873 if ds:
873 874 try:
874 875 cls = getattr(obj,'__class__')
875 876 except:
876 877 class_ds = None
877 878 else:
878 879 class_ds = getdoc(cls)
879 880 # Skip Python's auto-generated docstrings
880 881 if class_ds in _builtin_type_docstrings:
881 882 class_ds = None
882 883 if class_ds and ds != class_ds:
883 884 out['class_docstring'] = class_ds
884 885
885 886 # Next, try to show constructor docstrings
886 887 try:
887 888 init_ds = getdoc(obj.__init__)
888 889 # Skip Python's auto-generated docstrings
889 890 if init_ds == _object_init_docstring:
890 891 init_ds = None
891 892 except AttributeError:
892 893 init_ds = None
893 894 if init_ds:
894 895 out['init_docstring'] = init_ds
895 896
896 897 # Call form docstring for callable instances
897 898 if safe_hasattr(obj, '__call__') and not is_simple_callable(obj):
898 899 call_def = self._getdef(obj.__call__, oname)
899 900 if call_def and (call_def != out.get('definition')):
900 901 # it may never be the case that call def and definition differ,
901 902 # but don't include the same signature twice
902 903 out['call_def'] = call_def
903 904 call_ds = getdoc(obj.__call__)
904 905 # Skip Python's auto-generated docstrings
905 906 if call_ds == _func_call_docstring:
906 907 call_ds = None
907 908 if call_ds:
908 909 out['call_docstring'] = call_ds
909 910
910 911 # Compute the object's argspec as a callable. The key is to decide
911 912 # whether to pull it from the object itself, from its __init__ or
912 913 # from its __call__ method.
913 914
914 915 if inspect.isclass(obj):
915 916 # Old-style classes need not have an __init__
916 917 callable_obj = getattr(obj, "__init__", None)
917 918 elif callable(obj):
918 919 callable_obj = obj
919 920 else:
920 921 callable_obj = None
921 922
922 923 if callable_obj is not None:
923 924 try:
924 925 argspec = getargspec(callable_obj)
925 926 except Exception:
926 927 # For extensions/builtins we can't retrieve the argspec
927 928 pass
928 929 else:
929 930 # named tuples' _asdict() method returns an OrderedDict, but we
930 931 # we want a normal
931 932 out['argspec'] = argspec_dict = dict(argspec._asdict())
932 933 # We called this varkw before argspec became a named tuple.
933 934 # With getfullargspec it's also called varkw.
934 935 if 'varkw' not in argspec_dict:
935 936 argspec_dict['varkw'] = argspec_dict.pop('keywords')
936 937
937 938 return object_info(**out)
938 939
940 @staticmethod
941 def _source_contains_docstring(src, doc):
942 """
943 Check whether the source *src* contains the docstring *doc*.
944
945 This is is helper function to skip displaying the docstring if the
946 source already contains it, avoiding repetition of information.
947 """
948 try:
949 def_node, = ast.parse(dedent(src)).body
950 return ast.get_docstring(def_node) == doc
951 except Exception:
952 # The source can become invalid or even non-existent (because it
953 # is re-fetched from the source file) so the above code fail in
954 # arbitrary ways.
955 return False
956
939 957 def psearch(self,pattern,ns_table,ns_search=[],
940 958 ignore_case=False,show_all=False):
941 959 """Search namespaces with wildcards for objects.
942 960
943 961 Arguments:
944 962
945 963 - pattern: string containing shell-like wildcards to use in namespace
946 964 searches and optionally a type specification to narrow the search to
947 965 objects of that type.
948 966
949 967 - ns_table: dict of name->namespaces for search.
950 968
951 969 Optional arguments:
952 970
953 971 - ns_search: list of namespace names to include in search.
954 972
955 973 - ignore_case(False): make the search case-insensitive.
956 974
957 975 - show_all(False): show all names, including those starting with
958 976 underscores.
959 977 """
960 978 #print 'ps pattern:<%r>' % pattern # dbg
961 979
962 980 # defaults
963 981 type_pattern = 'all'
964 982 filter = ''
965 983
966 984 cmds = pattern.split()
967 985 len_cmds = len(cmds)
968 986 if len_cmds == 1:
969 987 # Only filter pattern given
970 988 filter = cmds[0]
971 989 elif len_cmds == 2:
972 990 # Both filter and type specified
973 991 filter,type_pattern = cmds
974 992 else:
975 993 raise ValueError('invalid argument string for psearch: <%s>' %
976 994 pattern)
977 995
978 996 # filter search namespaces
979 997 for name in ns_search:
980 998 if name not in ns_table:
981 999 raise ValueError('invalid namespace <%s>. Valid names: %s' %
982 1000 (name,ns_table.keys()))
983 1001
984 1002 #print 'type_pattern:',type_pattern # dbg
985 1003 search_result, namespaces_seen = set(), set()
986 1004 for ns_name in ns_search:
987 1005 ns = ns_table[ns_name]
988 1006 # Normally, locals and globals are the same, so we just check one.
989 1007 if id(ns) in namespaces_seen:
990 1008 continue
991 1009 namespaces_seen.add(id(ns))
992 1010 tmp_res = list_namespace(ns, type_pattern, filter,
993 1011 ignore_case=ignore_case, show_all=show_all)
994 1012 search_result.update(tmp_res)
995 1013
996 1014 page.page('\n'.join(sorted(search_result)))
General Comments 0
You need to be logged in to leave comments. Login now