docs: def dictinfo(dict_):
      """
      dictinfo
  
      In depth debugging info
  
      Args:
          dict_ (dict):
  
      Returns:
          str
  
      Example:
          >>> # DISABLE_DOCTEST
          >>> from utool.util_dict import *  # NOQA
          >>> dict_ = {}
          >>> result = dictinfo(dict_)
          >>> print(result)
      """
      import utool as ut
      if not isinstance(dict_, dict):
          return 'expected dict got %r' % type(dict_)
  
      keys = list(dict_.keys())
      vals = list(dict_.values())
      num_keys  = len(keys)
      key_types = list(set(map(type, keys)))
      val_types = list(set(map(type, vals)))
  
      fmtstr_ = '\n' + ut.unindent('''
      * num_keys  = {num_keys}
      * key_types = {key_types}
      * val_types = {val_types}
      '''.strip('\n'))
  
      if len(val_types) == 1:
          if val_types[0] == np.ndarray:
              # each key holds an ndarray
              val_shape_stats = ut.get_stats(set(map(np.shape, vals)), axis=0)
              val_shape_stats_str = ut.repr4(val_shape_stats, strvals=True, newlines=False)
              val_dtypes = list(set([val.dtype for val in vals]))
              fmtstr_ += ut.unindent('''
              * val_shape_stats = {val_shape_stats_str}
              * val_dtypes = {val_dtypes}
              '''.strip('\n'))
          elif val_types[0] == list:
              # each key holds a list
              val_len_stats =  ut.get_stats(set(map(len, vals)))
              val_len_stats_str = ut.repr4(val_len_stats, strvals=True, newlines=False)
              depth = ut.list_depth(vals)
              deep_val_types = list(set(ut.list_deep_types(vals)))
              fmtstr_ += ut.unindent('''
              * list_depth = {depth}
              * val_len_stats = {val_len_stats_str}
              * deep_types = {deep_val_types}
              '''.strip('\n'))
              if len(deep_val_types) == 1:
                  if deep_val_types[0] == np.ndarray:
                      deep_val_dtypes = list(set([val.dtype for val in vals]))
                      fmtstr_ += ut.unindent('''
                      * deep_val_dtypes = {deep_val_dtypes}
                      ''').strip('\n')
          elif val_types[0] in [np.uint8, np.int8, np.int32, np.int64, np.float16, np.float32, np.float64]:
              # each key holds a scalar
              val_stats = ut.get_stats(vals)
              fmtstr_ += ut.unindent('''
              * val_stats = {val_stats}
              ''').strip('\n')
  
      fmtstr = fmtstr_.format(**locals())
      return ut.indent(fmtstr)