argparse optional argument before positional argument
Question: I was wondering if it is possible to have a positional argument follow an
argument with an optional parameter. Ideally the last argument entered into
the command line would always apply toward 'testname'.

    
    
    import argparse
    parser = argparse.ArgumentParser(description='TAF')
    parser.add_argument('-r','--release',nargs='?',dest='release',default='trunk')
    parser.add_argument('testname',nargs='+')
    args = parser.parse_args()
    

I would like both of these calls to have smoketest apply to testname, but the
second one results in an error.

    
    
    >> python TAF.py -r 1.0 smoketest
    >> python TAF.py -r smoketest
    TAF.py: error: too few arguments
    

I realize that moving the positional argument to the front would result in the
correct behavior of the optional parameter, however this is not quite the
format I am looking for. The choices flag looks like an attractive
alternative, however it throws an error instead of ignoring the unmatched
item.

EDIT: I've found a hacky way around this. If anyone has a nicer solution I
would appreciate it.

    
    
    import argparse
    parser = argparse.ArgumentParser(description='TAF')
    parser.add_argument('-r','--release',nargs='?',dest='release',default='trunk')
    parser.add_argument('testname',nargs=argparse.REMAINDER)
    args = parser.parse_args()
    
    if not args.testname:
        args.testname = args.release
        args.release = ''
    


Answer: As stated in the
[documentation](http://docs.python.org/dev/library/argparse.html#nargs):

> `'?'`. One argument will be consumed from the command line if possible, and
> produced as a single item. If no command-line argument is present, the value
> from default will be produced. Note that for optional arguments, there is an
> additional case - the option string is present but not followed by a
> command-line argument. In this case the value from const will be produced.

So, the behaviour you want is not obtainable using `'?'`. Probably you could
write some hack using `argparse.Action` and meddling with the previous
results.(1)

I think the better solution is to split the functionality of that option. Make
it an option that requires an argument(but the option itself is optional) and
add an option without argument that sets the release to `'trunk'`. In this way
you can obtain the same results without any hack. Also I think the interface
is simpler.

In your example:

    
    
    python TAF.py -r smoketest
    

It's quite clear that `smoketest` will be interpreted as an argument to `-r`.
At least following unix conventions. If you want to keep `nargs='?'` then the
user _must_ use `--`:

    
    
    $ python TAF.py -r -- sometest
    Namespace(release=None, testname=['sometest'])   #parsed result
    

(1) An idea on how to do this: check if the option has an argument. If it has
one check if it is a valid test name. If so put into by hand into `testname`
and set `release` to the default value. You'll also have to set a "flag" that
tells you that this thing happened.

Now, before parsing `sys.argv` you must redirect `sys.stderr`. When doing the
parsing you must catch `SystemExit`, check the `stderr` and see if the error
was "too few arguments", check if the flag was set, if so ignore the error and
continue running, otherwise you should reprint to the original `stderr` the
error message and exit.

This approach does not look robust, and it's probably buggy.

