Optional Arguments in Argparse - python

How can I generate an error message if fewer than required optional arguments are passed in the command line while using argparse in code? for example, I have 5 optional arguments and I want to generate an error message if fewer than 4 optional arguments are used at any time.
My beginner brain can't figure this out.
import argparse
import math
parser = argparse.ArgumentParser(description='Loan Calculator')
parser.add_argument('--type', type=str)
parser.add_argument('--principal', type=int)
parser.add_argument('--periods', type=int)
parser.add_argument('--interest', type=float)
parser.add_argument('--payment', type=int)
args = parser.parse_args()

This is something that's most simply handled after you've called parse_args. Count how many of the options still have the default value of None. If there's more than 1, raise an error.
args = parser.parse_args()
if 1 < sum(1 for x in [args.type, args.principal, args.periods, args.interest, args.payment] if x is None):
sys.exit("Too few options specified")

Related

python argparse default with nargs wont work [duplicate]

This question already has answers here:
Argparse optional argument with different default if specified without a value
(2 answers)
Closed last month.
Here is my code:
from argparse import ArgumentParser, RawTextHelpFormatter
example_text = "test"
parser = ArgumentParser(description='my script.',
epilog=example_text,
formatter_class=RawTextHelpFormatter)
parser.add_argument('host', type=str, default="10.10.10.10",
help="Device IP address or Hostname.")
parser.add_argument('-j','--json_output', type=str, default="s", nargs='?',choices=["s", "l"],
help="Print GET statement in json form.")
#mutally exclusive required settings supplying the key
settingsgroup = parser.add_mutually_exclusive_group(required=True)
settingsgroup.add_argument('-k', '--key', type=str,
help="the api-key to use. WARNING take care when using this, the key specified will be in the user's history.")
settingsgroup.add_argument('--config', type=str,
help="yaml config file. All parameters can be placed in the yaml file. Parameters provided from form command line will take priority.")
args = parser.parse_args()
print(args.json_output)
my output:
None
Everything I am reading online says this should work, but it doesn't. Why?
You could use the const= parameter. const stores its value when the option is present but have no values
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-j', '--json-output', nargs='?', choices=['s', 'l'], const='s')
args = parser.parse_args()
However design wise, it might be better to use the following:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-o', '--output-type', choices=['json-s', 'json-l', 'normal'], default='normal')
args = parser.parse_args()

Python Argument Parser - the following arguments are reqired --name

