Who here is familiar with Python argparse? I'm trying to understand why the last printed value doesn't show a subcommand
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='subparser_name')
subparser1 = subparsers.add_parser('1')
subparser1.add_argument('-x')
subparser2 = subparsers.add_parser('2')
subparser2.add_argument('y')
res = parser.parse_args(['2', 'frobble'])
print(res);
parser = argparse.ArgumentParser()
sub = parser.add_subparsers(dest='foo')
sub1 = sub.add_parser('sub1')
sub1.add_argument('--foo');
sub1_sub = sub1.add_subparsers(title='dude')
sub2 = sub1_sub.add_parser('sub2')
sub2.add_argument('--dude')
print(parser.parse_args(['sub1', '--foo', '1']))
# 'sub2', '--dude', '2']));🧵
You would get a Namespace object as an output, which is the result of the parsing. It’s a class subclassing Dict
Should’ve been just a plain Dict but python and overengineering is a thing. Python is easy, something something… 😒
The first value does show a subcommand is what I meant
What’s the value that you see? I’ll try to take a better look with a proper machine
$ python3 arg.py --dude
Namespace(subparser_name='2', y='frobble')
Namespace(foo='1')if you add dest when creating a subparser its going to have that as a key in the namespace too. to help you identify which one was used
the second case just tells you the args as kv pairs
also you cannot create multiple subparsers with the same dest
https://docs.python.org/3/library/argparse.html#argparse.ArgumentParser.add_subparsers
I added dest= in both cases right?
ah right, lemme take another look
funny python: try
parser = argparse.ArgumentParser()
sub = parser.add_subparsers(dest="foo")
sub1 = sub.add_parser("sub1")
sub1.add_argument("--bar")
print(parser.parse_args(["sub1", "--bar", "1"]))guess what happens 😛
not sure?
ah no hold on
it crashes because it doesn't know bar would be my guess
finding a better one
yes this is good.
Namespace(foo='sub1', bar='1')
it was overwriting the key foo in your code
because foo is both a valid arg and the name of subparser dest
if you pass --bar then you have the expected behaviour
I'm confused
dont have the same dest as an arg
all I want is to find out the nest subparser output from this stuff
I don't care about the rest
you had dest as foo and an arg as foo too
I don't even want to know what "dest" is
the first foo got overwritten by the second
if I do this:
sub = parser.add_subparsers(dest='foo')
sub1 = sub.add_parser('sub1')
what does it even meanI thought sub1 was the subcommand, but is foo the subcommand?
no foo is the key in the namespace where the subcommand will be stored
in this case it would be foo = sub1
if you had another subparser: foo = sub2
can you maybe just write a program that has nested subcommand behavior that I can run? I just don't get this API
yeah
e.g. I want to run:
print(parser.parse_args(['sub1', '--bar', '1','sub2', '--dude', '2']));the imperativeness is the headache
and then see what the output is like
thanks!
import argparse
parser = argparse.ArgumentParser()
subparsers1 = parser.add_subparsers(dest="which_parser_l1")
sub1 = subparsers1.add_parser("sub1")
sub1.add_argument("--bar")
subparsers2 = sub1.add_subparsers(dest="which_parser_l2")
sub2 = subparsers2.add_parser("sub2")
sub2.add_argument("--dude")
print(parser.parse_args(["sub1", "--bar", "1", "sub2", "--dude", "2"]))does this help?
definitely!
and how does one get, say, the options for both subcommands out of this?
if they have the same keys the last one will be there
sure
import argparse
parser = argparse.ArgumentParser()
subparsers1 = parser.add_subparsers(dest="which_parser_l1")
sub1 = subparsers1.add_parser("sub1")
sub1.add_argument("--bar")
sub1.add_argument("--baz")
subparsers2 = sub1.add_subparsers(dest="which_parser_l2")
sub2 = subparsers2.add_parser("sub2")
sub2.add_argument("--dude")
sub2.add_argument("--baz")
print(
parser.parse_args(
["sub1", "--bar", "1", "--baz", "2", "sub2", "--dude", "2", "--baz", "4"]
)
)Namespace(which_parser_l1='sub1', bar='1', baz='4', which_parser_l2='sub2', dude='2')
huh, weird
even though i wanted baz as the second thing
but how do you get stuff out of this? is this data-ish?
res = parser.parse_args(
["sub1", "--bar", "1", "--baz", "2", "sub2", "--dude", "2", "--baz", "4"]
)
print(vars(res))this gives you a normal dict
it lumps all the options in one dict? I thought you would be able to get the opts out per subcommand or so
doesnt seem like it
ok, and how do normal python people get data out of this, without calling "vars"?
res.arg_name
lemme read a bit more about nested things, i could be missing something
TypeError: 'Namespace' object is not subscriptable
👍oh sorry, I just meant the thumbs up
ignore the error
right so it seems its in the order of the add_subparser calls. thats the order in which its going to form the keys in the namespace object.
all things following which_parser_l1 til which_parser_l2 are args to it
dicts in python maintain insertion order by default so that works too i suppose
for k, v in vars(res).items():
print(k, v)ok, still conflicts between the option keys, but it is possible to distuingish which group stuff was added to, got it
thanks for digging into this
lemme see what people say about conflicting option keys
yeah, like
--debug true sub1 --debug false sub2 --debug truethats the solution it seems:
import argparse
parser = argparse.ArgumentParser()
subparsers1 = parser.add_subparsers(dest="which_parser_l1")
sub1 = subparsers1.add_parser("sub1")
sub1.add_argument("--bar")
sub1.add_argument("--baz")
subparsers2 = sub1.add_subparsers(dest="which_parser_l2")
sub2 = subparsers2.add_parser("sub2")
sub2.add_argument("--dude")
sub2.add_argument("--baz", dest="sub_baz")
res = parser.parse_args(
["sub1", "--bar", "1", "--baz", "2", "sub2", "--dude", "2", "--baz", "4"]
)
print(res)Namespace(which_parser_l1='sub1', bar='1', baz='2', which_parser_l2='sub2', dude='2', sub_baz='4')