argparse limitations

Benoist Laurent benoist at ibpc.fr
Tue Jul 31 14:51:13 CEST 2012


Le Jul 31, 2012 à 1:45 PM, Oscar Benjamin a écrit :

> 
> 
> On 31 July 2012 12:03, Benoist Laurent <benoist at ibpc.fr> wrote:
> Finally.
> 
> The code I proposed doesn't work in this case: if you add any positional argument to one of the subparsers, then the parsing doesn't work anymore.
> The reason seems to be that argparse thinks the last argument of the first parser is the last but one argument.
> Hence, if a subparser takes some arguments, it fails.
> 
> Example: if the "-n" argument of the foo parser is set mandatory (so becomes "n" instead of "-n")
> 
> python toto.py foo.txt bar.txt foo 10
> usage: toto.py [-h] [fname [fname ...]] command ...
> toto.py: error: argument command: invalid choice: '10' (choose from 'foo', 'bar')
> 
> What about:
> 
> $ python toto.py foo.txt bar.txt foo -n 10
> 
> Note that contrary to what you said above, your program does not work like a "standard unix tool". A standard command line program to do what you want would normally look like

You're right.
But then, using argparse, I would have to add the same argument to all my subparsers since argparse does the work sequentially: once it recognized the start of a subparser, everything that follows have to be an argument of this subparser.
Hence, arguments (therefore options) from the main parser are not recognized anymore.

> 
> $ python toto.py foo -n 10 foo.txt bar.txt

Same remark as above: if I want the command line to look like this, then I would have setup each subparser with all the main program options.


> 
> or perhaps
> 
> $ python toto.py foo foo.txt bar.txt -n 10
> 
> so that the algorithm for differentiating the command 'foo' from the filenames is well defined. How do you propose that your user enters a filename 'foo'?

Well I guess it is a intrinsec limitation: I think it's quite natural that the user can't enter a filename named as a command.


