This question already has answers here:
Can't get argparse to read quoted string with dashes in it?
(7 answers)
Closed 5 years ago.
Consider following MCVE:
import sys
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-t", "--test")
parser.add_argument("-o", "--other")
assert sys.argv == ['mcve.py', '-o', '-t 123']
parsed = parser.parse_args()
assert parsed.other == "-t 123"
And its' invocation:
lrogalsk-mac01:src lrogalsk$ python mcve.py -o "-t 123"
usage: mcve.py [-h] [-t TEST] [-o OTHER]
mcve.py: error: argument -o/--other: expected one argument
As you can see, values in shell are interpreted correctly and passed to Python process as separate command line arguments. Nevertheless, argparse parsing mechanism still rejects this value (likely because it begins with match of another parameter, -t).
Changing invocation to space-prepended value (see below) and adjusting assertions in MCVE script makes it work, but this for me is merely workaround and not an actual solution.
lrogalsk-mac01:src lrogalsk$ python mcve.py -o " -t 123"
Is there any known way of fixing this behaviour in argparse?
Set-up details:
lrogalsk-mac01:src lrogalsk$ python --version
Python 2.7.10
In the 'argparse' documentation, this case is mentioned (16.4.4.3):
The parse_args() method attempts to give errors whenever the user has
clearly made a mistake, but some situations are inherently ambiguous.
For example, the command-line argument -1 could either be an attempt
to specify an option or an attempt to provide a positional argument.
The parse_args() method is cautious here: positional arguments may
only begin with - if they look like negative numbers and there are no
options in the parser that look like negative numbers
For positional arguments, you can prepend a '--', but in your case that doesn't seem to work. Instead, the use of subparsers is supported, so
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help = 'the subparsers')
parser_a = subparsers.add_parser('o', help = 'the o option')
parser_a.add_argument('-t', '--test')
parsed = parser.parse_args()
print(parsed.test)
works. Calling the script with
python mcve.py o -t 123
gives the output
123
Related
This question already has answers here:
Can't get argparse to read quoted string with dashes in it?
(7 answers)
Closed 5 years ago.
I'm doing a command line utility that can receive a parameter starting with a minus or plus, for instance, -gtest or +gtest the problem is that python3 don't accept this:
This is a minimal code that reproduce this problem:
import argparse
if (__name__== "__main__"):
parser = argparse.ArgumentParser()
parser.add_argument('-s', '--string', action='store',
help='String value')
p = parser.parse_args()
if p.string:
print("pass value:", p.string)
I try to invoke it as:
./example.py -s -gtest
./example.py -s "-gtest"
./example.py -s \-gtest
And always get next error:
usage: example.py [-h] [-s STRING]
example.py: error: argument -s/--string: expected one argument
So, my question is how I can pass a argument starting with a minus using argparse
You can run it with:
python example.py -s-gtest
python example.py -s+gtest
So simply not putting any space, nor escaping it in any special way.
I have been trying to set up a main parser with two subs parser so that when called alone, the main parser would display a help message.
def help_message():
print "help message"
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='sp')
parser_a = subparsers.add_parser('a')
parser_a.required = False
#some options...
parser_b = subparsers.add_parser('b')
parser_b.required = False
#some options....
args = parser.parse_args([])
if args.sp is None:
help_message()
elif args.sp == 'a':
print "a"
elif args.sp == 'b':
print "b"
This code works well on Python 3 and I would like it to work aswell on Python 2.x
I am getting this when running 'python myprogram.py'
myprogram.py: error: too few arguments
Here is my question : How can i manage to write 'python myprogram.py' in shell and get the help message instead of the error.
I think you are dealing the bug discussed in http://bugs.python.org/issue9253
Your subparsers is a positional argument. That kind of argument is always required, unless nargs='?' (or *). I think that is why you are getting the error message in 2.7.
But in the latest py 3 release, the method of testing for required arguments was changed, and subparsers fell through the cracks. Now they are optional (not-required). There's a suggested patch/fudge to make argparse behave as it did before (require a subparser entry). I expect that eventually py3 argparse will revert to the py2 practice (with a possible option of accepting a required=False parameter).
So instead of testing args.sp is None, you may want to test sys.argv[1:] before calling parse_args. Ipython does this to produce it's own help message.
For others - I ended up on this page while trying to figure out why I couldn't just call my script with no arguments while using argparse in general.
The tutorial demonstrates that the difference between an optional argument and a required argument is adding "--" to the name:
parser.add_argument("--show") <--- Optional arg
parser.add_argument("show") <--- Not optional arg
This question already has answers here:
Display help message with Python argparse when script is called without any arguments
(18 answers)
Closed 8 years ago.
With the following code:
import argparse
parser = argparse.ArgumentParser(description="Prepare something code.")
parser.add_argument("-t","--tabular", help="print something in tabular way for EXCEL",
action="store_true")
parser.add_argument("-v","--verbose", action="store_true")
args = parser.parse_args()
if args.tabular:
print "Tabular print"
elif args.verbose:
print "VERBOSE"
It's only when I execute it the following way, that it prints usage:
$ python mycode.py -h
usage: mycode.py [-h] [-t] [-v]
Prepare something code.
optional arguments:
-h, --help show this help message and exit
-t, --tabular print something in tabular way for EXCEL
-v, --verbose
What I want to do is to simply run the code: $ my code.py without any -h option whatsoever to print the usage. How can I do that?
That 2010 question covers the same thing, but only has 1 answer. While that answer comes indirectly from the designer of argparse, it does not cover all possibilities.
Here's one which surprised me as to its simplicity:
import sys
parser = ...
if len(sys.argv)==1:
parser.print_help()
# parser.print_usage() # for just the usage line
parser.exit()
args = parser.parse_args()
Yes you can check all the namespace args for default values, but that gets old if there are many arguments. But here I am just checking whether there are any argument strings. If none, then call the parser's own help function.
ipython does something like this to generate help. It checks sys.argv for some version of help, and produces its own help message(s), before even defining the parser.
import argparse
parser = argparse.ArgumentParser(description="Prepare something code.")
parser.add_argument("-t","--tabular", help="print something in tabular way for EXCEL",
action="store_true")
parser.add_argument("-v","--verbose", action="store_true")
args = parser.parse_args()
if args.tabular:
print "Tabular print"
elif args.verbose:
print "VERBOSE"
else:
print parser.print_help()
If you need exactly one of "-t" or "-v" be used, they aren't really optional. I'd use a positional parameter instead:
import argparse
parser = argparse.ArgumentParser(description="Prepare something code.")
parser.add_argument("type", choices=("tabular", "verbose", "t", "v"))
args = parser.parse_args()
if args.type in ("tabular", "t"):
print "Tabular print"
else: # Must be "verbose" or "v"
print "VERBOSE"
Then your program would be called using one of the following:
$ my_code t
$ my_code tabular
$ my_code v
$ my_code verbose
No argument would produce
$ my_code
usage: my_code [-h] {tabular,verbose,t,v}
my_code: error: too few arguments
I need some help regarding using argparse. What I want to achieve is that I need to pass in only one argument, it could be one of the followings: --k, --r, --b, --p,(ignore the rest). If the argument count is not 1, print "usage" information and quit. Also the program needs to know which flag is passed in in order to create corresponding object. I tried several times but I doesn't work, can anyone give me a hint on this? Thanks.
What you need to use to accomplish that is a mutually exclusive group:
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument('-k', action='store_true')
group.add_argument('-r', action='store_true')
group.add_argument('-b', action='store_true')
group.add_argument('-p', action='store_true')
parser.parse_args()
As it can be seen in the example below, only one option in a mutually exclusive group is allowed at the same time:
$ python test.py -k -r -b -p
usage: test.py [-h] [-k | -r | -b | -p]
test.py: error: argument -r: not allowed with argument -k
To check which flag was passed, you just need to look at the argparse.Namespace object returned by parse_args method (the flag passed will be set to True).
How about not using argparse at all? It doesn't seem really necessary.
if len(sys.argv) != 2:
print_usage()
arg = sys.argv[1]
if arg not in ["--k", "--r", "--b", "--p"]:
print_usage()
# Do whatever you want with arg
This question already has answers here:
How to read/process command line arguments?
(22 answers)
Closed last month.
What would be an easy expression to process command line arguments if I'm expecting anything like 001 or 999 (let's limit expectations to 001...999 range for this time), and few other arguments passed, and would like to ignore any unexpected?
I understand if for example I need to find out if "debug" was passed among parameters it'll be something like that:
if 'debug' in argv[1:]:
print 'Will be running in debug mode.'
How to find out if 009 or 575 was passed?
All those are expected calls:
python script.py
python script.py 011
python script.py 256 debug
python script.py 391 xls
python script.py 999 debug pdf
At this point I don't care about calls like that:
python script.py 001 002 245 568
python script.py some unexpected argument
python script.py 0001
python script.py 02
...first one - because of more than one "numeric" argument; second - because of... well, unexpected arguments; third and fourth - because of non-3-digits arguments.
As others answered, optparse is the best option, but if you just want quick code try something like this:
import sys, re
first_re = re.compile(r'^\d{3}$')
if len(sys.argv) > 1:
if first_re.match(sys.argv[1]):
print "Primary argument is : ", sys.argv[1]
else:
raise ValueError("First argument should be ...")
args = sys.argv[2:]
else:
args = ()
# ... anywhere in code ...
if 'debug' in args:
print 'debug flag'
if 'xls' in args:
print 'xls flag'
EDIT: Here's an optparse example because so many people are answering optparse without really explaining why, or explaining what you have to change to make it work.
The primary reason to use optparse is it gives you more flexibility for expansion later, and gives you more flexibility on the command line. In other words, your options can appear in any order and usage messages are generated automatically. However to make it work with optparse you need to change your specifications to put '-' or '--' in front of the optional arguments and you need to allow all the arguments to be in any order.
So here's an example using optparse:
import sys, re, optparse
first_re = re.compile(r'^\d{3}$')
parser = optparse.OptionParser()
parser.set_defaults(debug=False,xls=False)
parser.add_option('--debug', action='store_true', dest='debug')
parser.add_option('--xls', action='store_true', dest='xls')
(options, args) = parser.parse_args()
if len(args) == 1:
if first_re.match(args[0]):
print "Primary argument is : ", args[0]
else:
raise ValueError("First argument should be ...")
elif len(args) > 1:
raise ValueError("Too many command line arguments")
if options.debug:
print 'debug flag'
if options.xls:
print 'xls flag'
The differences here with optparse and your spec is that now you can have command lines like:
python script.py --debug --xls 001
and you can easily add new options by calling parser.add_option()
Have a look at the optparse module. Dealing with sys.argv yourself is fine for really simple stuff, but it gets out of hand quickly.
Note that you may find optparse easier to use if you can change your argument format a little; e.g. replace debug with --debug and xls with --xls or --output=xls.
optparse is your best friend for parsing the command line. Also look into argparse; it's not in the standard library, though.
If you want to implement actual command line switches, give getopt a look. It's incredibly simple to use, too.
Van Gale is largely correct in using the regular expression against the argument. However, it is NOT absolutely necessary to make everything an option when using optparse, which splits sys.argv into options and arguments, based on whether a "-" or "--" is in front or not. Some example code to go through just the arguments:
import sys
import optparse
claParser = optparse.OptionParser()
claParser.add_option(
(opts, args) = claParser.parse_args()
if (len(args) >= 1):
print "Arguments:"
for arg in args:
print " " + arg
else:
print "No arguments"
sys.exit(0)
Yes, the args array is parsed much the same way as sys.argv would be, but the ability to easily add options if needed has been added. For more about optparse, check out the relevant Python doc.