docs: def _add_args(parser, args, required):
      """
      Add new arguments to an ArgumentParser.
  
      :param argparse.ArgumentParser parser: instance to update with new arguments
      :param Iterable[str] args: Collection of names of arguments to add.
      :param Iterable[str] required: Collection of arguments to designate as required
      :return argparse.ArgumentParser: Updated ArgumentParser
      """
  
      import copy
  
      required = required or []
  
      # Determine the default pipeline config file.
      pipeline_script = os.path.basename(sys.argv[0])
      default_config, _ = os.path.splitext(pipeline_script)
      default_config += ".yaml"
  
      # Define the arguments.
      argument_data = {
          "recover":
              ("-R", {"action": "store_true",
                      "help": "Overwrite locks to recover from previous failed run"}),
          "new-start":
              ("-N", {"action": "store_true",
                      "help": "Overwrite all results to start a fresh run"}),
          "dirty":
              ("-D", {"action": "store_true",
                      "help": "Don't auto-delete intermediate files"}),
          "force-follow":
              ("-F", {"action": "store_true",
                      "help": "Always run 'follow' commands"}),
          "start-point":
              {"help": "Name of pipeline stage at which to begin"},
          "stop-before":
              {"help": "Name of pipeline stage at which to stop "
                       "(exclusive, i.e. not run)"},
          "stop-after":
              {"help": "Name of pipeline stage at which to stop "
                       "(inclusive, i.e. run)"},
          "config":
              ("-C", {"dest": "config_file", "metavar": "CONFIG_FILE",
                      "default": default_config,
                      "help": "Pipeline configuration file (YAML). "
                              "Relative paths are with respect to the "
                              "pipeline script."}),
          "sample-name":
              ("-S", {"metavar": "SAMPLE_NAME",
                      "help": "Name for sample to run"}),
          "output-parent":
              ("-O", {"metavar": "PARENT_OUTPUT_FOLDER",
                      "help": "Parent output directory of project"}),
          "cores":
              ("-P", {"type": int, "default": 1, "metavar": "NUMBER_OF_CORES",
                      "help": "Number of cores for parallelized processes"}),
          "mem":
              ("-M", {"default": "4000", "metavar": "MEMORY_LIMIT",
                      "help": "Memory limit for processes accepting such. "
                      "Default units are megabytes unless specified "
                      "using the suffix [K|M|G|T]."}),
          "input":
              ("-I", {"nargs": "+", "metavar": "INPUT_FILES",
                      "help": "One or more primary input files"}),
          "input2":
              ("-I2", {"nargs": "*", "metavar": "INPUT_FILES2",
                       "help": "Secondary input files, such as read2"}),
          "genome":
              ("-G", {"dest": "genome_assembly",
                      "help": "Identifier for genome assembly"}),
          "single-or-paired":
              ("-Q", {"default": "single",
                      "help": "Single- or paired-end sequencing protocol"})
      }
  
      if len(required) > 0:
          required_named = parser.add_argument_group('required named arguments')
  
      # Configure the parser for each argument.
      for arg in args:
          try:
              argdata = copy.deepcopy(argument_data[arg])
          except KeyError:
              print("Skipping undefined pypiper argument: '{}'".format(arg))
              continue
          if isinstance(argdata, dict):
              short_opt = None
          else:
              try:
                  short_opt, argdata = argdata
              except ValueError:
                  raise TypeError(
                      "Option name must map to dict or two-tuple (short "
                      "name and dict) of argument command-line argument "
                      "specification data.")
  
          argdata["required"] = arg in required
  
          long_opt = "--{}".format(arg)
          opts = (short_opt, long_opt) if short_opt else (long_opt, )
          if arg in required:
              required_named.add_argument(*opts, **argdata)
          else:
              parser.add_argument(*opts, **argdata)
  
      return parser