how can I make subparsers be required? [duplicate] - python

This question already has answers here:
Argparse with required subparser
(2 answers)
Closed 3 years ago.
I would like to make sure at least one of the sub commands is selected. But there is no required option for add_subparsers() how can I enforce at least one subparser is selected?
Currently I did this to mimic the effect:
subparsers = parser.add_subparsers(
title='sub commands',
help='valid sub commands',
)
subparser1 = subparsers.add_parser('subcmd1')
subparser1.set_defaults(which_subcmd='subcmd1')
subparser2 = subparsers.add_parser('subcmd2')
subparser2.set_defaults(which_subcmd='subcmd2')
parsedargs = parser.parse_args()
if 'which_subcmd' not in parsedargs:
parser.print_help()
But I want an official way to do this and make the help content display something like {subcmd1 | subcmd2}
Update:
according to #hpaulj, in 3.7 there is required option. But I want some work around can work in python 3.5 and 3.6

Instead of printing help, I would prefer to raise an error:
if which_subcmd not in parsedargs:
msg = "Subcommands needed: subcmd1, subcmd2"
raise argparse.ArgumentTypeError(msg)
This way is more consistent with other argparse errors. But just a matter of taste. I don't see anything wrong on your approach as long as you exit from your script after that print_help() statement.

Related

Looking to set a global default argument with argparse [duplicate]

This question already has answers here:
Display help message with Python argparse when script is called without any arguments
(18 answers)
Closed 3 years ago.
I am writting a new script and would like for the -h or --help argument to be called by default when the script is called without any parameters. So for example if someone calls command_line_utility.py then I want it to print the output you would get with command_line_utility.py -h.
I have dug around in the docs and looked at some examples, but all of them were specifying default argument values and not actually having arg parse call a default argument.
# Setting up Main Argument Parser
main_parser = argparse.ArgumentParser(description="A set of python web utility scripts")
main_parser.add_argument("-v",'--version', action='version', version='kuws V0.0.1')
# Setting up the main subparser
subparsers = main_parser.add_subparsers(help="Available commands found below, for more info on a command use: python command_line_utility.py <command> -h or kuws <command> -h")
"""Code below handles 'redirects' command in the main script
i.e. >python command_line_utility.py redirects or kuws redirects
"""
redirects_parser = subparsers.add_parser('redirects', argument_default='-u',
help='Allows you to trace redirects and get other information')
redirects_parser.add_argument('-u', "--url",
help='usage: python main.py redirects -u <url>; Lets you see the trace for a url', nargs='?', dest="trace_url")
As it stands when I run the file nothing actually gets printed to the command line. No help text or errors or anything.
I'm afraid argparse doesn't have any built-in support for this, but you can identify this situation and print the help message:
import sys
if len(sys.argv)==1:
parser.print_help(sys.stderr)
sys.exit(1)
Checking that len(sys.argv)==1 and in that case calling the print_help method of the parser as described in this answer to a similar question is a possible way to print the help message defined in the parser when no arguments are given.
When using subparsers, a common scheme is using set_defaults(func=<function to be called>) and then calling this function (as explained in sub-commands).
You can simply define a first set_defaults(func=help) at first that will be overwritten with the functions of your command.
Note that you can also make the command required when you declare your subparsers (add_subparsers(..., required='True')) and thus, when the user invokes without a command, she will get an error with the usage.

Print all argparse arguments including defaults

I want to log the usage of a python program which uses the argparse module. Currently, the logger records the command line usage similar to the answer given in this post. However, that only gives the command line arguments, and not including the defaults set later in argparse (which is the intended use, after all). Is there a simple way to print ALL the argparse options to create a nice, tidy usage log entry that includes the default values?
It isn't difficult to go into the argparse namespace to fetch each argument by name, but I am hoping that someone has a concise way of extracting the needed info.
In response to the accepted answer:
Great! If anyone is interest, here is my implementation with logging:
logger.info("Usage:\n{0}\n".format(" ".join([x for x in sys.argv])))
logger.debug("All settings used:") for k,v in sorted(vars(args).items()):
logger.debug("{0}: {1}".format(k,v))
I've done something similar in an application, hopefully the below snippets give you what you need. It is the call to vars that gave me a dictionary of all the arguments.
parser = argparse.ArgumentParser(description='Configure')
....
args = parser.parse_args()
......
options = vars(args)

How to have two independent groups [duplicate]

