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