I am using argparse to parse user args. There are defaults provided for each argument, but due to my special need, I would need to also get a list of args that are specified by the user.
Example:
parser = argparse.ArgumentParser(description="Generic Program")
parser.add_argument('-a', type=int, default=1, )
parser.add_argument('-b', type=int, default=2, )
parser.add_argument('-c', type=int, default=3, )
args = parser.parse_args()
Calling:
main.py -a 1 -b 2
I would like to know that the user actually only specified -a and -b but not -c. I cannot seem to see how that is done through the argparse official docs. Using sys.argv would've been too low level and too messy to deal with the raw parsing.
Don't supply a default. You can set the value to 3 once you have determined that it was unset. This adds more work for you, but it seems like the easiest way to do what you are asking.
Related
How can I make it a required argument only if I don't select another option, so when I select version it shouldn't require -f, but the rest of the time it should be required?
parser = argparse.ArgumentParser(
description="This script will check the uri's from XXX")
parser.add_argument(
"-f", "--file", help="XXX export file to use", required=True)
parser.add_argument("-c", "--check", action="store_true",
help="Check the uri's")
parser.add_argument("-p", "--passwords", action="store_true",
help="Check the weak passwords")
parser.add_argument("-V", "--version", action="store_true",
help="Show version")
self.params = parser.parse_args(self.get_params())
So, two things:
In the general case, this is done with add_mutually_exclusive_group(required=True) and adding the mutually exclusive arguments to that group (this isn't exactly what you want, since it won't allow you to pass both, but it's close enough).
In this specific case, you should be using the action='version' action for displaying the version, which exists specifically for this purpose, and leave -f plain required=True as you've already written it.
I've read the documentation but still can't figure out how to achieve the following behavior:
1.likes. Give a specified number of likes to users in a tinder (in the future, this may contain more options, such as "gender", "frequency", "age", etc.)
2. Write a given text to a given number of people on tinder (in the future, there may also be more options).
There is my code:
parser = argparse.ArgumentParser(description='Badoo liker', epilog='Enjoy the program! :)')
# I also tried "add_mutually_exclusive_group" instead of "add_argument_group"
chat_args = parser.add_argument_group(title='chat_args')
chat_args.add_argument('-c', '--chat', help='chat help')
chat_args.add_argument('-t', '--text', help='text help')
chat_args.add_argument('-n', '--number', help='n help')
like_args = parser.add_argument_group(title='like_args')
like_args.add_argument('-l', '--like', help='like help')
like_args.add_argument('-n', '--number', help='n help')
args = parser.parse_args()
Usage:
$script.py chat --text 'Hello world' -n 20 # Var 1
$script.py liking -n 20 # Var 2
Obviously, I'm waiting for arguments either for a chat or either for liking
P.S. I'm getting an error because of -n common argument, but even if comment it it will not working as expecting
It's a little hard to tell what you understand and what has worked or not for you.
This is more of a comment, but long enough that I'll make it answer.
Are those usage lines samples of what you use when calling this script? What error(s) do you get?
Have you tried scipt.py -h to see the help?
I don't see a positional argument that would accept a string like "chat" or "liking". I suspect you want to use the subcommands mechanism, but get the basic argparse working.
I often suggest including a print(args) line to get a clear idea of what the parser has done. Though obviously you won't see that while argparse is raising errors.
Postpone the use of groups until you get the basics down. argument_group just groups arguments in the help display. mutually_exclusive_group is a parsing tool, that complains if you try to use more than one item in the group.
Eventually, I did it, the next code is (apparently) meets my question
# "metavar=''" -just hide redundant double --key KEY word
parser = argparse.ArgumentParser(description='Badoo liker', epilog='Enjoy the program! :)')
subparsers = parser.add_subparsers(help='')
parser_like = subparsers.add_parser('like', help='like help')
parser_like.add_argument('-n', '--number', metavar='', help='Set count of likes', default=49)
parser_like.add_argument('-f', '--frequency', metavar='', help='Set chance to like/dislike', default=70)
parser_chat = subparsers.add_parser('chat', help='chat help')
parser_chat.add_argument('-n', '--number', metavar='', help='number help', required=True)
parser_chat.add_argument('-t', '--text', metavar='', help='text help', required=True)
args = parser.parse_args()
I'm writing a program that can either take one flag-argument --list OR two or more positional arguments SOURCE [SOURCE ...] DESTINATION. Ideally with when SRC/DST is used it should also accept --recursive but that can be a global option simply ignored with --list.
For now I have this:
group = parser.add_argument_group('Source / Dest Selection')
group.add_argument('--list', action="store_true")
group.add_argument('--recursive', action="store_true")
group.add_argument('SOURCE', nargs='+')
group.add_argument('DESTINATION')
However it always requires SOURCE and DESTINATION. I don't want to make each optional, instead I would like to either require both SRC and DST or none of them and then require --list.
I would also settle for both or none of SRC/DST and simply ignore them if --list was used.
Any idea how to express that with argparse? Thanks!
Very hackish but you could use multiple parsers. May be something like:
import argparse
parser1 = argparse.ArgumentParser()
parser1.add_argument('--list', action="store_true")
parser1.add_argument('DUMMY_POSITIONAL', nargs='*')
args1 = parser1.parse_args()
if not args1.list:
parser2 = argparse.ArgumentParser()
parser2.add_argument('SOURCE', nargs='+')
parser2.add_argument('DESTINATION')
args2 = parser2.parse_args()
if len(args2.SOURCE) == 0:
print("Must specify SOURCE")
else:
print(args2.SOURCE, args2.DESTINATION)
I've read through quite a few tutorials, questions and documentation and could not figure out how to achieve this:
prog.py [-h] [-d DEVICE -l | (-m M -s S -p P)]
When using the -l argument, prog.py reads from a device interface. When providing -m, -s and/or -p, prog.py writes to that interface. Reading and writing is not possible at the same time, so reading and writing arguments are mutually exclusive.
Once DEVICE has been specified, either -l or at least one of -m, -s or -p needs to be provided, it should also be possible to provide any combination of those three.
So far I approached this problem from various angles:
I tried mutually exclusive groups which do not work as only single arguments can mutually exclude each other (please correct me if I'm wrong)
I tried to set up sub parsers but I failed...
This is what I tried last:
import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument("-d","--device",
default="system",
help="foo")
subparsers = parser.add_subparsers(help='foo')
read_parser = subparsers.add_parser('read', help='foo')
read_parser.add_argument("-l", "--list",
action="store_true")
write_parser = subparsers.add_parser("write", help="bar")
write_parser.add_argument("-m","--mode",
type=str,
choices=["on","off","auto"],
help="foo")
write_parser.add_argument("-s", "--season",
type=str,
choices=["winter","summer"],
help="foo")
write_parser.add_argument("-p","--present",
type=int,
choices=[0,1],
help="foo")
parser.parse_args()
This is not even close as with subparsers argparse expects either read or write. What I need to do is add groups that are mutually exclusive. Anyone has an idea of how to solve this?
You can check on your own (with basic argparse functionalities) if correct arguments combination was passed:
parser = argparse.ArgumentParser()
parser.add_argument("-d","--device",
default="system",
help="foo")
parser.add_argument("-l", "--list",
action="store_true")
parser.add_argument("-m","--mode",
type=str,
choices=["on","off","auto"],
help="foo")
parser.add_argument("-s", "--season",
type=str,
choices=["winter","summer"],
help="foo")
parser.add_argument("-p","--present",
type=int,
choices=[0,1],
help="foo")
args = parser.parse_args()
# if user defines device but not any read/write argument raise exception
if args.device is not None and not args.list and all(arg is None for arg in (args.season, args.present, args.mode)):
parser.error('Wrong arguments passed')
# if user defines read and write arguments at the same time raise exception
if args.list and not all(arg is None for arg in (args.season, args.present, args.mode)):
parser.error('Wrong arguments passed')
I am using Argparse on python to do a script on command line. I have this for my script:
parser = argparse.ArgumentParser(prog = 'manageAdam')
parser.add_argument("-s", action='store_true', default=False, help='Shows configuration file')
parser.add_argument("d", type=str, help="device")
parser.add_argument("o", type=str, help="operation")
parser.add_argument("-v", "--value", type=int, nargs='*', help="value or list to send in the operation")
I am looking that if I call manageAdam -s it would work and don't ask for the positional arguments, something like the -h, which can be called without any other positional argument that is defined. Is it possible?
There is no built-in way to do this. You might be able to achieve something by writing some custom Action classes that keep track on the parser about their state, but I believe it will become quite messy and buggy.
I believe the best bet is to simply improve your UI. The -s is not an option. It's a separate command that completely alters how your script executes. In such cases you should use the subparsers functionality which allows to introduce sub-commands. This is a better interface then the one you thought, and is used by a lot of other tools (e.g. Git/mercurial).
In this case you'd have a config command to handle the configuration and a run (or how you want to call it) command to perform the operations on the device:
subparsers = parser.add_subparsers(dest='command')
parser_config = subparsers.add_parser('config', help='Configuration')
parser_run = subparsers.add_parser('run', help='Execute operation on device')
parser_run.add_argument('d', type=str, ...)
parser_run.add_argument('o', type=str, ...)
parser_run.add_argument('-v', type=int, nargs='*', ...)
# later:
args = parser.parse_args()
if args.command == 'config':
print('Configuration')
else:
print('Run operation')
Used from the command line as:
$ manageAdam config
# or
$ manageAdam run <device> <operation> <values...>
No, there are no such way.
You can make all arguments optional and set default value to None then perform check that all of them aren't None otherwise raise argparse.ArgumentError, if manageAdam provided skip check for other arguments.