This question already has answers here:
Python argparse mutual exclusive group
(4 answers)
Closed 6 years ago.
My program has two functionalities. One is run without any arguments, and the other can have optional arguments. The groups can't interfere with each other.
import argparse
parser = argparse.ArgumentParser()
root_group = parser.add_mutually_exclusive_group()
group_export = root_group.add_argument_group()
group_export.add_argument('--export', action='store_true', help='Exports data from database')
group_export.add_argument('-l', action='append', help='Reduce output with league name')
group_export.add_argument('-d', action='append', help='Reduce output with date range')
group_run = root_group.add_argument_group()
group_run.add_argument('--run', action='store_true', help='Start gathering of data')
I want this to be allowed:
python file.py --export -l name1 -l name2 -d 1/1/2015
python file.py --export
python file.py --run
And this to be not allowed:
python file.py --run --export # Namespace(d=None, export=True, l=None, run=True)
python file.py --run -l name1 # Namespace(d=None, export=False, l=['name1'], run=True)
However, as on now neither of the disallowed operations rises an error, as indicated by the comments.
Argument groups don't nest inside a mutually exclusive group. Despite the names, the two kinds of groups have different purposes.
Argument groups group arguments in the help display. They do nothing during parsing.
Mutually exclusive groups test the occurrence of arguments, and try to display that in the usage line.
You could make --export and --run mutually exclusive. But it won't block the use of l or d with run. But you could just ignore those values. Or you could do your own tests after parsing, and complain that the point.
What would be a meaningful way of representing this constrain in the usage line? You may need to customize that.
Another possibility is to use subparsers. That might fit your case better. The 'export' parser would define the arguments that work with that. The 'run' would not accept any further arguments.
In one way or other this has been discussed in other argparse questions. The sidebar seems to have found some possible matches.

Mutually exclusive groups of arguments? [duplicate]

This question already has answers here:
Python argparse mutual exclusive group
(4 answers)
Closed 6 years ago.
I have a single Python file which includes unit tests in the source code. It works like this:
parser = argparse.ArgumentParser()
parser.add_argument('--test', action='store_true', help="Run unit tests and return.")
args = parser.parse_args()
if args.test:
testsuite = unittest.TestLoader().loadTestsFromTestCase(SanitizeTestCase)
unittest.TextTestRunner(verbosity=1).run(testsuite)
If args.test is false, the program runs as expected. I don't want to have to make this into an entire setuptools project, it's a pretty simple script with some unit tests to evaluate that it does what it's supposed to.
I now find myself needing to parse other arguments, and that's where things start to fall apart. --test is a mutually exclusive parameter and all of the other parameters don't apply if --test is passed.
Is there a way to have mutually-exclusive argument groups in argparse?
There is a mutually exclusive group mechanism, but all the arguments in that group are mutually exclusive. You can't say, --test xor any of the other others.
But such a group doesn't do anything profound. It adds some markings to the usage line (try it), and it complains when your user (yourself?) violates the exclusivity.
You can do the same things yourself, and fine tune them. You can give the parser a custom usage line. And after parsing you can choose to ignore conflicting values, or you can choose to raise your own error message (parser.error('dumb user, cant you read ...?')). You could, for example, ignore all the other arguments, regardless of value, if this args.test is True.

Subparser -- show help for both parser and subparser

I've looked through dozens of similar SO questions but haven't find suitable solutions so please forgive me in case of a dublicate.
I have a problem similar to this one
I want to have a parser+subparser pair, with --help option causing help being shown for the both if subparser is "activated".
The only way I was able to get full (parser + subparser) help is:
common_parser = argparse.ArgumentParser(add_help=False)
common_parser.add_argument('-c', required = True)
parser = argparse.ArgumentParser(parents=[common_parser])
subparsers = parser.add_subparsers(dest="sub")
subparser = subparsers.add_parser("sub_option", parents=[common_parser])
subparser.add_argument('-o', required = False)
settings = parser.parse_args()
But then script requires the -c option to be entered twice (apparently for parser and subparser). If I don't use parents then I get normal behaviour but I don't the help I get for subparser contains only -o description (I want also -c to be shown)
P.S. Python 2.7
For a start let's distinguish between parsing behavior and help display.
I assume you have multiple subparsers (otherwise why use the subparser mechanism). -o is an argument specific to sub_option, and presumably the other subparsers have their own arguments.
What is the purpose of -c? Is it something that is common to all subparsers? Since subparsers are required, it doesn't make sense to talk about an argument that only matters to the main parser.
One way to deal with a common argument is to define it for all subparsers. The parents mechanism that you use saves you a bit of typing. Just omit it from the main parser definition. That gets rid of the problem with having to supply it twice.
If -c is defined for all the subparsers, then there isn't a need to show it in the main parser help, is there?
The whole subparser mechanism is cleanest when the subparser command is the 1st argument string, with all of its arguments, positionals and options following. It's possible to define arguments for the main parser, but it often complicates both use and help.
The issue of display the help for both the main parser and (all) the subparsers has come up before, both on SO, and on the python bug/issues. There isn't a simple solution. Some tools that may help are:
generate help under program control with parser.print_help(), and subparse.print_help().
add_subparsers() command takes parameters like prog, title and description which can be used to control the help, including the usage of the subparser help.
add_subparser() takes the same sort of parameters as ArgumentParser (since it defines a parser), description and usage may be useful.
Looking a previous question
How to show help for all subparsers in argparse?
I realized that if -c is not required, it can be defined for both the main and subparser, and appear as expected in the helps. But by making it 'required', both parsers have to see it - but only the value seen by the subparser appears in the namespace.
Also positionals defined in the main parser appear in the subparser usage.
Another subparsers help display question
argparse subparser monolithic help output
http://bugs.python.org/issue20333 argparse subparser usage message hides main parser usage discusses the question of how much of main parser usage should show up in the subparse usage line. Currently just positionals (defined before the subparsers) show up. In the patch I suggest adding required optionals as well. But you can always fudge this by defining your own prog for subparsers.

Categories

Resources