I am playing around with Python's argparse module in order to get a rather complicated and large sub-commands structure. So far, the arguments parse goes pretty well and everything works fine but I am looking for a better way to manage how sub-commands are executed.
Here is an example of my dummy/playaround application:
def a_func(cmd_args):
print(cmd_args)
def b_func(cmd_args):
print(cmd_args)
CMD_DISPATCHER = {
'a': a_func,
'b': b_func
}
def parse_commands():
# Create top-level parser
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subcmd_name')
# Create parser for the "a" sub-command
parser_a = subparsers.add_parser('a')
parser_a.add_argument('-bar', type=int)
# Create parser for the "b" sub-command
parser_b = subparsers.add_parser('b')
parser_b.add_argument('-foo', type=int)
args = parser.parse_args()
CMD_DISPATCHER[args.subcmd_name](args)
def main():
parse_commands()
if __name__ == '__main__':
main()
As you can see, here I use a simple dict (CMD_DISPATCHER) as a map relating the sub-command name to its function.
As I said, this is just a simple example of what I want to achieve but the real project will have many nested sub-commands so I would like a better way to manage those several sub-commands.
Do you know a better/more-professional way to do this?
OK, after some more research I have found a good way that fits my needs: set_defaults. I have used this function earlier but always to set default existing default argument values. I did not notice the clear example that argparse documentation provides:
>>> # sub-command functions
>>> def foo(args):
... print(args.x * args.y)
...
>>> def bar(args):
... print('((%s))' % args.z)
...
>>> # create the top-level parser
>>> parser = argparse.ArgumentParser()
>>> subparsers = parser.add_subparsers()
>>>
>>> # create the parser for the "foo" command
>>> parser_foo = subparsers.add_parser('foo')
>>> parser_foo.add_argument('-x', type=int, default=1)
>>> parser_foo.add_argument('y', type=float)
>>> parser_foo.set_defaults(func=foo)
>>>
>>> # create the parser for the "bar" command
>>> parser_bar = subparsers.add_parser('bar')
>>> parser_bar.add_argument('z')
>>> parser_bar.set_defaults(func=bar)
>>>
>>> # parse the args and call whatever function was selected
>>> args = parser.parse_args('foo 1 -x 2'.split())
>>> args.func(args)
2.0
>>>
>>> # parse the args and call whatever function was selected
>>> args = parser.parse_args('bar XYZYX'.split())
>>> args.func(args)
((XYZYX))
As you can see the line parser_bar.set_defaults(func=bar) sets a new variable to parser_bar arguments. In this case bar is a function that is eventually used as the sub-command executor in line args.func(args).
I hope this helps someone in the future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With