babashka-sci-dev

borkdude 2023-11-16T16:33:55.977889Z

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']));

borkdude 2023-11-16T16:34:01.693739Z

🧵

lispyclouds 2023-11-16T18:01:30.581809Z

You would get a Namespace object as an output, which is the result of the parsing. It’s a class subclassing Dict

lispyclouds 2023-11-16T18:03:49.973539Z

Should’ve been just a plain Dict but python and overengineering is a thing. Python is easy, something something… 😒

borkdude 2023-11-16T18:07:45.659879Z

The first value does show a subcommand is what I meant

lispyclouds 2023-11-16T18:12:48.510849Z

What’s the value that you see? I’ll try to take a better look with a proper machine

borkdude 2023-11-16T18:28:24.002829Z

$ python3 arg.py --dude
Namespace(subparser_name='2', y='frobble')
Namespace(foo='1')

lispyclouds 2023-11-16T20:00:26.085009Z

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

lispyclouds 2023-11-16T20:00:53.855649Z

the second case just tells you the args as kv pairs

lispyclouds 2023-11-16T20:01:35.712689Z

also you cannot create multiple subparsers with the same dest

borkdude 2023-11-16T20:05:27.327069Z

I added dest= in both cases right?

lispyclouds 2023-11-16T20:06:07.195169Z

ah right, lemme take another look

lispyclouds 2023-11-16T20:09:48.062349Z

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"]))

lispyclouds 2023-11-16T20:10:04.448439Z

guess what happens 😛

borkdude 2023-11-16T20:10:18.620499Z

not sure?

lispyclouds 2023-11-16T20:10:32.206639Z

ah no hold on

borkdude 2023-11-16T20:10:38.549809Z

it crashes because it doesn't know bar would be my guess

lispyclouds 2023-11-16T20:10:40.901929Z

finding a better one

lispyclouds 2023-11-16T20:11:32.522949Z

yes this is good. Namespace(foo='sub1', bar='1')

lispyclouds 2023-11-16T20:11:51.999779Z

it was overwriting the key foo in your code

lispyclouds 2023-11-16T20:12:19.623169Z

because foo is both a valid arg and the name of subparser dest

lispyclouds 2023-11-16T20:12:56.070809Z

if you pass --bar then you have the expected behaviour

borkdude 2023-11-16T20:13:27.747289Z

I'm confused

lispyclouds 2023-11-16T20:13:40.720559Z

dont have the same dest as an arg

borkdude 2023-11-16T20:13:42.539779Z

all I want is to find out the nest subparser output from this stuff

borkdude 2023-11-16T20:13:46.432909Z

I don't care about the rest

lispyclouds 2023-11-16T20:14:02.023179Z

you had dest as foo and an arg as foo too

borkdude 2023-11-16T20:14:04.742289Z

I don't even want to know what "dest" is

lispyclouds 2023-11-16T20:14:14.720549Z

the first foo got overwritten by the second

borkdude 2023-11-16T20:14:29.721059Z

if I do this:

sub = parser.add_subparsers(dest='foo')
sub1 = sub.add_parser('sub1')
what does it even mean

borkdude 2023-11-16T20:14:41.466519Z

I thought sub1 was the subcommand, but is foo the subcommand?

lispyclouds 2023-11-16T20:15:16.943959Z

no foo is the key in the namespace where the subcommand will be stored

lispyclouds 2023-11-16T20:15:30.916219Z

in this case it would be foo = sub1

lispyclouds 2023-11-16T20:15:51.386699Z

if you had another subparser: foo = sub2

borkdude 2023-11-16T20:16:23.757619Z

can you maybe just write a program that has nested subcommand behavior that I can run? I just don't get this API

lispyclouds 2023-11-16T20:16:31.945259Z

yeah

borkdude 2023-11-16T20:16:43.996829Z

e.g. I want to run:

print(parser.parse_args(['sub1', '--bar', '1','sub2', '--dude', '2']));

lispyclouds 2023-11-16T20:16:52.418539Z

the imperativeness is the headache

borkdude 2023-11-16T20:16:55.994029Z

and then see what the output is like

borkdude 2023-11-16T20:17:36.622739Z

thanks!

lispyclouds 2023-11-16T20:25:28.217449Z

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"]))

lispyclouds 2023-11-16T20:25:47.665079Z

does this help?

borkdude 2023-11-16T20:26:54.659719Z

definitely!

borkdude 2023-11-16T20:27:05.330169Z

and how does one get, say, the options for both subcommands out of this?

lispyclouds 2023-11-16T20:28:28.754579Z

if they have the same keys the last one will be there

borkdude 2023-11-16T20:28:45.333439Z

sure

lispyclouds 2023-11-16T20:28:59.284869Z

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"]
    )
)

lispyclouds 2023-11-16T20:29:13.409769Z

Namespace(which_parser_l1='sub1', bar='1', baz='4', which_parser_l2='sub2', dude='2')

borkdude 2023-11-16T20:29:27.547819Z

huh, weird

lispyclouds 2023-11-16T20:29:36.106669Z

even though i wanted baz as the second thing

borkdude 2023-11-16T20:29:50.709609Z

but how do you get stuff out of this? is this data-ish?

lispyclouds 2023-11-16T20:30:57.450659Z

res = parser.parse_args(
    ["sub1", "--bar", "1", "--baz", "2", "sub2", "--dude", "2", "--baz", "4"]
)

print(vars(res))

lispyclouds 2023-11-16T20:31:06.061789Z

this gives you a normal dict

borkdude 2023-11-16T20:31:55.582969Z

it lumps all the options in one dict? I thought you would be able to get the opts out per subcommand or so

lispyclouds 2023-11-16T20:32:13.630619Z

doesnt seem like it

borkdude 2023-11-16T20:32:44.292389Z

ok, and how do normal python people get data out of this, without calling "vars"?

lispyclouds 2023-11-16T20:33:02.387759Z

res.arg_name

lispyclouds 2023-11-16T20:33:26.546739Z

lemme read a bit more about nested things, i could be missing something

borkdude 2023-11-16T20:33:43.630249Z

TypeError: 'Namespace' object is not subscriptable
👍

borkdude 2023-11-16T20:33:55.255739Z

oh sorry, I just meant the thumbs up

borkdude 2023-11-16T20:33:58.959269Z

ignore the error

lispyclouds 2023-11-16T20:40:08.388179Z

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.

lispyclouds 2023-11-16T20:40:59.166859Z

all things following which_parser_l1 til which_parser_l2 are args to it

lispyclouds 2023-11-16T20:42:21.496989Z

dicts in python maintain insertion order by default so that works too i suppose

lispyclouds 2023-11-16T20:43:32.053839Z

for k, v in vars(res).items():
    print(k, v)

borkdude 2023-11-16T20:45:44.530809Z

ok, still conflicts between the option keys, but it is possible to distuingish which group stuff was added to, got it

borkdude 2023-11-16T20:46:03.925829Z

thanks for digging into this

👍🏾 1
lispyclouds 2023-11-16T20:47:16.008989Z

lemme see what people say about conflicting option keys

borkdude 2023-11-16T20:48:55.826779Z

yeah, like

--debug true sub1 --debug false sub2 --debug true

lispyclouds 2023-11-16T20:59:34.964039Z

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)

lispyclouds 2023-11-16T20:59:51.320069Z

Namespace(which_parser_l1='sub1', bar='1', baz='2', which_parser_l2='sub2', dude='2', sub_baz='4')

👍 1