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