chriskiehl / Gooey

Turn (almost) any Python command line program into a full GUI application with one line
MIT License
20.56k stars 1.01k forks source link

Missing arguments in GUI with subparsers #796

Open m-ad opened 2 years ago

m-ad commented 2 years ago

Hi all,

when I have an ArgumentParser with subparsers, the ArgumentParsers arguments are ignored by Gooey.

Here is a short example:

import argparse
from gooey import Gooey

@Gooey()
def main():
    mainparser = argparse.ArgumentParser()
    mainparser.add_argument(
        "-s", "--size",
        type=int,
        help="size of the drink")
    subparsers = mainparser.add_subparsers(
        dest='subparser_name',
        help="Choose your drink"
        )
    parser_milk = subparsers.add_parser(
        name='milkshake',
        help='tasty milkshake')
    parser_fruit = subparsers.add_parser(
        name='smoothy',
        help='fruity smoothy')
    parser_milk.add_argument(
        "-m", "--milk",
        type=str,
        required=True,
        choices=["cow", "goat", "soybean", "almond"],
        help="Choose your type of milk")
    parser_fruit.add_argument(
        "-f", "--fruit",
        choices=["banana", "strawberry", "cherry", "apple"],
        required=True,
        help="Choose the fruit")
    args = mainparser.parse_args()
    print(args)

main()

My issue here is with the --size argument. Without Gooey, I can call this code with --size 2 milkshake -m almond and get Namespace(milk='almond', size=2, subparser_name='milkshake') in return. With Gooey, there is no way to input the --size argument and it is always None.

image

In short: Expected behaviour: I can select --size in the GUI, for both milkshakes and smoothies. Actual behaviour: There is no widget for --size in the GUI.

Why does this matter? In my actual code, I have multiple subparsers with multiple common arguments, like --size in the example. Duplicating these common arguments for each subparser instead of keeping them in the main ArgumentParser would be one solution, but it would certainly go against the DRY principle and make messy code.

SamLinoFinnegan commented 2 years ago

Hi, I was having a similar problem, Gooey was ignoring a set of nested sub_parser, I was able to work around it by re-organizing my parsers.

I was able to fix your problem by adding the --size parsers to each sub_parser:

`

import argparse
from gooey import Gooey

@Gooey()
def main():
mainparser = argparse.ArgumentParser()

subparsers = mainparser.add_subparsers(
    dest='subparser_name',
    help="Choose your drink"
)
parser_milk = subparsers.add_parser(
    name='milkshake',
    help='tasty milkshake')
parser_fruit = subparsers.add_parser(
    name='smoothy',
    help='fruity smoothy')
parser_milk.add_argument(
    "-m", "--milk",
    type=str,
    required=True,
    choices=["cow", "goat", "soybean", "almond"],
    help="Choose your type of milk")
parser_milk.add_argument(
    "-s", "--size",
    type=int,
    help="size of the drink")
parser_fruit.add_argument(
    "-f", "--fruit",
    choices=["banana", "strawberry", "cherry", "apple"],
    required=True,
    help="Choose the fruit")
parser_fruit.add_argument(
    "-s", "--size",
    type=int,
    help="size of the drink")
args = mainparser.parse_args()
print(args)

main()

`

m-ad commented 2 years ago

Thanks for the workaround suggestion @SamLinoFinnegan! I was aware of that possibility:

Duplicating these common arguments for each subparser instead of keeping them in the main ArgumentParser would be one solution, but it would certainly go against the DRY principle and make messy code.

With just a few more arguments and subparsers than in the toy example the workaround gets messy quickly.

ventourist commented 2 years ago

I'm facing the same limitation, and agree with @m-ad to go for DRY coding. Hopefully a future improvement?

AlphonsG commented 2 years ago

This may be a potential solution:

@Gooey(tabbed_groups=True, navigation='Tabbed')
def main():
    parser = GooeyParser()
    parser.add_argument('command', type=str, choices=['subcommand1', 'subcommand2'])
    parser.add_argument("file")  # required common argument
    parser.add_argument('--foo', action='store_true',
                        help='Option one')  # optional common argument

    group1 = parser.add_argument_group('subcommand1', description='subcommand2')  # subcommand
    group1.add_argument('--goo', action='store_true')

    group2 = parser.add_argument_group('subcommand2', description='subcommand2')  # subcommand
    group2.add_argument('--boo', action='store_true')

    args = parser.parse_args()

May also solve https://github.com/chriskiehl/Gooey/issues/574, https://github.com/chriskiehl/Gooey/issues/274 and the error "Gooey doesn't currently support top level required arguments when subparsers are present."