ConfigArgParse
ConfigArgParse copied to clipboard
Adding a sub command appears to cause config file to be ignored
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?
+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.
I found out that you need to :
- set the parser_class parameter on add_subparsers() method,
- use the
add_argumenton 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.
@AdamLenda is this ticket still open for you?
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.
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.
I would expect that config file sections (which are currently ignored) correspond to subcommands.
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
I would expect that config file sections (which are currently ignored) correspond to subcommands.
Yes! That is exactly how I thought it would work.