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