When I run the following code:
def read_args():
parser = default_parser()
parser.add_argument('--tensorboard-dir', type=str, default='/tmp/cifar10/tensorboard')
parser.add_argument('-N', type=int, default=50000, help="Use N training examples.")
return parser.parse_args()
def main():
flags = readargs()
I have the following error output:
The following arguments are required: --name
However when I add the --name argument:
def read_args():
parser = default_parser()
parser.add_argument('--name', type=str, default='cifar10test')
parser.add_argument('--tensorboard-dir', type=str, default='/tmp/cifar10/tensorboard')
parser.add_argument('-N', type=int, default=50000, help="Use N training examples.")
return parser.parse_args()
def main():
flags = readargs()
is also creating problem.
Any ideas?
It appears that default_parser contains a --name argument which is required. What you're doing in your second example is defining the argument twice - once in default_parser and once in your program. Instead, you should be passing a --name argument when calling your program from the command line.
Example:
python cifar.py -N=1200 --tensorboard-dir=file.txt --name=cool_name
Alternatively, you could remove default_parser and construct your own ArgumentParser:
`parser = argparse.ArgumentParser()`
Full working demo:
import argparse
def read_args():
parser = argparse.ArgumentParser()
parser.add_argument('--tensorboard-dir', type=str,
default='/tmp/cifar10/tensorboard')
parser.add_argument('-N', type=int, default=50000,
help="Use N training examples.")
return parser.parse_args()
def main():
flags = vars(read_args())
# You can access your args as a dictionary
for key in flags:
print("{} is {}".format(key, flags[key]))
main()
The parser returns a Namespace object, but we can access its (much simpler) internal dictionary using vars(Namespace). You can then get your arguments by accessing the dictionary, for example, flags['N']. Note that tensorboard-dir becomes tensorboard_dir inside your python program to avoid issues with the subtraction operator.
Call it from the command line (I'm using Bash):
python cifar.py -N=1200 --tensorboard-dir=file.txt
Output:
tensorboard_dir is file.txt
N is 1200

Python - Optional Command Line Argument

I would like to have an option -n, that will allow users to specify a size of a list. The default will be 30. So:
./findNumberOfPlayers.py -n10
I haven't done any command line arguments with python before but am confused with how to include -n10 within the program. I understand I would import sys and have 12 assigned to sys.argv[1] but how does it work with -n10?
Thank You! I appreciate the help.
Use argparse.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-n", "--number", help="Enter a number", type=int)
You can then access the arg like this -
args = parser.parse_args()
num_players = args.number if args.number else 30

Call function based on argparse

I'm new to python and currently playing with it.
I have a script which does some API Calls to an appliance. I would like to extend the functionality and call different functions based on the arguments given when calling the script.
Currently I have the following:
parser = argparse.ArgumentParser()
parser.add_argument("--showtop20", help="list top 20 by app",
action="store_true")
parser.add_argument("--listapps", help="list all available apps",
action="store_true")
args = parser.parse_args()
I also have a
def showtop20():
.....
and
def listapps():
....
How can I call the function (and only this) based on the argument given?
I don't want to run
if args.showtop20:
#code here
if args.listapps:
#code here
as I want to move the different functions to a module later on keeping the main executable file clean and tidy.
Since it seems like you want to run one, and only one, function depending on the arguments given, I would suggest you use a mandatory positional argument ./prog command, instead of optional arguments (./prog --command1 or ./prog --command2).
so, something like this should do it:
FUNCTION_MAP = {'top20' : my_top20_func,
'listapps' : my_listapps_func }
parser.add_argument('command', choices=FUNCTION_MAP.keys())
args = parser.parse_args()
func = FUNCTION_MAP[args.command]
func()
At least from what you have described, --showtop20 and --listapps sound more like sub-commands than options. Assuming this is the case, we can use subparsers to achieve your desired result. Here is a proof of concept:
import argparse
import sys
def showtop20():
print('running showtop20')
def listapps():
print('running listapps')
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
# Create a showtop20 subcommand
parser_showtop20 = subparsers.add_parser('showtop20', help='list top 20 by app')
parser_showtop20.set_defaults(func=showtop20)
# Create a listapps subcommand
parser_listapps = subparsers.add_parser('listapps', help='list all available apps')
parser_listapps.set_defaults(func=listapps)
# Print usage message if no args are supplied.
# NOTE: Python 2 will error 'too few arguments' if no subcommand is supplied.
# No such error occurs in Python 3, which makes it feasible to check
# whether a subcommand was provided (displaying a help message if not).
# argparse internals vary significantly over the major versions, so it's
# much easier to just override the args passed to it.
if len(sys.argv) <= 1:
sys.argv.append('--help')
options = parser.parse_args()
# Run the appropriate function (in this case showtop20 or listapps)
options.func()
# If you add command-line options, consider passing them to the function,
# e.g. `options.func(options)`
There are lots of ways of skinning this cat. Here's one using action='store_const' (inspired by the documented subparser example):
p=argparse.ArgumentParser()
p.add_argument('--cmd1', action='store_const', const=lambda:'cmd1', dest='cmd')
p.add_argument('--cmd2', action='store_const', const=lambda:'cmd2', dest='cmd')
args = p.parse_args(['--cmd1'])
# Out[21]: Namespace(cmd=<function <lambda> at 0x9abf994>)
p.parse_args(['--cmd2']).cmd()
# Out[19]: 'cmd2'
p.parse_args(['--cmd1']).cmd()
# Out[20]: 'cmd1'
With a shared dest, each action puts its function (const) in the same Namespace attribute. The function is invoked by args.cmd().
And as in the documented subparsers example, those functions could be written so as to use other values from Namespace.
args = parse_args()
args.cmd(args)
For sake of comparison, here's the equivalent subparsers case:
p = argparse.ArgumentParser()
sp = p.add_subparsers(dest='cmdstr')
sp1 = sp.add_parser('cmd1')
sp1.set_defaults(cmd=lambda:'cmd1')
sp2 = sp.add_parser('cmd2')
sp2.set_defaults(cmd=lambda:'cmd2')
p.parse_args(['cmd1']).cmd()
# Out[25]: 'cmd1'
As illustrated in the documentation, subparsers lets you define different parameter arguments for each of the commands.
And of course all of these add argument or parser statements could be created in a loop over some list or dictionary that pairs a key with a function.
Another important consideration - what kind of usage and help do you want? The different approaches generate very different help messages.
If your functions are "simple enough" take adventage of type parameter https://docs.python.org/2.7/library/argparse.html#type
type= can take any callable that takes a single string argument and
returns the converted value:
In your example (even if you don't need a converted value):
parser.add_argument("--listapps", help="list all available apps",
type=showtop20,
action="store")
This simple script:
import argparse
def showtop20(dummy):
print "{0}\n".format(dummy) * 5
parser = argparse.ArgumentParser()
parser.add_argument("--listapps", help="list all available apps",
type=showtop20,
action="store")
args = parser.parse_args()
Will give:
# ./test.py --listapps test
test
test
test
test
test
test
Instead of using your code as your_script --showtop20, make it into a sub-command your_script showtop20 and use the click library instead of argparse. You define functions that are the name of your subcommand and use decorators to specify the arguments:
import click
#click.group()
#click.option('--debug/--no-debug', default=False)
def cli(debug):
print(f'Debug mode is {"on" if debug else "off"}')
#cli.command() # #cli, not #click!
def showtop20():
# ...
#cli.command()
def listapps():
# ...
See https://click.palletsprojects.com/en/master/commands/
# based on parser input to invoke either regression/classification plus other params
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--path", type=str)
parser.add_argument("--target", type=str)
parser.add_argument("--type", type=str)
parser.add_argument("--deviceType", type=str)
args = parser.parse_args()
df = pd.read_csv(args.path)
df = df.loc[:, ~df.columns.str.contains('^Unnamed')]
if args.type == "classification":
classify = AutoML(df, args.target, args.type, args.deviceType)
classify.class_dist()
classify.classification()
elif args.type == "regression":
reg = AutoML(df, args.target, args.type, args.deviceType)
reg.regression()
else:
ValueError("Invalid argument passed")
# Values passed as : python app.py --path C:\Users\Abhishek\Downloads\adult.csv --target income --type classification --deviceType GPU
You can evaluate using evalwhether your argument value is callable:
import argparse
def list_showtop20():
print("Calling from showtop20")
def list_apps():
print("Calling from listapps")
my_funcs = [x for x in dir() if x.startswith('list_')]
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--function", required=True,
choices=my_funcs,
help="function to call", metavar="")
args = parser.parse_args()
eval(args.function)()

argparse coding issue

write a script that takes two optional boolean arguments,"--verbose‚" and ‚"--live", and two required string arguments, "base"and "pattern". Please set up the command line processing using argparse.
This is the code I have so far for the question, I know I am getting close but something is not quite right. Any help is much appreciated.Thanks for all the quick useful feedback.
def main():
import argparse
parser = argparse.ArgumentParser(description='')
parser.add_argument('base', type=str)
parser.add_arguemnt('--verbose', action='store_true')
parser.add_argument('pattern', type=str)
parser.add_arguemnt('--live', action='store_true')
args = parser.parse_args()
print(args.base(args.pattern))
The string arguments are not required by default, so you need to state that. Also the print statement that uses the arguments is incorrect.
#!/usr/bin/python
import argparse
if __name__=="__main__":
parser = argparse.ArgumentParser(description='eg $python myargs.py --base arg1 --pattern arg2 [--verbose] [--live]')
parser.add_argument('--base', required=True, type=str)
parser.add_argument('--pattern', required=True, type=str)
parser.add_argument('--verbose', action='store_true')
parser.add_argument('--live', action='store_true')
args = parser.parse_args()
print "args.base=" + str(args.base)
print "args.pattern=" + str(args.pattern)
print "args.verbose=" + str(args.verbose)
print "args.live=" + str(args.live)
the #!/usr/bin/python at the top enables the script to be called directly, though python must be located there (to confirm, type $which python), and you must set the file to have execute permission ($chmod +x myargs.py)

Categories

Resources