Basics tutorial¶
Installation¶
You can install clize using pip. If in an activated virtualenv, type:
pip install clize
If you wish to do a user-wide install:
pip install --user clize
A minimal application¶
A minimal command-line application written with clize consists of writing
a function and passing it to run()
:
from clize import run
def hello_world():
return "Hello world!"
if __name__ == '__main__':
run(hello_world)
If you save this as helloworld.py and run it, the function will be run:
$ python3 helloworld.py
Hello world!
In this example, run()
simply takes our function, runs it and prints
the result.
Requiring arguments¶
You can require arguments the same way as you would in any Python function
definition. To illustrate, lets write an echo
command.
from clize import run
def echo(word):
return word
if __name__ == '__main__':
run(echo)
Save it as echo.py and run it. You will notice the script requires exactly one argument now:
$ python3 ./echo.py
./echo.py: Missing required arguments: word
Usage: ./echo.py [OPTIONS] word
$ python3 ./echo.py ham
ham
$ python3 ./echo.py ham spam
./echo.py: Received extra arguments: spam
Usage: ./echo.py [OPTIONS] word
Enhancing the --help
message¶
If you try to specify --help
when running either of the previous examples,
you will notice that Clize has in fact also generated a --help
feature for
you already:
$ python3 ./echo.py --help
Usage: ./echo.py [OPTIONS] word
Positional arguments:
word
Other actions:
-h, --help Show the help
It is fairly unhelpful right now, so we should improve that by giving our function a docstring:
def echo(word):
"""Echoes word back
:param word: One word or quoted string to echo back
"""
return word
As you would expect, it translates to this:
$ python3 ./echo.py --help
Usage: ./echo.py [OPTIONS] word
Echoes word back
Positional arguments:
word One word or quoted string to echo back
Other actions:
-h, --help Show the help
Accepting options¶
Clize will treat any regular parameter of your function as a positional parameter of the resulting command. To specify an option to be passed by name, you will need to use keyword-only parameters.
Let’s add a pair of options to specify a prefix and suffix around each line of
word
:
def echo(word, *, prefix='', suffix=''):
"""Echoes text back
:param word: One word or quoted string to echo back
:param prefix: Prepend this to each line in word
:param suffix: Append this to each line in word
"""
if prefix or suffix:
return '\n'.join(prefix + line + suffix
for line in word.split('\n'))
return word
In Python, any parameters after *args
or *
become keyword-only: When
calling a function with such parameters, you can only provide a value for them
by name, i.e.:
echo(word, prefix='b', suffix='a') # good
echo(word, 'b', 'a') # invalid
Clize then treats keyword-only parameters as options rather than as positional parameters.
The change reflects on the command and its help when run:
$ python3 ./echo.py --prefix x: --suffix :y 'spam
$ ham'
x:spam:y
x:ham:y
$ python3 ./echo.py --help
Usage: ./echo.py [OPTIONS] word
Echoes text back
Positional arguments:
word One word or quoted string to echo back
Options:
--prefix=STR Prepend this to each line in word(default: )
--suffix=STR Append this to each line in word(default: )
Other actions:
-h, --help Show the help
See also
Collecting all positional arguments¶
Just like when defining a regular Python function, you can prefix a parameter with one asterisk and it will collect all remaining positional arguments:
def echo(*text, prefix='', suffix=''):
...
However, just like in Python, this makes the parameter optional. To require
that it should receive at least one argument, you will have to tell Clize that
text
is required using an annotation:
from clize import Parameter, run
def echo(*text:Parameter.REQUIRED, prefix='', suffix=''):
"""Echoes text back
:param text: The text to echo back
:param prefix: Prepend this to each line in word
:param suffix: Append this to each line in word
"""
text = ' '.join(text)
if prefix or suffix:
return '\n'.join(prefix + line + suffix
for line in text.split('\n'))
return text
if __name__ == '__main__':
run(echo)
Accepting flags¶
Parameters which default to False
are treated as flags. Let’s add a flag
to reverse the input:
def echo(*text:Parameter.REQUIRED, prefix='', suffix='', reverse=False):
"""Echoes text back
:param text: The text to echo back
:param reverse: Reverse text before processing
:param prefix: Prepend this to each line in word
:param suffix: Append this to each line in word
"""
text = ' '.join(text)
if reverse:
text = text[::-1]
if prefix or suffix:
return '\n'.join(prefix + line + suffix
for line in text.split('\n'))
return text
$ python3 ./echo.py --reverse hello world
dlrow olleh
Converting arguments¶
Clize automatically tries to convert arguments to the type of the receiving parameter’s default value. So if you specify an inteteger as default value, Clize will always give you an integer:
def echo(*text:Parameter.REQUIRED,
prefix='', suffix='', reverse=False, repeat=1):
"""Echoes text back
:param text: The text to echo back
:param reverse: Reverse text before processing
:param repeat: Amount of times to repeat text
:param prefix: Prepend this to each line in word
:param suffix: Append this to each line in word
"""
text = ' '.join(text)
if reverse:
text = text[::-1]
text = text * repeat
if prefix or suffix:
return '\n'.join(prefix + line + suffix
for line in text.split('\n'))
return text
$ python3 ./echo.py --repeat 3 spam
spamspamspam
Aliasing options¶
Now what we have a bunch of options, it would be helpful to have shorter names for them. You can specify aliases for them by annotating the corresponding parameter:
def echo(*text:Parameter.REQUIRED,
prefix:'p'='', suffix:'s'='', reverse:'r'=False, repeat:'n'=1):
...
$ python3 ./echo.py --help
Usage: ./echo.py [OPTIONS] text...
Echoes text back
Positional arguments:
text The text to echo back
Options:
-r, --reverse Reverse text before processing
-n, --repeat=INT Amount of times to repeat text(default: 1)
-p, --prefix=STR Prepend this to each line in word(default: )
-s, --suffix=STR Append this to each line in word(default: )
Other actions:
-h, --help Show the help
Arbitrary requirements¶
Let’s say we want to give an error if the word spam is in the text. To do so,
one option is to raise an ArgumentError
from within your function:
from clize import ArgumentError, Parameter, run
def echo(*text:Parameter.REQUIRED,
prefix:'p'='', suffix:'s'='', reverse:'r'=False, repeat:'n'=1):
"""Echoes text back
:param text: The text to echo back
:param reverse: Reverse text before processing
:param repeat: Amount of times to repeat text
:param prefix: Prepend this to each line in word
:param suffix: Append this to each line in word
"""
text = ' '.join(text)
if 'spam' in text:
raise ArgumentError("I don't want any spam!")
if reverse:
text = text[::-1]
text = text * repeat
if prefix or suffix:
return '\n'.join(prefix + line + suffix
for line in text.split('\n'))
return text
def version():
"""Show the version"""
return 'echo version 0.2'
if __name__ == '__main__':
run(echo, alt=version)
$ ./echo.py spam bacon and eggs
./echo.py: I don't want any spam!
Usage: ./echo.py [OPTIONS] text...
If you would like the usage line not to be printed, raise UserError
instead.
Next up, we will look at how you can have Clize dispatch to multiple functions for you.