ConfigArgParse icon indicating copy to clipboard operation
ConfigArgParse copied to clipboard

Adding a sub command appears to cause config file to be ignored

Open AdamLenda opened this issue 7 years ago • 8 comments

Reproduce Bug

python source

import configargparse
def example():
    parser = configargparse.ArgumentParser(prog="test")
    parser.add_argument(
        '-e',
        '--environments',
        type=str,
        dest='environments',
        metavar='Environment',
        choices=['dev', 'test', 'beta', 'prod'],
        action='append',
        nargs='?',
        required=True,
        help="List of deployment environments to prepare"
    )
    parser.add_argument(
        '-s',
        '--solution_path',
        type=str,
        dest='solution_path',
        metavar='Solution Path',
        required=True,
        nargs='?',
        help='Path to the root of the application source files'
    )
    parser.add_argument(
        '-c',
        '--config',
        dest='my--config',
        is_config_file=True,
        nargs='?',
        help='Config file path'
    )
    command_subparsers = parser.add_subparsers(title='Commands', dest='command', required=True)
    command_subparsers.add_parser('help', help="Prints this screen")
    args = parser.parse_known_args()
    print(args)

if __name__ == '__main__':
    example()

my-config.conf source

environments = [test, beta]
solution_path = /var/PhotApp

command

$ python3 -m my-module -c ../my-config.conf help

output:

usage: test [-h] -e [Environment] -s [Solution Path] [-c [MY--CONFIG]]
            {help} ...
test: error: the following arguments are required: -e/--environments, -s/--solution_path

Bypass Bug

comment out these lines

    command_subparsers = parser.add_subparsers(title='Commands', dest='command', required=True)
    command_subparsers.add_parser('help', help="Prints this screen")

run w/ sub command

$ python3 -m my-module -c ../my-config.conf

output

(Namespace(environments=['test', 'beta'], solution_path='/var/PhotApp', **{'my--config': '../my-config.conf'}), [])

Questions

It seems to me that adding a subcommand breaks configuration parsing.

Can anyone show me why this isn't a bug?

AdamLenda avatar Sep 17 '18 06:09 AdamLenda

+1 Same problem for me indeed. I'm trying to track down the problem in the code but addind a sub parser definitively breaks something.

ronhanson avatar Oct 22 '18 16:10 ronhanson

I found out that you need to :

  • set the parser_class parameter on add_subparsers() method,
  • use the add_argument on your command "sub" parser, not on the parent one,
  • also add a config argument on your "sub" parser, as otherwise it won't accept config files.

To summarize, adding a subparser needs reconfiguring everything you did to the parent parser.

Also to use config file in your sub parser, you also need to do :

command_subparsers = parser.add_subparsers(parser_class=configargparse.ArgParser)
subparser = command_subparsers.add_parser('mycommand', help="Launch mycommand")
subparser.add_argument(
        '-e',
        '--environments',
        type=str,
        dest='environments',
        metavar='Environment',
        choices=['dev', 'test', 'beta', 'prod'],
        action='append',
        nargs='?',
        required=True,
        help="List of deployment environments to prepare"
    )
subparser.add_argument(
        '-s',
        '--solution_path',
        type=str,
        dest='solution_path',
        metavar='Solution Path',
        required=True,
        nargs='?',
        help='Path to the root of the application source files'
    )
subparser.add_argument(
        '-c',
        '--config',
        dest='my--config',
        is_config_file=True,
        nargs='?',
        help='Config file path'
    )

Also, add_parser command takes same **kwargs as in configargparse.ArgParser(**kwargs), so you should specify the same parameters to this command as well. I advise you to put all your arguments in a dict and pass your dict (unpacked) to constructor and unpacked to add_parser as kwargs.

Hope this helps.

ronhanson avatar Oct 23 '18 12:10 ronhanson

@AdamLenda is this ticket still open for you?

ronhanson avatar Jan 31 '19 15:01 ronhanson

While the above solution does seem to work, this ends up necessitating multiple config files - one for the main parser, and then one for each of the subparsers - and multiple, unique arguments for the config file. This doesn't seem ideal to me in that the config can't all be read from one file. If any config file has arguments not related to its particular parser, you end up with

error: unrecognized arguments: [...]

At least for me, what would make most intuitive sense is that the config file for the main parser applies any argument values relevant to subparsers.

Aetylus avatar Jul 01 '20 14:07 Aetylus

Being able to specify everything from within one big configuration file would be really helpful and much easier to handle from a user point of view.

wonkoRT avatar Nov 11 '20 16:11 wonkoRT

I would expect that config file sections (which are currently ignored) correspond to subcommands.

moi90 avatar May 16 '21 07:05 moi90

bump! not having to use different configuration files per subcommand would be nice (or enable ignore_unknown_args)

also, propagating auto_env_var_prefix and default_config_files from main configargparse.ArgParser to the subparsers (so we don't have to specify it on every subparsers.add_parser) would be really nice

fopina avatar Jun 30 '22 00:06 fopina

I would expect that config file sections (which are currently ignored) correspond to subcommands.

Yes! That is exactly how I thought it would work.

tedhenry100 avatar May 26 '23 15:05 tedhenry100