This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-11-16
Channels
- # announcements (62)
- # babashka (12)
- # babashka-sci-dev (73)
- # beginners (16)
- # biff (10)
- # calva (65)
- # cider (13)
- # clerk (8)
- # clojure (31)
- # clojure-europe (16)
- # clojure-nl (1)
- # clojure-norway (19)
- # clojure-spec (24)
- # clojure-uk (5)
- # clojuredesign-podcast (18)
- # clojurescript (18)
- # dev-tooling (2)
- # emacs (30)
- # etaoin (4)
- # gratitude (3)
- # hyperfiddle (20)
- # integrant (2)
- # jobs (4)
- # kaocha (7)
- # malli (1)
- # observability (11)
- # off-topic (11)
- # pathom (12)
- # podcasts-discuss (7)
- # portal (12)
- # quil (3)
- # re-frame (6)
- # releases (1)
- # sql (22)
- # squint (5)
- # testing (79)
- # tools-deps (3)
- # xtdb (20)
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… 😒
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
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 😛
ah no hold on
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
dont have the same dest as an arg
you had dest as foo and an arg as foo too
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 meanno 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
e.g. I want to run:
print(parser.parse_args(['sub1', '--bar', '1','sub2', '--dude', '2']));
the imperativeness is the headache
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?
if they have the same keys the last one will be there
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')
even though i wanted baz as the second thing
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
res.arg_name
lemme read a bit more about nested things, i could be missing something
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
lemme see what people say about conflicting option keys
thats 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')