Python code to redirect stdin and stdout to a shell script
Question: I am trying to write a program that reads from a file and writes to a new file
using the command line. I am using the CommandLine class and using ArgParse to
accept different args as well as the file names for input and output. I am
trying to redirect stdin and stdout to these files. However, I keep getting an
error that I put at the bottom of the code below. Am I inputting the arguments
to the command line incorrectly, or is something else going on? All of my
files are in the same folder.

    
    
    class CommandLine() :
    '''
    Handle the command line, usage and help requests.
    
    CommandLine uses argparse, now standard in 2.7 and beyond. 
    it implements a standard command line argument parser with various argument options,
    a standard usage and help, and an error termination mechanism do-usage_and_die.
    
    attributes:
    all arguments received from the commandline using .add_argument will be
    avalable within the .args attribute of object instantiated from CommandLine.
    For example, if myCommandLine is an object of the class, and requiredbool was
    set as an option using add_argument, then myCommandLine.args.requiredbool will
    name that option.
    
    '''
    
    def __init__(self, inOpts=None):
        '''
        CommandLine constructor.
        Implements a parser to interpret the command line argv string using argparse.
        '''
    
        import argparse
        self.parser = argparse.ArgumentParser(description = 'Program prolog - a brief description of what this thing does', 
                                             epilog = 'Program epilog - some other stuff you feel compelled to say', 
                                             add_help = True, #default is True 
                                             prefix_chars = '-', 
                                             usage = '%(prog)s [options] -option1[default] <input >output'
                                             )
        self.parser.add_argument('inFile', action = 'store', help='input file name')
        self.parser.add_argument('outFile', action = 'store', help='output file name')
        self.parser.add_argument('-lG', '--longestGene', action = 'store', nargs='?', const=True, default=False, help='longest Gene in an ORF')
        self.parser.add_argument('-mG', '--minGene', type=int, choices= (0, 100, 200, 300, 500, 1000), action = 'store', help='minimum Gene length')
        self.parser.add_argument('-s', '--start', action = 'append', nargs='?', help='start Codons') #allows multiple list options
        self.parser.add_argument('-st', '--stop', action = 'append', nargs='?', help='stop Codons') #allows multiple list options
        self.parser.add_argument('-v', '--version', action='version', version='%(prog)s 0.1')  
        if inOpts is None :
            self.args = self.parser.parse_args()
        else :
            self.args = self.parser.parse_args(inOpts)
    
    C:\Users\Zach\Documents\UCSC\BME 160\Lab 5>python findORFsCmdLine.py --    minGene=3
    00 --longestGene --start=ATG --stop=TAG --stop=TGA --stop=TAA <tass2.fa     >result.
    txt
    usage: findORFsCmdLine.py [options] -option1[default] <input >output
    findORFsCmdLine.py: error: the following arguments are required: inFile,     outFile
    


Answer: The error tells you that you did not provide `inFile` and `outFile`. This
seems confusing because you did indeed provide `<tass2.fa` and `>result.txt`
on the command line.

On the command line `<` and `>` have special meaning. `<tass2.fa` is handled
by `bash` (or whichever shell you use) and it opens the file `tass2.fa` and
sends the contents to your program over `stdin`. It then removes that from the
list of command line arguments because `bash` has already taken care of it.

A similar thing happens with `>result.txt` where any output from your file
that normally goes to `stdout` such as print calls will be written to that
file. Again `bash` handles this so your program never gets the argument from
the command line.

To make sure the filenames go to your program you need to remove the `<` and
`>` symbols.

* * *

In addition to that, the way you are call `add_argument` for `inFile` and
`outFile` is not correct. Using `action='store'` simply stores the value of
the argument under the given name. This is the default action so doing that is
redundant.

You need to tell `add_argument` that these are file types. Then you can use
these as files and read and write as you desire.

    
    
    parser.add_argument('inFile', type=argparse.FileType('r'))
    parser.add_argument('outFile', type=argparse.FileType('w'))
    

If you wish to allow these arguments to be optional and use `stdin` and
`stdout` automatically if they do not supply a filename then you can do this:

    
    
    parser.add_argument('inFile', type=argparse.FileType('r'),
        nargs='?', default=sys.stdin)
    parser.add_argument('outFile', type=argparse.FileType('w'),
        nargs='?', default=sys.stdout)
    

* * *

You say you are writing a program that reads from a file and writes to a new
file using the command line and go on to say that you are trying to redirect
these files to stdin and stdout.

If it is really your intention to redirect the input and output files using
the shell with the `>` and `<` operators, then you do not need to call
`add_argument` with `outFile` at all. Just let the shell handle it. Remove
that line from your program and use `print` or similar to send your content to
`stdout` and that file will be created. You will still need the call
`add_argument('inFile', ...`.

