Parseļ
This is intended to be a gentle introduction to Parser
, a command-line parsing class based on argparse.
Optional arguments can be added to commands using the quo.parse.Parser
.
Optional arguments in Quo are profoundly configurable and ought not to be mistaken for positional arguments.
- Parameters
filename
(str) - The name of the file to open (or'-'
for stdin/stdout).prog
- The name of the program (default:os.path.basename(sys.argv[0])
)color
(bool) - Print a colorful help outputusage
- A usage message (default: auto-generated from arguments)description
- A description of what the program doesepilog
- Text following the argument descriptionsargument_default
- The default value for all argumentsadd_help
(bool) - Add a -h/-help optionallow_abbrev
(bool)- Allow long options to be abbreviated unambiguouslyexit_on_error
(bool) - Determines whether or not ArgumentParser exits with error info when an error occurs
How to name Optional Arguments
ļ
For the purpose of uniformity, a name is chosen in the following order
In the event that the name is not prefixed with ā or -, it will be considered a positional argument.
If there is more than one name prefixed with ā or -, the first one given is used as the name.
The basicsļ
Let us start with a very simple example which does (almost) nothing:
from quo.parse import Parser
arg = Parser()
arg.parse()
Following is a result of running the code:
python example1.py --help
python example1.py --verbose
Running the script without any options results in nothing displayed to stdout. Not so useful.
The second one starts to display the usefulness of Parser
. We have done almost nothing, but already we get a nice help message.
The āhelp option, which can also be shortened to -h, is the only option we get for free (i.e. no need to specify it). Specifying anything else results in an error. But even then, we do get a useful usage message.
from quo.parse import Parser
optional = Parser()
optional.argument("--verbosity", help="Increase the verbosity")
arg = optional.parse()
if arg.verbosity:
print("Verbosity turned on")
python example2.py --verbosity 1
python example2.py --help
python example2.py --verbosity
The program above is written so as to display something when āverbosity is specified and display nothing when not specified. To show that the option is actually optional, there is no error when running the program without it.
Note
By default, if an optional argument isnāt used, the relevant variable, in this case argsverbosity, is given None as its value.
When using the optional argument in this case āverbosity option, one must also specify some value, any value.
The above example accepts arbitrary integer values for āverbosity, but for our simple program, only two values are actually useful, True or False. Letās modify the code accordingly:
from quo.parse import Parser
optional = Parser()
optional.argument("--verbose", help="Increase the verbosity", action="store_true")
arg = optional.parse()
if arg.verbose:
print("Verbosity turned on")
And the output:
python example2.py --verbose
python example2.py --verbose 1
python example2.py --help
Here is what is happening:
The option is now more of a flag than something that requires a value. We even changed the name of the option to match that idea. Note that we now specify a new keyword, action, and give it the value āstore_trueā. This means that, if the option is specified, assign the value True to arg.verbose. Not specifying it implies False.
It complains when you specify a value, in true spirit of what flags actually are.
Notice the different help text.
Short optionsļ
If you are familiar with command line usage, you will notice that I havenāt yet touched on the topic of short versions of the options. Itās quite simple:
from quo.parse import Parser
optional = Parser()
optional.argument("-v", "--verbose", help="Increase the verbosity", action="store_true")
arg = optional.parse()
if arg.verbose:
print("Verbosity turned on")
And here goes:
python example3.py -v
/image/
python example3.py --help
/image/
Note that the new ability is also reflected in the help text.
import argparse The help message is a bit different.
Positional Argumentsļ
Introducing Positional arguments An example:
from quo.parse import Parser
positional = Parser()
positional.argument("echo")
arg = positional.parse()
print(arg.echo)
Note however that, although the help display looks nice and all, it currently is not as helpful as it can be. For example we see that we got echo as a positional argument, but we donāt know what it does, other than by guessing or by reading the source code. So, letās make it a bit more useful:
from quo.parse import Parser
positional = Parser()
positional.argument("echo", help="echo the string you use here")
arg = positional.parse()
print(arg.echo)
-h, --help show this help message and exit
Now, how about doing something even more useful:
from quo.parse import Parser
positional = Parser()
positional.argument("square", help="display a square of a given number")
arg = positional.parse()
print(arg.square**2)
Following is a result of running the code:
python prog.py 4
That didnāt go so well. Thatās because Parser
treats the options we give it as strings, unless we tell it otherwise. So, letās tell it to treat that input as an integer:
from quo.parse import Parser
positional = Parser()
positional.argument("square", help="display a square of a given number", type=int)
arg = positional.parse()
print(arg.square**2)
Following is a result of running the code:
python prog.py 4
16
how about thisā¦
python prog.py four
That went well. The program now even helpfully quit on illegal input before proceeding.
Combining Positional and Optional argumentsļ
Our program keeps growing in complexity
from quo.parse import Parser
parser = Parser()
parser.argument("square", type=int, help="display a square of a given number")
parser.argument("-v", "--verbose", action="store_true", help="increase output verbosity")
arg = parser.parse()
answer = arg.square**2
if args.verbose:
print(f"the square of {arg.square} equals {answer}")
else:
print(answer)
And now the output:
python prog.py
python3 prog.py 4 --verbose
Note that the order does not matter. The above program can be written like so:
python3 prog.py --verbose 4
How about we give this program of ours back the ability to have multiple verbosity values, and actually get to use them:
from quo.parse import Parser
parser = Parser()
parser.argument("square", type=int, help="display a square of a given number")
parser.argument("-v", "--verbosity", type=int, help="increase output verbosity")
arg = parser.parse()
answer = arg.square**2
if arg.verbosity == 2:
print(f"the square of {arg.square} equals {answer}")
elif arg.verbosity == 1:
print(f"{arg.square}^2 == {answer}")
else:
print(answer)
And the output:
python prog.py 4
$ python3 prog.py 4 16
python prog.py 4 -v
$ python3 prog.py 4 -v usage: prog.py [-h] [-v VERBOSITY] square prog.py: error: argument -v/āverbosity: expected one argument
python prog.py 4 -v 1
python prog.py 4 -v 2
python prog.py 4 -v 3
These all look good except the last one, which exposes a bug in our program. Letās fix it by restricting the values the --verbosity
option can accept:
from quo.parse import Parser
parser = Parser()
parser.argument("square", type=int, help="display a square of a given number")
parser.argument("-v", "--verbosity", type=int, choices=[0, 1, 2], help="increase output verbosity")
arg = parser.parse()
answer = arg.square**2
if arg.verbosity == 2:
print(f"the square of {arg.square} equals {answer}")
elif arg.verbosity == 1:
print(f"{arg.square}^2 == {answer}")
else:
print(answer)
And the output:
python prog.py 4 -v 3
Note that the change also reflects both in the error message as well as the help string. .. code:: console
python prog.py 4 -h
Now, letās use a different approach of playing with verbosity, which is pretty common. It also matches the way the CPython executable handles its own verbosity argument (check the output of python āhelp):
from quo.parse import Parser
parser = Parser()
parser.argument("square", type=int, help="display a square of a given number")
parser.argument("-v", "--verbosity", action="count", help="increase output verbosity")
arg = parser.parse()
answer = arg.square**2
if arg.verbosity == 2:
print(f"the square of {arg.square} equals {answer}")
elif arg.verbosity == 1:
print(f"{arg.square}^2 == {answer}")
else:
print(answer)
We have introduced another action, count
, to count the number of occurrences of specific options.
python prog.py 4
python prog.py 4 -v
python prog.py 4 -vv
python prog.py 4 -v 1
Grouping conflicting optional argumentsļ
group()
allows us to specify options that conflict with each other. Letās also change the rest of the program so that the new functionality makes more sense: weāll introduce the --quiet
option, which will be the opposite of the --verbose
one.
from quo.parse import Parser
parser = Parser()
group = parser.group()
group.argument("-v", "--verbose", action="store_true")
group.argument("-q", "--quiet", action="store_true")
parser.argument("x", type=int, help="the base")
parser.argument("y", type=int, help="the exponent")
arg = parser.parse()
answer = arg.x**arg.y
if arg.quiet:
print(answer)
elif arg.verbose:
print(f"{arg.x} to the power {arg.y} equals {answer}")
else:
print(f"{arg.x}^{arg.y} == {answer}")
Our program is now simpler, and weāve lost some functionality for the sake of demonstration. Anyways, hereās the output
python prog.py 4 2
Ouput:
4^2 == 16
$ python prog.py 4 2 -q
Output:
16
$ python3 prog.py 4 2 -v
Ouput:
4 to the power 2 equals 16
$ python prog.py 4 2 -vq
That should be easy to follow. Iāve added that last output so you can see the sort of flexibility you get, i.e. mixing long form options with short form ones.
Before we conclude, you probably want to tell your users the main purpose of your program, just in case they donāt know
from quo.parse import Parser
parser = Parser(description="calculate X to the power of Y")
group = parser.group()
group.argument("-v", "--verbose", action="store_true")
group.argument("-q", "--quiet", action="store_true")
parser.argument("x", type=int, help="the base")
parser.argument("y", type=int, help="the exponent")
arg = parser.parse()
answer = arg.x**arg.y
if arg.quiet:
print(answer)
elif arg.verbose:
print("{} to the power {} equals {}".format(arg.x, arg.y, answer))
else:
print("{}^{} == {}".format(arg.x, arg.y, answer))
Note that slight difference in the usage text. Note the [-v | -q], which tells us that we can either use -v or -q, but not both at the same time
python prog.py --help