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