docstr: Compute a dict with detailed information about an object.
  
  Parameters
  ----------
  obj : any
      An object to find information about
  oname : str (default: '')
      Name of the variable pointing to `obj`.
  info : (default: None)
      A struct (dict like with attr access) with some information fields
      which may have been precomputed already.
  detail_level : int (default:0)
      If set to 1, more information is given.
  
  Returns
  -------
  An object info dict with known fields from `info_fields`. Keys are
  strings, values are string or None.
docstr_tok: ["Compute","a","dict","with","detailed","information","about","an","object",".","Parameters","--","--","--","--","--","obj",":","any","An","object","to","find","information","about","oname",":","str","(","default",":","``",")","Name","of","the","variable","pointing","to","`","obj","`",".","info",":","(","default",":","None",")","A","struct","(","dict","like","with","attr","access",")","with","some","information","fields","which","may","have","been","precomputed","already",".","detail_level",":","int","(","default:0",")","If","set","to","1",",","more","information","is","given",".","Returns","--","--","--","-","An","object","info","dict","with","known","fields","from","`","info_fields","`",".","Keys","are","strings",",","values","are","string","or","None","."]
code: def info(
      self, obj, oname="", info=None, detail_level=0
  ) -> Dict[str, Any]:
      """Compute a dict with detailed information about an object.
  
      Parameters
      ----------
      obj : any
          An object to find information about
      oname : str (default: '')
          Name of the variable pointing to `obj`.
      info : (default: None)
          A struct (dict like with attr access) with some information fields
          which may have been precomputed already.
      detail_level : int (default:0)
          If set to 1, more information is given.
  
      Returns
      -------
      An object info dict with known fields from `info_fields`. Keys are
      strings, values are string or None.
      """
  
      if info is None:
          ismagic = False
          isalias = False
          ospace = ""
      else:
          ismagic = info.ismagic
          isalias = info.isalias
          ospace = info.namespace
  
      # Get docstring, special-casing aliases:
      att_name = oname.split(".")[-1]
      parents_docs = None
      prelude = ""
      if (
          info
          and info.parent is not None
          and hasattr(info.parent, HOOK_NAME)
      ):
          parents_docs_dict = getattr(info.parent, HOOK_NAME)
          parents_docs = parents_docs_dict.get(att_name, None)
      out = dict(
          name=oname,
          found=True,
          isalias=isalias,
          ismagic=ismagic,
          subclasses=None,
      )
  
      if parents_docs:
          ds = parents_docs
      elif isalias:
          if not callable(obj):
              try:
                  ds = "Alias to the system command:\n  %s" % obj[1]
              except:
                  ds = "Alias: " + str(obj)
          else:
              ds = "Alias to " + str(obj)
              if obj.__doc__:
                  ds += "\nDocstring:\n" + obj.__doc__
      else:
          ds_or_None = getdoc(obj)
          if ds_or_None is None:
              ds = "<no docstring>"
          else:
              ds = ds_or_None
  
      ds = prelude + ds
  
      # store output in a dict, we initialize it here and fill it as we go
  
      string_max = (
          200  # max size of strings to show (snipped if longer)
      )
      shalf = int((string_max - 5) / 2)
  
      if ismagic:
          out["type_name"] = "Magic function"
      elif isalias:
          out["type_name"] = "System alias"
      else:
          out["type_name"] = type(obj).__name__
  
      try:
          bclass = obj.__class__
          out["base_class"] = str(bclass)
      except:
          pass
  
      # String form, but snip if too long in ? form (full in ??)
      if detail_level >= self.str_detail_level:
          try:
              ostr = str(obj)
              str_head = "string_form"
              if not detail_level and len(ostr) > string_max:
                  ostr = ostr[:shalf] + " <...> " + ostr[-shalf:]
                  ostr = ("\n" + " " * len(str_head.expandtabs())).join(
                      q.strip() for q in ostr.split("\n")
                  )
              out[str_head] = ostr
          except:
              pass
  
      if ospace:
          out["namespace"] = ospace
  
      # Length (for strings and lists)
      try:
          out["length"] = str(len(obj))
      except Exception:
          pass
  
      # Filename where object was defined
      binary_file = False
      fname = find_file(obj)
      if fname is None:
          # if anything goes wrong, we don't want to show source, so it's as
          # if the file was binary
          binary_file = True
      else:
          if fname.endswith((".so", ".dll", ".pyd")):
              binary_file = True
          elif fname.endswith("<string>"):
              fname = "Dynamically generated function. No source code available."
          out["file"] = compress_user(fname)
  
      # Original source code for a callable, class or property.
      if detail_level:
          # Flush the source cache because inspect can return out-of-date
          # source
          linecache.checkcache()
          try:
              if isinstance(obj, property) or not binary_file:
                  src = getsource(obj, oname)
                  if src is not None:
                      src = src.rstrip()
                  out["source"] = src
  
          except Exception:
              pass
  
      # Add docstring only if no source is to be shown (avoid repetitions).
      if ds and not self._source_contains_docstring(
          out.get("source"), ds
      ):
          out["docstring"] = ds
  
      # Constructor docstring for classes
      if inspect.isclass(obj):
          out["isclass"] = True
  
          # get the init signature:
          try:
              init_def = self._getdef(obj, oname)
          except AttributeError:
              init_def = None
  
          # get the __init__ docstring
          try:
              obj_init = obj.__init__
          except AttributeError:
              init_ds = None
          else:
              if init_def is None:
                  # Get signature from init if top-level sig failed.
                  # Can happen for built-in types (list, etc.).
                  try:
                      init_def = self._getdef(obj_init, oname)
                  except AttributeError:
                      pass
              init_ds = getdoc(obj_init)
              # Skip Python's auto-generated docstrings
              if init_ds == _object_init_docstring:
                  init_ds = None
  
          if init_def:
              out["init_definition"] = init_def
  
          if init_ds:
              out["init_docstring"] = init_ds
  
          names = [sub.__name__ for sub in type.__subclasses__(obj)]
          if len(names) < 10:
              all_names = ", ".join(names)
          else:
              all_names = ", ".join(names[:10] + ["..."])
          out["subclasses"] = all_names
      # and class docstring for instances:
      else:
          # reconstruct the function definition and print it:
          defln = self._getdef(obj, oname)
          if defln:
              out["definition"] = defln
  
          # First, check whether the instance docstring is identical to the
          # class one, and print it separately if they don't coincide.  In
          # most cases they will, but it's nice to print all the info for
          # objects which use instance-customized docstrings.
          if ds:
              try:
                  cls = getattr(obj, "__class__")
              except:
                  class_ds = None
              else:
                  class_ds = getdoc(cls)
              # Skip Python's auto-generated docstrings
              if class_ds in _builtin_type_docstrings:
                  class_ds = None
              if class_ds and ds != class_ds:
                  out["class_docstring"] = class_ds
  
          # Next, try to show constructor docstrings
          try:
              init_ds = getdoc(obj.__init__)
              # Skip Python's auto-generated docstrings
              if init_ds == _object_init_docstring:
                  init_ds = None
          except AttributeError:
              init_ds = None
          if init_ds:
              out["init_docstring"] = init_ds
  
          # Call form docstring for callable instances
          if safe_hasattr(obj, "__call__") and not is_simple_callable(
              obj
          ):
              call_def = self._getdef(obj.__call__, oname)
              if call_def and (call_def != out.get("definition")):
                  # it may never be the case that call def and definition differ,
                  # but don't include the same signature twice
                  out["call_def"] = call_def
              call_ds = getdoc(obj.__call__)
              # Skip Python's auto-generated docstrings
              if call_ds == _func_call_docstring:
                  call_ds = None
              if call_ds:
                  out["call_docstring"] = call_ds
  
      return object_info(**out)
  
imports: from dataclasses import dataclass
  from inspect import signature
  from textwrap import dedent
  import ast
  import html
  import inspect
  import io
  import linecache
  import os
  import sys
  import types
  import warnings
  from typing import Any, Optional, Dict, Union, List, Tuple
  from typing import TypeAlias
  from IPython.core import page
  from IPython.lib.pretty import pretty
  from IPython.testing.skipdoctest import skip_doctest
  from IPython.utils import PyColorize
  from IPython.utils import openpy
  from IPython.utils.dir2 import safe_hasattr
  from IPython.utils.path import compress_user
  from IPython.utils.text import indent
  from IPython.utils.wildcard import list_namespace
  from IPython.utils.wildcard import typestr2type
  from IPython.utils.coloransi import TermColors, ColorScheme, ColorSchemeTable
  from IPython.utils.py3compat import cast_unicode
  from IPython.utils.colorable import Colorable
  from IPython.utils.decorators import undoc
  from pygments import highlight
  from pygments.lexers import PythonLexer
  from pygments.formatters import HtmlFormatter
label_desc: Use image node_id 17 for calling the Inspector obj's underlying member method code with example usage: obj.info(obj, oname, info, detail_level) and returns: object_info