docs: def to_argv_schema(data, arg_names=None, arg_abbrevs=None, filters=None, defaults=None):
      '''
      to_argv_schema(instructions) yields a valid tuple of CommandLineParser instructions for the
        given instructions tuple; by itself, this will only return the instructions as they are, but
        optional arguments (below) will override the values in the instructions if provided.
      to_argv_schema(plan) yields a valid tuple of CommandLineParser instructions for the given plan
        object.
  
      These schema returned by this function will parse a command-line list (sys.argv) for parameters
      either listed in the instructions (see help(CommandLineParser)) or the afferent parameters of
      the plan. Generally, this should be called by the argv_parse() function and not directly.
  
      If a plan is given as the first argument, then the following rules are used to determine how
      arguments are parsed:
        * An argument that begins with -- (e.g., --quux-factor=10) is checked for a matching
          plan parameter; the argument name "quux-factor" will match either a parameter called
          "quux-factor" or "quux_factor" (dashes in command-line arguments are auto-translated
          into underscores).
        * If "quux_factor" is a parameter to the plan and is the only parameter that starts with a
          'q', then -q10 or -q 10 are both equivalent to --quux-factor=10. If other parameters
          also start with a 'q' then neither "quux_factor" or the other parameter(s) will be
          matched with the -q flag unless it is specified explicitly via the arg_abbrevs option.
        * Argument values are parsed using Python's ast.literal_eval(); if this raises an
          exception then the value is left as a string.
        * If an argument or flag is provided without an argument (e.g. "--quuxztize" or "-q") then
          it is interpreted as a boolean flag and is given the value True.
        * Arguments that come after the flag "--" are never processed.
  
      The following options may be given:
        * arg_names (default: None) may be a dictionary that specifies explicity command-line
          argument names for the plan parameters; plan parameters should be keys and the argument
          names should be values. Any parameter not listed in this option will be interpreted
          according to the above rules. If a parameter is mapped to None then it will not be
          filled from the command-line arguments.
        * arg_abbrevs (default:None) may be a dictionary that is handled identically to that of
          arg_names except that its values must be single letters, which are used for the
          abbreviated flag names.
        * defaults (default: None) may specify the default values for the plan parameters; this
          dictionary overrides the default values of the plan itself.
      '''
      if is_plan(data):
          # First we must convert it to a valid instruction list
          (plan, data) = (data, {})
          # we go through the afferent parameters...
          for aff in plan.afferents:
              # these are provided by the parsing mechanism and shouldn't be processed
              if aff in ['argv', 'argv_parsed', 'stdout', 'stderr', 'stdin']: continue
              # we ignore defaults for now
              data[aff] = (None, aff.replace('_', '-'), aff)
          # and let's try to guess at abbreviation names
          entries = sorted(data.keys())
          n = len(entries)
          for (ii,entry) in enumerate(entries):
              if ii > 0   and entry[0] == entries[ii-1][0]: continue
              if ii < n-1 and entry[0] == entries[ii+1][0]: continue
              r = data[entry]
              data[entry] = (entry[0], r[1], entry, r[3]) if len(r) == 4 else (entry[0], r[1], entry)
          # now go through and fix defaults...
          for (entry,dflt) in six.iteritems(plan.defaults):
              if entry not in data: continue
              r = data[entry]
              data[entry] = (r[0], r[1], r[2], dflt)
      elif arg_names is None and arg_abbrevs is None and defaults is None:
          # return the same object if there are no changes to a schema
          return data
      else:
          data = {r[2]:r for r in data}
      # Now we go through and make updates based on the optional arguments
      if arg_names is None: arg_names = {}
      for (entry,arg_name) in six.iteritems(arg_names):
          if entry not in data: continue
          r = data[entry]
          data[entry] = (r[0], arg_name, entry) if len(r) == 3 else (r[0], arg_name, entry, r[3])
      if arg_abbrevs is None: arg_abbrevs = {}
      for (entry,arg_abbrev) in six.iteritems(arg_abbrevs):
          if entry not in data: continue
          r = data[entry]
          data[entry] = (arg_abbrev, r[1], entry) if len(r) == 3 else (arg_abbrev, r[1], entry, r[3])
      if defaults is None: defaults = {}
      for (entry,dflt) in six.iteritems(defaults):
          if entry not in data: continue
          r = data[entry]
          data[entry] = (r[0], r[1], entry, dflt)
      # return the list-ified version of this
      return [tuple(row) for row in six.itervalues(data)]