How can I get an argument name from argparse? - python

This is my command line script
import argparse
parser = argparse.ArgumentParser('My command line app')
parser.add_argument('--start', type=start, metavar='HOST', dest='result', nargs='*', default='all', help='Start hosts')
parser.add_argument('--stop', type=stop, metavar='HOST', dest='result', nargs='*', default='all', help='Stop hosts')
parser.add_argument('--status', type=status, metavar='HOST', dest='result', nargs='*', default='all', help='Show hosts status')
args = parser.parse_args()
Currently I defined one function for each option, but I would like to wrap them in only one for these three options. Then I would need to know which argument was used. Is it possible with argparse?
Solution
At the end I took this way:
import argparse
def wrapper(command, hosts):
pass
parser = argparse.ArgumentParser('My script')
parser.add_argument('action', choices=['start', 'stop', 'status'], help='Action')
parser.add_argument('hosts', metavar='HOST', nargs='*', default='all')
args = parser.parse_args()
wrapper(args.action, args.hosts)

It sounds like the saner way to handle this would be the choices parameter:
commands = {'start': start, 'stop': stop, 'status': status}
parser = argparse.ArgumentParser('My command line app')
parser.add_argument('command', choices=commands.keys())
parser.add_argument('hosts', nargs='*', default=[])
args = parser.parse_args()
commands[args.command](*args.hosts)

Related

How to add groups in subparser?

I would like to add groups in a subparser.
parser = argparse.ArgumentParser(description="A Pipeline.")
subparsers = parser.add_subparsers(
help="Choose imagery source", dest="imagery_source"
)
animal_parser = subparsers.add_parser("animal")
group1_parser = animal_parser.add_argument_group("for_dog_config")
group1_parser.add_argument("--dog", type=str)
group2_parser = animal_parser.add_argument_group("for_cat_config")
group2_parser.add_argument("--cat", type=str)
args = parser.parse_args()
print(args)
run_pipeline animal --dog hello --cat world
Here is the output of namespace.
Namespace(cat='world', dog='hello', imagery_source='animal')
What I would like is that the cat and dog are in different namespaces or dictionaries respectively. Is it possible?
Note: I know there are other answers using add_argument_group in ArgumentParser object, but I need to use subparsers = prser.add_subparsers here.
=========== Update ===========
This code block almost do what I need.
def get_arg(parser):
args = parser.parse_args()
args_groups = {}
for group in parser._action_groups:
group_dict = {a.dest: getattr(args, a.dest, None) for a in group._group_actions}
args_groups.update({group.title: argparse.Namespace(**group_dict)})
return args_groups
parser = argparse.ArgumentParser(description="A Pipeline.")
subparsers = parser.add_subparsers(
help="Choose imagery source", dest="imagery_source"
)
group1_parser = parser.add_argument_group("for_dog_config")
group1_parser.add_argument("--dog", type=str)
group2_parser = parser.add_argument_group("for_cat_config")
group2_parser.add_argument("--cat", type=str)
args = get_arg(parser)
print(args)
Execute run_stereo_pipeline --dog hello --cat world
The output is
{'positional arguments': Namespace(imagery_source=None), 'optional arguments': Namespace(help=None), 'for_dog_config': Namespace(dog='hello'), 'for_cat_config': Namespace(cat='world')}
As you can see, now I can do things like args["for_cat_config"] to get all arguments in the "for_cat_config" group. But in this approach, I can not specify animal source which is what I want in the question.

python get changed (non-default) cli arguments?

