docs: def MI_parse_args(self, args, ingore_index2=False, allow_new=False):
      '''
      Parse the arguments for indexing in MIDict.
  
      Full syntax: ``d[index1:key, index2]``.
  
      ``index2`` can be flexible indexing (int, list, slice etc.) as in ``IndexDict``.
  
      Short syntax:
  
      * d[key] <==> d[key,] <==> d[first_index:key, all_indice_except_first]
      * d[:key] <==> d[:key,] <==> d[None:key] <==> d[last_index:key, all_indice_except_last]
      * d[key, index2] <==> d[first_index:key, index2] # this is valid
        # only when index2 is a list or slice object
      * d[index1:key, index2_1, index2_2, ...] <==> d[index1:key, (index2_1, index2_2, ...)]
  
      '''
      empty = len(self.indices) == 0
      if empty and not allow_new:
          raise KeyError('Item not found (dictionary is empty): %s' % (args,))
  
      names = force_list(self.indices.keys())
  
      Nargs = len(args) if isinstance(args, tuple) else 1
  
      _default = object()
      index1 = index2 = _default
  
      if isinstance(args, tuple):
          # easy handle of default logic (use continue/break as shortcut)
          for _ in (1,):
              if ingore_index2:
                  continue
  
              if isinstance(args[0], slice):
                  index1, key = args[0].start, args[0].stop
  
                  if Nargs == 2:
                      index2 = args[1]
                  elif Nargs > 2:
                      index2 = args[1:]
                  break
  
              # args[0] is not a slice
              if Nargs > 1 and isinstance(args[1], (list, slice)):
                  if Nargs == 2:
                      key, index2 = args
                      break
                  else:
                      raise KeyError('No arguments allowed after index2, found: %s' % (args[2:],))
          else:
              key = args
  
      elif isinstance(args, slice):
          index1, key = args.start, args.stop
  
      else:
          key = args
  
      if empty: # allow_new is True
          index1_last = False
  
          exist_names = []  # list of names already passed in as arguments
          if index1 is not _default:
              if index1 is None: # slice syntax d[:key]
                  index1_last = True
                  index1 = _default
              elif isinstance(index1, int):
                  raise TypeError('Index1 can not be int when dictionary '
                                  'is empty: %s' % (index1,))
              else:
                  MI_check_index_name(index1)
                  exist_names.append(index1)
          if index2 is not _default:
              if isinstance(index2, (tuple, list)):
                  map(MI_check_index_name, index2)
                  exist_names.extend(index2)
              elif isinstance(index2, (int, slice)):
                  raise TypeError('Index2 can not be int or slice when '
                                  'dictionary is empty: %s' % (index2,))
              else:
                  MI_check_index_name(index2)
                  exist_names.append(index2)
  
          # auto generate index names and avoid conficts with existing names
          if index1 is _default:
              if index1_last:
                  if len(exist_names) > 1: # index2 is specified
                      name1 = 'index_%s' % (len(exist_names) + 1)
                  else:
                      name1 = 'index_2'
              else:
                  name1 = 'index_1'
              index1 = get_unique_name(name1, exist_names)
              exist_names.append(index1)
  
          if index2 is _default:
              name2 = 'index_1' if index1_last else 'index_2'
              index2 = get_unique_name(name2, exist_names)
  
          return index1, key, index2, index1_last
  
      # not empty:
  
      if index1 is _default:  # not specified
          index1 = 0
      elif index1 is None:  # slice syntax d[:key]
          index1 = -1
  
      # index1 is always returned as an int
      index1 = _key_to_index_single(names, index1)
  
      try:
          item = MI_get_item(self, key, index1)
      except KeyError:
          if allow_new:  # new key for setitem; item_d = None
              item = None
          else:
              raise KeyError('Key not found in index #%s "%s": %s' %
                              (index1, names[index1], key))
  
      if ingore_index2:  # used by delitem
          return item
  
      if index2 is _default:  # not specified
          # index2 defaults to all indices except index1
          if len(names) == 1:
              index2 = 0  # index2 defaults to the only one index
          else:
              index2 = force_list(range(len(names)))
              index2.remove(index1)
              if len(index2) == 1:  # single index
                  index2 = index2[0]
      else:
          # index2 is always returned as int or list of int
          index2 = _key_to_index(names, index2)
  
      if item is None:  # allow_new. item and value are None
          return index1, key, index2, None, None
  
  #    try:
  #        value = mget_list(item, index2)
  #    except IndexError:
  #        raise KeyError('Index not found: %s' % (index2,))
  
      # no need to try since index2 is always returned as int or list of int
      value = mget_list(item, index2)
      return index1, key, index2, item, value