title: How can I input specific arguments to argparse?
body: <p>I found this code on the web that can parse a specific type of text file as below:</p>
  
  <pre><code># RELION; version 3.0
  
  data_images
  
  loop_ 
  _rlnCoordinateX #1 
  _rlnCoordinateY #2 
  _rlnHelicalTubeID #3 
  _rlnAngleTiltPrior #4 
  _rlnAnglePsiPrior #5 
  _rlnHelicalTrackLength #6 
  _rlnAnglePsiFlipRatio #7 
  _rlnImageName #8 
  _rlnMicrographName #9 
  _rlnMagnification #10 
  _rlnDetectorPixelSize #11 
  _rlnCtfMaxResolution #12 
  _rlnCtfFigureOfMerit #13 
  _rlnVoltage #14 
  _rlnDefocusU #15 
  _rlnDefocusV #16 
  _rlnDefocusAngle #17 
  _rlnSphericalAberration #18 
  _rlnCtfBfactor #19 
  _rlnCtfScalefactor #20 
  _rlnPhaseShift #21 
  _rlnAmplitudeContrast #22 
  _rlnOriginX #23 
  _rlnOriginY #24 
   3041.398896  3692.419723            1    90.000000    63.534898     0.000000     0.500000 000001@Extract/job011/Movies/Microtubules_02563.mrcs MotionCorr/job003/Movies/Microtubules_02563.mrc 10000.000000     5.480000     5.830000     0.124704   300.000000  7457.819824  6964.129883    33.520000     2.700000     0.000000     1.000000     0.000000     0.100000     0.031176 2.475269e-32 
   3068.235643  3638.511334            1    90.000000    63.534898    60.218978     0.500000 000002@Extract/job011/Movies/Microtubules_02563.mrcs MotionCorr/job003/Movies/Microtubules_02563.mrc 10000.000000     5.480000     5.830000     0.124704   300.000000  7457.819824  6964.129883    33.520000     2.700000     0.000000     1.000000     0.000000     0.100000     0.000000     0.000000 
   3095.072390  3584.602946            1    90.000000    63.534898   120.437956     0.500000 000003@Extract/job011/Movies/Microtubules_02563.mrcs MotionCorr/job003/Movies/Microtubules_02563.mrc 10000.000000     5.480000     5.830000     0.124704   300.000000  7457.819824  6964.129883    33.520000     2.700000     0.000000     1.000000     0.000000     0.100000     0.000000     0.000000 
   3121.909136  3530.694558            1    90.000000    63.534898   180.656934     0.500000 000004@Extract/job011/Movies/Microtubules_02563.mrcs MotionCorr/job003/Movies/Microtubules_02563.mrc 10000.000000     5.480000     5.830000     0.124704   300.000000  7457.819824  6964.129883    33.520000     2.700000     0.000000     1.000000     0.000000     0.100000     0.000000     0.000000 
  </code></pre>
  
  <p>The code (two classes and a few lines at the end to call them):</p>
  
  <pre><code>import os
  import sys
  import argparse
  from collections import OrderedDict, namedtuple
  
  
  class Column:
      def __init__(self, name, type=None):
          self._name = name
          # Get the type from the LABELS dict, assume str by default
          self._type = type
  
      def __str__(self):
          return self._name
  
      def __cmp__(self, other):
          return self._name == str(other)
  
  
  class Table:
      """
      Class to hold and manipulate tabular data for EM processing programs.
      """
      def __init__(self, **kwargs):
          self.clear()
  
          if 'fileName' in kwargs:
              if 'columns' in kwargs:
                  raise Exception("Please provide either 'columns' or 'fileName',"
                                  " but not both.")
              fileName = kwargs.get('fileName')
              tableName = kwargs.get('tableName', None)
              self.read(fileName, tableName)
          elif 'columns' in kwargs:
              self._createColums(kwargs['columns'])
  
      def clear(self):
          self.Row = None
          self._columns = OrderedDict()
          self._rows = []
  
      def clearRows(self):
          """ Remove all the rows from the table, but keep its columns. """
          self._rows = []
  
      def addRow(self, *args, **kwargs):
          self._rows.append(self.Row(*args, **kwargs))
  
      def readStar(self, inputFile, tableName=None):
          """
          :param inputFile: Provide the input file from where to read the data.
              The file pointer will be moved until the last data line of the
              requested table.
          :return:
          """
          self.clear()
          dataStr = 'data_%s' % (tableName or '')
  
          self._findDataLine(inputFile, dataStr)
  
          # Find first column line and parse all columns
          line, foundLoop = self._findLabelLine(inputFile)
          colNames = []
          values = []
  
          while line.startswith('_'):
              parts = line.split()
              colNames.append(parts[0][1:])
              if not foundLoop:
                  values.append(parts[1])
              line = inputFile.readline().strip()
  
          self._createColums(colNames)
  
          if not foundLoop:
              self.addRow(*values)
          else:
              # Parse all data lines
              while line:
                  self.addRow(*line.split())
                  line = inputFile.readline().strip()
  
      def read(self, fileName, tableName=None):
          with open(fileName) as f:
              self.readStar(f, tableName)
  
      def writeStar(self, outputFile, tableName=None, singleRow=False):
          """
          Write a Table in Star format to the given file.
          :param outputFile: File handler that should be already opened and
              in the position to write.
          :param tableName: The name of the table to write.
          :param singleRow: If True, don't write loop_, just label - value pairs.
          """
          outputFile.write("\ndata_%s\n\n" % (tableName or ''))
  
          if self.size() == 0:
              return
  
          if singleRow:
              m = max([len(c) for c in self._columns.keys()]) + 5
              lineFormat = "_{:&lt;%d} {:&gt;10}\n" % m
              row = self._rows[0]
              for col, value in row._asdict().iteritems():
                  outputFile.write(lineFormat.format(col, value))
              outputFile.write('\n\n')
              return
  
          outputFile.write("loop_\n")
  
          # Write column names
          for col in self._columns.values():
              outputFile.write("_%s \n" % col)
  
          # Take a hint for the columns width from the first row
  
          widths = [len(str(v)) for v in self._rows[0]]
          # Check middle and last row, just in case ;)
          for index in [len(self)//2, -1]:
              for i, v in enumerate(self._rows[index]):
                  w = len(str(v))
                  if w &gt; widths[i]:
                      widths[i] = w
  
          lineFormat = " ".join("{:&gt;%d} " % (w + 1) for w in widths)
  
          # Write data rows
          for row in self._rows:
              outputFile.write(lineFormat.format(*row))
              outputFile.write('\n')
  
          outputFile.write('\n')
  
      def write(self, output_star, tableName=None):
          with open(output_star, 'w') as output_file:
              self.writeStar(output_file, tableName)
  
      def printStar(self, tableName=None):
          self.writeStar(sys.stdout, tableName)
  
      def size(self):
          return len(self._rows)
  
      def getColumns(self):
          return self._columns.values()
  
      def getColumnValues(self, colName):
          """
          Return the values of a given column
          :param colName: The name of an existing column to retrieve values.
          :return: A list with all values of that column.
          """
          if colName not in self._columns:
              raise Exception("Not existing column: %s" % colName)
          return [getattr(row, colName) for row in self._rows]
  
      def __len__(self):
          return self.size()
  
      def __iter__(self):
          for item in self._rows:
              yield item
  
      def __getitem__(self, item):
          return self._rows[item]
  
      def __setitem__(self, key, value):
          self._rows[key] = value
  
      # --------- Internal implementation methods ------------------------
  
      def _addColumn(self, nameOrTuple):
          """
          :param nameOrTuple: This parameter should be either a string or
              a tuple (string, type).
          """
          if isinstance(nameOrTuple, str):
              col = Column(nameOrTuple)
          elif isinstance(nameOrTuple, tuple):
              col = Column(nameOrTuple[0], nameOrTuple[1])
          else:
              raise Exception("Invalid input as column, "
                              "should be either string or tuple.")
          self._columns[str(col)] = col
  
      def _createColums(self, columnList):
          self.clear()
          for col in columnList:
              self._addColumn(col)
          self._createRowClass()
  
      def _createRowClass(self):
          self.Row = namedtuple('Row', [str(c) for c in self._columns])
  
      def _findDataLine(self, inputFile, dataStr):
          """ Raise an exception if the desired data string is not found.
          Move the line pointer after the desired line if found.
          """
          line = inputFile.readline()
          while line:
              if line.startswith(dataStr):
                  return line
              line = inputFile.readline()
  
          raise Exception("%s block was not found")
  
      def _findLabelLine(self, inputFile):
          line = ''
          foundLoop = False
  
          l = inputFile.readline()
          while l:
              if l.startswith('_'):
                  line = l
                  break
              elif l.startswith('loop_'):
                  foundLoop = True
              l = inputFile.readline()
  
          return line.strip(), foundLoop
  
  
  
  
  if __name__ == '__main__':
  
      parser = argparse.ArgumentParser(
          description="Script to manipulate metadata files.")
  
      add = parser.add_argument  # shortcut
      add("input", help="Input metadata filename. ", nargs='?', default="")
      add("output",
          help="Output metadata filename, if no provided, print to stdout. ",
          nargs='?', default="")
  
      add("-l", "--limit", type=int, default=0,
          help="Limit the number of rows processed, useful for testing. ")
  
      #add("-v", "--verbosity", action="count", default=0)
  
      args = parser.parse_args()
  
      if '@' in args.input:
          tableName, fileName = args.input.split('@')
      else:
          tableName, fileName = None, args.input
  
      if not os.path.exists(fileName):
          raise Exception("Input file '%s' does not exists. " % fileName)
  
      tableIn = Table(fileName=fileName, tableName=tableName)
  
  
  
  
      # Create another table with same columns
      tableOut = Table(columns=[str(c) for c in tableIn.getColumns()])
  
      limit = args.limit
  
      for i, row in enumerate(tableIn):
          if limit &gt; 0 and i == limit:
              break
  
          tableOut.addRow(*row)
  
      if args.output:
          tableOut.write(args.output, tableName)
      else:
          tableOut.printStar(tableName)
  </code></pre>
  
  <p>The problem and a few questions: I want to use this code to change the value of a certain column and rewrite the above text file (P.s. this is a trivial python script, but I want to accomplish this task using the object oriented code above).</p>
  
  <p>I also have a few questions about this code. The only argument I provide to this script is the text file, but I see this line here if args.output:tableOut.write(args.output, tableName) which implies that other arguments are possible, which would result in rewriting the file, instead of just printing it as the code would execute if you would just run it on the above text file. Also if '@' in args.input:, what is the purpose of this conditional, why would I input @ in the arguments for this script?! (the code doesn't come with documentation) </p>
  
  <p>My attempt at the solution (since I don't practice object oriented python a lot): I thought perhaps I can add this function to the Table class and then add the following line to the final script to change a certain column value to the input values from the user.</p>
  
  <pre><code>    def _changeColumnsValue(self, colName, colValue):
          if colName not in self._columns:
              raise Exception("Not existing column: %s" % colName)
          for row in self._rows:
              setattr(row, colName, colValue) 
  
  
      change_value  = input('Which column would you like to change, and to what value? Example input: _rlnVoltage 200')
      tableOut._changeColumnsValue(change_value.split()[0], change_value.split()[1])
  </code></pre>