Given an argument parser with n arguments, where I change the default value of only a small subset every run from the command line, is there a clean way of extracting a dict/namespace of all the non-default k,v arguments?
parser = argparse.ArgumentParser()
parser.add_argument("--a",type=str,default='a')
parser.add_argument("--b",type=str,default='b')
parser.add_argument("--c",type=str,default='c')
parser.add_argument("--d",type=str,default='d')
And
python run.py --a "e"
I would like to have
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--a",type=str,default='a')
parser.add_argument("--b",type=str,default='b')
parser.add_argument("--c",type=str,default='c')
parser.add_argument("--d",type=str,default='d')
non_default = parse_non_default(parser) # non_default = {'a':'e'}
You could lookup the parser and compare which values differenciate:
import argparse
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--a", type=str, default='a')
parser.add_argument("--b", type=str, default='b')
parser.add_argument("--c", type=str, default='c')
parser.add_argument("--d", type=str, default='d')
parser.add_argument("--n", type=int, default=999)
args = parser.parse_args(['--a', 'e']) # Test CLI arguments!
non_default = {
opt.dest: getattr(args, opt.dest)
for opt in parser._option_string_actions.values()
if hasattr(args, opt.dest) and opt.default != getattr(args, opt.dest)
}
print(non_default)
main()
Out:
{'a': 'e'}

argparse - how to pass argument from args into function?

import argparse
from queries import most_common_cities
parser = argparse.ArgumentParser(description='A script that does operations with database data and returns values')
parser.add_argument('-c', '--most_common_cities',
nargs=1,
type=positive_int,
help='Specify how many common cities.')
args = parser.parse_args()
if args.most_common_cities:
result = most_common_cities(n) # "n" should be an arg passed by user
print(result)
How could I pass arguments from CLI to my function arg?
When someone use command:
python argp.py --most_common_cities 5
It should return 5 most common cities.
Remove nargs=1, then args.most_common_cities will be the actual value passed in.
nargs=1 wraps it in a list.
parser.add_argument('-c', '--most_common_cities',
type=int,
help='Specify how many common cities.')
args = parser.parse_args(['-c', '5'])
n = args.most_common_cities
print(n)
print(type(n))
# 5
# <class 'int'>
I started your script with following command:
python3 test.py --most_common_cities 5
You can access the arguments with:
import argparse
parser = argparse.ArgumentParser(description='A script that does operations with database data and returns values')
parser.add_argument('-c', '--most_common_cities',
nargs=1,
type=int,
help='Specify how many common cities.')
args = parser.parse_args()
arguments = vars(parser.parse_args())
print(arguments) #{'most_common_cities': [5]}
#then you can access the value with:
arguments['most_common_cities']

Subparser function calls

How do I call the following functions below based on user input?
For example, if they type:
python test.py cmd1 -n hostname
it will call def cmd1 and pass the -n parameter (hostname) to function
import argparse
def cmd1(node):
print('cmd1')
def cmd1_option1():
print('cmd2')
def cmd1_option1(template):
print('cmd3')
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='Functions')
command_1 = subparsers.add_parser('cmd1', help='...')
command_1.add_argument('-n', "--node", type=str, help='...')
command_2 = subparsers.add_parser('cmd2', help='...')
command_3 = subparsers.add_parser('cmd3', help='...')
command_3.add_argument('-t', "--template", type=int, help='...')
args = parser.parse_args()

python - argparse one argument instead of several others

For example I have options:
parser.add_argument('-b', action="store_true")
parser.add_argument('-c', action="store_true")
parser.add_argument('-d', action="store_true")
I want to enable all of them with synonym option "-a". Is it possible?
I think it is simplest to do this after parse_args():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-b', action="store_true")
parser.add_argument('-c', action="store_true")
parser.add_argument('-d', action="store_true")
parser.add_argument('-a', action="store_true")
args = parser.parse_args()
if args.a: args.b = args.c = args.d = True
Alternatively, you could do it with a custom action, but I think it is overkill:
import argparse
class AllAction(argparse.Action):
def __call__(self, parser, args, values, option_string = None):
# print '{n} {v} {o}'.format(n = args, v = values, o = option_string)
for param in ['a', 'b', 'c', 'd']:
setattr(args, param, True)
parser = argparse.ArgumentParser()
parser.add_argument('-b', action="store_true")
parser.add_argument('-c', action="store_true")
parser.add_argument('-d', action="store_true")
parser.add_argument('-a', action = AllAction, nargs = '?')
args = parser.parse_args()
print(args)

Categories