> 
> Oscar.
> 
> 
> 
> Any solution?
> 
> Cheers,
> Ben
> 
> 
> 
> Le Jul 31, 2012 à 12:37 PM, Benoist Laurent a écrit :
> 
>> Really sorry about that.
>> 
>> So, for the community, below is the full code for a tool that behaves like a Unix standard tool.
>> It takes in argument the files to process and a command.
>> 
>> """Just to setup a command-line parser that acts just like a unix
>> standard tool."""
>> 
>> import argparse
>> import sys
>> 
>> def define_options():
>>     parser = argparse.ArgumentParser()
>>     parser.add_argument("fname", help="input file", nargs="*")
>> 
>>     # create subparsers
>>     subparsers = parser.add_subparsers(dest="cmd", metavar="command")
>> 
>>     # create the parser for the "foo" command
>>     get_parser = subparsers.add_parser("foo", help="foo help")
>>     get_parser.add_argument("-n", help="number of foo to print", 
>>                             type=int, default=10)
>> 
>>     # create the parser for the "bar" command
>>     sum_parser = subparsers.add_parser("bar", help="bar help")
>>     
>>     return parser
>> 
>> 
>> if __name__ == '__main__':
>>     args = define_options().parse_args()
>> 
>>     if not args.fname:
>>         content = sys.stdin.read()
>>         # do something
>>     else:
>>         for fname in args.fname:
>>             with(open(fname, "rt")) as f:
>>                 content = f.read()
>>             # do somet
>> 
>> 
>> Benoist
>> 
>> 
>> 
>> Le Jul 31, 2012 à 11:55 AM, Oscar Benjamin a écrit :
>> 
>>> 
>>> On Jul 31, 2012 10:32 AM, "Benoist Laurent" <benoist at ibpc.fr> wrote:
>>> >
>>> > Well sorry about that but it seems I was wrong.
>>> > It was Friday evening and I guess I've not been careful.
>>> >
>>> > Actually when you specify nargs="?",  the doc says "One argument will be consumed from the command line if possible, and produced as a single item".
>>> > So you can't pass several arguments to the program.
>>> 
>>> Right below that in the docs it explains about using nargs='*' and nargs='+'. One of those will do what you want.
>>> 
>>> Oscar.
>>> 
>>> >
>>> > So, to rephrase the question, how can I get a argument parser that parses the command-line just as Unix grep would do?
>>> > i.e.
>>> >
>>> > $ echo 42 > foo.txt
>>> > $ echo 172 >> foo.txt
>>> > $ cp foo.txt bar.txt
>>> > $
>>> > $ grep 42 foo.txt
>>> > 42
>>> > $ grep 42 foo.txt bar.txt
>>> > foo.txt:42
>>> > bar.txt:42
>>> > $ cat foo.txt | grep 42
>>> > 42
>>> > $ grep -c 42 foo.txt
>>> > 1
>>> >
>>> >
>>> > Cheers,
>>> > Ben
>>> >
>>> >
>>> >
>>> >
>>> > Le Jul 27, 2012 à 7:08 PM, Benoist Laurent a écrit :
>>> >
>>> >>
>>> >>
>>> >> Yes basically looks like you get it.
>>> >> I have to further test it but my first impression is that it's correct.
>>> >>
>>> >> So actually the point was to use nargs="?".
>>> >>
>>> >> Thank you very much.
>>> >> Ben
>>> >>
>>> >>
>>> >>
>>> >> Le Jul 27, 2012 à 5:44 PM, Peter Otten a écrit :
>>> >>
>>> >>> Benoist Laurent wrote:
>>> >>>
>>> >>>> I'm impletting a tool in Python.
>>> >>>>
>>> >>>> I'd like this tool to behave like a standard unix tool, as grep for
>>> >>>>
>>> >>>> exemple. I chose to use the argparse module to parse the command line and
>>> >>>>
>>> >>>> I think I'm getting into several limitations of this module.
>>> >>>>
>>> >>>>
>>> >>>>> First Question.
>>> >>>>
>>> >>>> How can I configure the the ArgumentParser to allow the user to give
>>> >>>>
>>> >>>> either an input file or to pipe the output from another program?
>>> >>>>
>>> >>>>
>>> >>>> $ mytool.py file.txt
>>> >>>>
>>> >>>> $ cat file.txt | mytool.py
>>> >>>
>>> >>>
>>> >>> $ echo alpha > in.txt
>>> >>> $ cat in.txt | ./mytool.py 
>>> >>> ALPHA
>>> >>> $ cat in.txt | ./mytool.py - out.txt
>>> >>> $ cat out.txt 
>>> >>> ALPHA
>>> >>> $ ./mytool.py in.txt 
>>> >>> ALPHA
>>> >>> $ ./mytool.py in.txt out2.txt
>>> >>> $ cat out2.txt 
>>> >>> ALPHA
>>> >>> $ cat ./mytool.py
>>> >>> #!/usr/bin/env python
>>> >>> assert __name__ == "__main__"
>>> >>>
>>> >>> import argparse
>>> >>> import sys
>>> >>>
>>> >>> parser = argparse.ArgumentParser()
>>> >>> parser.add_argument("infile", nargs="?", type=argparse.FileType("r"), 
>>> >>> default=sys.stdin)
>>> >>> parser.add_argument("outfile", nargs="?", type=argparse.FileType("w"), 
>>> >>> default=sys.stdout)
>>> >>> args = parser.parse_args()
>>> >>>
>>> >>> args.outfile.writelines(line.upper() for line in args.infile)
>>> >>>
>>> >>> Is that good enough?
>>> >>>
>>> >>>
>>> >>> -- 
>>> >>> http://mail.python.org/mailman/listinfo/python-list
>>> >>>
>>> >>
>>> >> -- 
>>> >> Benoist Laurent
>>> >> Laboratoire de Biochimie Theorique / CNRS UPR 9080
>>> >> Institut de Biologie Physico-Chimique
>>> >> 13, rue Pierre et Marie Curie
>>> >> F-75005 Paris
>>> >> Tel. +33 [0]1 58 41 51 67 or +33 [0]6 21 64 50 56
>>> >>
>>> >> -- 
>>> >> http://mail.python.org/mailman/listinfo/python-list
>>> >
>>> >
>>> > -- 
>>> > Benoist Laurent
>>> > Laboratoire de Biochimie Theorique / CNRS UPR 9080
>>> > Institut de Biologie Physico-Chimique
>>> > 13, rue Pierre et Marie Curie
>>> > F-75005 Paris
>>> > Tel. +33 [0]1 58 41 51 67 or +33 [0]6 21 64 50 56
>>> >
>>> >
>>> > --
>>> > http://mail.python.org/mailman/listinfo/python-list
>>> >
>> 
>> -- 
>> Benoist Laurent
>> Laboratoire de Biochimie Theorique / CNRS UPR 9080
>> Institut de Biologie Physico-Chimique
>> 13, rue Pierre et Marie Curie
>> F-75005 Paris
>> Tel. +33 [0]1 58 41 51 67 or +33 [0]6 21 64 50 56
>> 
>> -- 
>> http://mail.python.org/mailman/listinfo/python-list
> 
> 
> -- 
> Benoist Laurent
> Laboratoire de Biochimie Theorique / CNRS UPR 9080
> Institut de Biologie Physico-Chimique
> 13, rue Pierre et Marie Curie
> F-75005 Paris
> Tel. +33 [0]1 58 41 51 67 or +33 [0]6 21 64 50 56
> 
> 

-- 
Benoist Laurent
Laboratoire de Biochimie Theorique / CNRS UPR 9080
Institut de Biologie Physico-Chimique
13, rue Pierre et Marie Curie
F-75005 Paris
Tel. +33 [0]1 58 41 51 67 or +33 [0]6 21 64 50 56

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-list/attachments/20120731/a2aa7e3b/attachment.html>


More information about the Python-list mailing list