clize: Turn functions into command-line interfaces¶
Clize is an argument parser for Python. It focuses on minimizing the effort required to create them:
- Command-line interfaces are created by passing functions to
clize.run
. - Parameter types are deduced from the functions’ parameters.
- A
--help
message is generated from your docstrings. Seriously, why does this still need to be a bullet point? - Decorators can be used to reuse functionality across functions.
- Clize can be extended with new parameter behavior.
Here’s an example:
from sigtools.modifiers import kwoargs
from clize import run
@kwoargs('no_capitalize') # turns no_capitalize into a keyword-only parameter
# on Python 2
def hello_world(name=None, no_capitalize=False):
"""Greets the world or the given name.
name: If specified, only greet this person.
no_capitalize: Don't capitalize the given name.
"""
if name:
if not no_capitalize:
name = name.title()
return 'Hello {0}!'.format(name)
return 'Hello world!'
if __name__ == '__main__':
run(hello_world)
run
takes the function and automatically produces a command-line
interface for it:
$ pip install --user clize
$ python examples/hello.py --help
Usage: examples/hello.py [OPTIONS] [name]
Greets the world or the given name.
Positional arguments:
name If specified, only greet this person.
Options:
--no-capitalize Don't capitalize the give name.
Other actions:
-h, --help Show the help
$ python hello.py
Hello world!
$ python hello.py john
Hello John!
$ python hello.py dave --no-capitalize
Hello dave!
Interested?
- Follow the tutorial
- Browse the examples
- Ask for help on Gitter
- Check out why Clize was made
- Star, watch or fork Clize on GitHub
Here is the full table of contents:
About Clize¶
Why Clize was made¶
Clize started from the idea that other argument parsers were too complicated to use. Even for a small script, one would have to use a fairly odd interface to first generate a « parser » object with the correct behavior then use it.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("name", nargs='?',
help="The person to greet")
parser.add_argument("repeat", nargs='?', type=int, default=1,
help="How many times should the person be greeted")
parser.add_argument("--no-capitalize", action='store_const', const=True)
args = parser.parse_args()
if args.name is None:
greeting = 'Hello world!'
else:
name = args.name if args.no_capitalize else args.name.title()
greeting = 'Hello {0}!'.format(name)
for _ in range(args.repeat):
print(greeting)
This doesn’t really feel like what Python should be about. It’s too much for such a simple CLI.
A much simpler alternative could be to use argument unpacking:
import sys.argv
def main(script, name=None, repeat='1'):
if name is None:
greeting = 'Hello world!'
else:
greeting = 'Hello {0}!'.format(name.title())
for _ in range(int(repeat)):
print(greeting)
main(*sys.argv)
This makes better use of Python concepts: a function bundles a series of statements with a list of parameters, and that bundle is now accessible from the command-line.
However, we lose several features in this process: Our simpler version can’t
process named arguments like --no-capitalize
, there is no --help
function of any sort, and all errors just come up as tracebacks, which would be
confusing for the uninitiated.
Those shortcomings are not inherent to bundling behavior and parameters into functions. Functions can have keyword-only parameters (and this can be backported to Python 2.x), and those parameter lists can be examined at run time. Specific errors can be reformatted, and so forth.
Clize was made to address these shortcomings while expanding on this idea that command-line parameters are analogous to those of a function call in Python.
The following table summarizes a few direct translations Clize makes:
Python construct | Command-line equivalent |
---|---|
Function | Command |
List of functions | Multiple commands |
Docstring | Source for the --help output |
Decorator | Transformation of a command |
Positional parameter | Positional parameter |
Keyword-only parameter | Named parameter (like --one ) |
Parameter with a default value | Optional parameter |
Parameter with False as default |
Flag (True if present, False otherwise) |
Some concepts fall outside these straightforward relationships, but in all cases your part of the command-line interface remains a normal function. You can call that function normally, have another command from your CLI use it, or test it like any other function.
For when Python constructs aren’t enough, Clize uses parameter annotations, a yet mostly unexplored feature of Python 3. For instance, you can specify value converters for the received arguments, or replace how a parameter is implemented completely.
Even though its basic purpose could be called magicky, Clize attempts to
limit magic in the sense that anything Clize’s own parameters do can also be
done in custom parameters. For instance, --help
in a command-line will
trigger the displaying of the help screen, even if there were errors
beforehand. You might never need to do this, but the option is there if and
when you ever need this. argparse
for instance does not let you do this.
With Clize, you start simple but you remain flexible throughout, with options for refactoring and extending your command-line interface.
“Why not use an existing parser instead of making your own?”¶
Argument parsing is a rather common need for Python programs. As such, there are many argument parsers in existence, including no less than three in the standard library alone!
The general answer is that they are different. The fact that there are so many
different parsers available shows that argument parsing APIs are far from being
a “solved problem”. Clize offers a very different approach from those of
argparse
, Click or docopt. Each of these always have you write a specification for
your CLI.
Clize comes with less batteries included than the above. It focuses on
providing just the behavior that corresponds with Python parameters, along with
just a few extras. Clize can afford to do this because unlike these, Clize can
be extended to accomodate custom needs. Every parameter kind can be implemented
by external code and made usable the same way as clize.parameters.multi
or
clize.parameters.argument_decorator
.
“Why not create a thin wrapper around argparse?”¶
Back during Clize’s first release, argparse
‘s parser would have been
sufficient for what Clize proposed, though I wasn’t really interested in
dealing with it at the time. With Clize 3’s extensible parser, replacing it
with argparse
would be a loss in flexibility, in parameter capabilities and
help message formatting.
An illustrated history¶
This document recounts the story of each clize version. Here’s the short version first:
Version | Release date | Major changes |
---|---|---|
1.0b | April 4th 2011 | First release |
2.0 | October 7th 2012 | Subcommands, Python 3 syntax support |
2.2 | August 31st 2013 | Minor additions |
2.4 | October 2nd 2013 | Bugfixes |
3.0 | May 13th 2015 | Extensibility, decorators, focus on py3 |
You can also browse the release notes.
And here’s the story:
Before Clize¶
After having used optparse
and twisted’s usage.Options
in various medium-sized projects, and
viewing argparse
as being more of the same, I wondered if I needed all this
when writing a trivial program. I realized that if I only wanted to read some
positional arguments, I could just use tuple unpacking on sys.argv
:
from __future__ import print_function
import sys
script, first, last = sys.argv
print('Hello', first, last)
If you used argument packing in a functon call instead, you gain the ability to make use of default values:
from __future__ import print_function
import sys
def greet(script, first, last, greeting="Hello"):
print(greeting, first, last)
greet(*sys.argv)
It works nicely save for the fact that you can’t request a help page from it or have named options. So I set out to add those capabilities while doing my best to keep it as simple as possible, like the above example.
1.0: A first release¶
from __future__ import print_function
from clize import clize, run
@clize
def greet(first, last, greeting="Hello"):
print(greeting, first, last)
run(greet)
Thanks to the ability in Python to look at a function’s signature, you gained a
--help
page, and greeting
was available as --greeting
on the
command line, while adding just one line of code. This was very different from
what argparse
had to offer. It allowed you to almost completely ignore
argument parsing and just write your program’s logic as a function, with your
parameters’ documented in the docstring.
In a way, Clize had opinions about what a CLI should and shouldn’t be like. For instance, it was impossible for named parameters to be required. It was generally very rigid, which was fine given its purpose of serving smaller programs.
It hadn’t visibly garnered much interest. I was still a user myself, and no other argument parser had really interested me, so I kept using it and watched out for possible improvements. Aside from the subcommand dispatcher, there was little user feedback so the inspiration ended up coming from somewhere else.
2.0: Function annotations¶
Clize 2.0 came out with two major features. Subcommands and a new way of specifying additional information on the parameters. I’ll skip over subcommands because they are already a well established concept in argument parsing. See Multiple commands for their documentation.
Through now forgotten circumstances, I came across PEP 3107 implemented since Python 3.0, which proposed a syntax for adding information about parameters.
Up until then, if you wanted to add an alias to a named parameter, it looked a bit like this:
from __future__ import print_function
from clize import clize, run
@clize(require_excess=True, aliases={'reverse': ['r']})
def echo(reverse=False, *args):
text = ' '.join(args)
if reverse:
text = text[::-1]
print(text)
run(echo)
Many things involved passing parameters in the decorator. It was generally quite ugly, especially when more than one parameter needed adjusting, at which point the decorator call grew to the point of needing to be split over multiple lines.
The parameter annotation syntax from PEP 3107 was fit to replace this. You could tag the parameter directly with the alias or conversion function or whatever. It involved looking at the type of each annotation, but it was a lot more practical than spelling alias, converter and the parameter’s name all over the place.
It also allowed for keyword-only parameters from PEP 3102 to map directly to named parameters while others would always be positional parameters.
from __future__ import print_function
from clize import clize, run
@clize(require_excess=True)
def echo(*args, reverse:'r'=False):
text = ' '.join(args)
if reverse:
text = text[::-1]
print(text)
run(echo)
Python 3 wasn’t quite there yet, so these were just features on the side at the time. I liked it a lot however and used it whenever I could, but had to use the older interface whenever I had to use Python 2.
3.0: The rewrite¶
Python 3.3 introduced inspect.signature
, an alternative to the rough
inspect.getfullargspec
. This provided an opportunity to start again from
scratch to build something on a solid yet flexible base.
For versions of Python below 3.3, a backport of inspect.signature
existed on
PyPI
. This inspired a Python 3-first approach: The
old interface was deprecated in favor of the one described just above.
from clize import run, parameter
def echo(*args: parameter.required, reverse:'r'=False):
text = ' '.join(args)
if reverse:
text = text[::-1]
print(text)
run(echo)
Since the @clize
decorator is gone, echo
is now just a regular function
that could theoretically be used in non-cli code or tests.
Users looking to keep Python 2 compatibility would have to use a compability
layer for keyword-only parameters and annotations: sigtools.modifiers
.
from __future__ import print_function
from sigtools import modifiers
from clize import run, parameter
@modifiers.autokwoargs
@modifiers.annotate(args=parameter.REQUIRED, reverse='r')
def echo(reverse=False, *args):
text = ' '.join(args)
if reverse:
text = text[::-1]
print(text)
run(echo)
sigtools
was created specifically because of Clize, but it aims to be a
generic library for manipulating function signatures. Because of Clize’s
reliance on accurate introspection data on functions and callables in general,
sigtools
also provided tools to fill the gap when inspect.signature
stumbles.
For instance, when a decorator replaces a function and complements its
parameters, inspect.signature
would only produce something like (spam,
*args, ham, **kwargs)
when Clize would need more information about what
*args
and **kwargs
mean.
sigtools
thus provided decorators such as forwards
and
the higher-level wrapper_decorator
for specifying what
these parameters meant. This allowed for creating decorators for CLI
functions in a way analogous to regular decorators,
which was up until then something other introspection-based tools had never
done. It greatly improved Clize’s usefulness with multiple commands.
With the parser being completely rewritten, a large part of the argument
parsing was moved away from the monolithic “iterate over sys.argv
” loop to
one that deferred much of the behaviour to parameter objects determined from
the function signature. This allows for library and application authors to
almost completely customize how their parameters work, including things like replicating --help
‘s behavior of working
even if there are errors beforehand, or other completely bizarre stuff.
This is a departure from Clize’s opiniated beginnings, but the defaults remain
sane and it usually takes someone to create new Parameter
subclasses for bizarre stuff to be made. In return Clize gained a flexibility
few other argument parsers offer.
Frequently asked questions¶
Drats! These docs are all new and the FAQ is almost empty! Help me improve this dire situation by contacting me with your questions!
Table of contents
- What versions of Python are supported?
- What libraries are required for Clize to run?
- I just installed Clize using
pip
and I still getImportErrors
- What is
sigtools
and why is it a separate library? - What other libraries can be used for argument parsing?
- How can I write mutually exclusive flags?
- Some of my commands share features, can I reuse code somehow?
- Where can I find more help?
- Contacting the author
What versions of Python are supported?¶
Clize is tested to run succesfully on Python 2.6, 2.7, 3.2, 3.3 and 3.4.
What libraries are required for Clize to run?¶
Using pip
to install Clize from PyPI as in Installation will
automatically install the right dependencies for you.
If you still need the list, Clize always requires:
- six: For helping run Clize on both Python 2 and 3.
- sigtools: Utilities to help manipulate function sigatures.
If you wish to use clize.converters.datetime
, you need:
- python-dateutil: For parsing dates.
pip
will install dateutil
if you specify to install Clize with the
datetime
option, i.e. pip install "clize[datetime]"
.
On Python 2, sigtools
requires:
- funcsigs: A backport of
inspect.signature
to Python 2.
Finally, on Python 2.6, this is also needed:
- ordereddict: A backport of
collections.OrderedDict
.
I just installed Clize using pip
and I still get ImportErrors
¶
Old versions of pip
do not read Python-version dependent requirements and
therefore do not install funcsigs
or ordereddict
. To remedy this, you can:
- Upgrade
pip
and install Clize again. (Use the-U
flag ofpip install
to force a reinstall.) - Install the dependencies manually.
What is sigtools
and why is it a separate library?¶
sigtools
is used in many of the examples throughout this documentation, and
it is maintained by the same person as Clize, thus the above question.
Clize’s purpose is twofold:
- Convert the idioms of a function signature into those of a CLI,
- Parse the input that CLI arguments are.
It turns out that just asking for the function signature from
inspect.signature
is not good enough:
- Python 2 users cannot write keyword-only parameters.
inspect.signature
cannot process decorators that return a function with slightly altered parameters.
For the first point, Clize could have accepted an argument that said “do as if that parameter was keyword-only and make it a named parameter on the CLI” (and in fact it used to), but that would have Clize behave according to a signature and a bunch of things around it, which is a concept it tries to steer away from.
For the second, some tooling would be necessary to specify how exactly a decorator affected a wrapped function’s parameters.
Modifying and making signatures more useful was both complex and independent
from command-line argument parsing, so it was made a separate library as
sigtools
.
So there you have it, sigtools
helps you add keyword-only parameters on
Python 2, and helps decorators specify how they alter parameters on decorated
functions. All Clize sees is the finished accurate signature from which it
infers a CLI.
What other libraries can be used for argument parsing?¶
Similar to Clize in that parameter behavior is inferred from a function signature:
- Baker: Similar to Clize 2, with a decorator-based approach for adding commands.
- argh: Based on
argparse
, optionally lets you add parameters using a decorator API similar toargparse
.
Others:
How can I write mutually exclusive flags?¶
Mutually exclusive flags refer to when a user can use one flag A (--flag-a
)
or the other (--flag-b
), but not both at the same time.
It is a feature that is difficult to express in a function signature as well as
on the --help
screen for the user (other than in the full usage form).
It is therefore recommended to use a positional parameter or option that
accepts one of specific values. one_of
can help you do
that.
If you still think mutually exclusive parameters are your best option, you can
check for the condition in your function and raise clize.ArgumentError
, as in
the Arbitrary requirements part of the tutorial.
Where can I find more help?¶
You can get help by contacting me directly, writing in the dedicated Gitter chatroom, using the #clize #python hashtags on Twitter, or by posting in the Clize Google+ community.
Contacting the author¶
You can contact me via @YannKsr on Twitter or via email. Feel free to ask about Clize!
Getting started¶
This section contains tutorials for the most commonly used features of Clize.
Basics¶
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:
$ python 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.
#!/usr/bin/env python
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:
$ ./echo.py
./echo.py: Missing required arguments: word
Usage: ./echo.py [OPTIONS] word
$ ./echo.py ham
ham
$ ./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:
$ ./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
word: One word or quoted string to echo back
"""
return word
As you would expect, it translates to this:
$ ./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
:
from sigtools.modifiers import autokwoargs
@autokwoargs
def echo(word, prefix='', suffix=''):
"""Echoes text back
word: One word or quoted string to echo back
prefix: Prepend this to each line in word
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
Here, autokwoargs
turns all parameters with defaults into
keyword-only parameters. Clize then treats it as an option instead of a
positional parameter.
Note
Since Python does not have syntax for specifying keyword-only parameters
until Python 3, we will use decorators from the sigtools.modifiers
module to emulate them in all Python versions supported by Clize.
If you don’t need to worry about Python 2 compatibility, you can use the Python 3 features directly:
def echo(word, *, prefix='', suffix=''):
pass # ...
The change reflects to the command and its help when run:
$ ./echo.py --prefix x: --suffix :y 'spam
$ ham'
x:spam:y
x:ham:y
$ ./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
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:
@autokwoargs
def echo(prefix='', suffix='', *text):
pass # ...
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:
#!/usr/bin/env python
from sigtools.modifiers import annotate, autokwoargs
from clize import Parameter, run
@annotate(text=Parameter.REQUIRED)
@autokwoargs
def echo(prefix='', suffix='', *text):
"""Echoes text back
text: The text to echo back
prefix: Prepend this to each line in word
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:
@annotate(text=Parameter.REQUIRED)
@autokwoargs
def echo(prefix='', suffix='', reverse=False, *text):
"""Echoes text back
text: The text to echo back
reverse: Reverse text before processing
prefix: Prepend this to each line in word
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
$ ./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:
@annotate(text=Parameter.REQUIRED)
@autokwoargs
def echo(prefix='', suffix='', reverse=False, repeat=1, *text):
"""Echoes text back
text: The text to echo back
reverse: Reverse text before processing
repeat: Amount of times to repeat text
prefix: Prepend this to each line in word
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
$ ./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:
@annotate(text=Parameter.REQUIRED,
prefix='p', suffix='s', reverse='r', repeat='n')
@autokwoargs
def echo(prefix='', suffix='', reverse=False, repeat=1, *text):
pass # ...
$ ./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 sigtools.modifiers import annotate, autokwoargs
from clize import ArgumentError, Parameter, run
@annotate(text=Parameter.REQUIRED,
prefix='p', suffix='s', reverse='r', repeat='n')
@autokwoargs
def echo(prefix='', suffix='', reverse=False, repeat=1, *text):
"""Echoes text back
text: The text to echo back
reverse: Reverse text before processing
repeat: Amount of times to repeat text
prefix: Prepend this to each line in word
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.
Dispatching to multiple functions¶
So far the previous part of the tutorial showed you how to use clize to
run a single function. Sometimes your program will need to
perform diffferent related actions that involve different parameters. For
instance, git offers all kinds of commands related to
managing a versionned code repository under the git
command. Alternatively,
your program could have one main function and a few auxiliary ones, for
instance for verifying the format of a config file, or simply for displaying
the program’s version.
Alternate actions¶
These allow you to provide auxiliary functions to your program while one
remains the main function. Let’s write a program with an alternate command
triggered by --version
that prints the version.
Here are the two functions we could have: do_nothing
will be the main function while version
will be provided as an alternate command.
VERSION = "0.2"
def do_nothing():
"""Does nothing"""
return "I did nothing, I swear!"
def version():
"""Show the version"""
return 'Do Nothing version {0}'.format(VERSION)
You use run
as usual for the main function, but specify the alternate command
in the alt=
parameter:
from clize import run
run(do_nothing, alt=version)
The version
function will be available as --version
:
$ python examples/altcommands.py --help
Usage: examples/altcommands.py
Does nothing
Other actions:
-h, --help Show the help
--version Show the version
You can specify more alternate commands in a list. For instance,
from sigtools import modifiers
@modifiers.kwoargs('show_time')
def build_date(show_time=False):
"""Show the build date for this version"""
print("Build date: 17 August 1979", end='')
if show_time:
print(" afternoon, about tea time")
print()
run(do_nothing, alt=[version, build_date])
You can instead use a dict
to specify their names if those automatically
drawn from the function names don’t suit you:
run(do_nothing, alt={
'totally-not-the-version': version,
'birthdate': build_date
})
$ python examples/altcommands.py --help
Usage: examples/altcommands.py
Does nothing
Other actions:
--birthdate Show the build date for this version
-h, --help Show the help
--totally-not-the-version
Show the version
Using a collections.OrderedDict
instance rather than dict
will guarantee
the order they appear in the help is the same as in the source.
Multiple commands¶
This allows you to keep multiple commands under a single program without singling one out as the main one. They become available by naming the subcommand directly after the program’s name on the command line.
Let’s see how we can use it in a mock todo list application:
def add(*text):
"""Adds an entry to the to-do list.
text: The text associated with the entry.
"""
return "OK I will remember that."
def list_():
"""Lists the existing entries."""
return "Sorry I forgot it all :("
You can specify multiple commands to run by passing each function as an
argument to run
:
from clize import run
run(add, list_)
$ python examples/multicommands.py add A very important note.
OK I will remember that.
$ python examples/multicommands.py list
Sorry I forgot it all :(
Alternatively, as with alternate commands, you can
pass in an iterable, a dict
or an OrderedDict
.
Because it isn’t passed a regular function with a docstring, Clize can’t
determine an appropriate description from a docstring. You can explicitly give
it a description with the description=
parameter. Likewise, you an add
footnotes with the footnotes=
parameter. The format is the same as with
other docstrings, just without documentation for parameters.
run(add, list_, description="""
A reliable to-do list utility.
Store entries at your own risk.
""")
$ python examples/multicommands.py --help
Usage: examples/multicommands.py command [args...]
A reliable to-do list utility.
Store entries at your own risk.
Commands:
add Adds an entry to the to-do list.
list Lists the existing entries.
Often, you will need to share a few characteristics, for instance a set of parameters, between multiple functions. See how Clize helps you do that in Function compositing.
Function compositing¶
One of Python’s strengths is how easy it is to manipulate functions and combine
them. However, this typically breaks tools such as Clize which try to inspect
the resulting callable and only get vague information. Fortunately, using the
functions found in sigtools
, we can overcome this drawback.
Let’s look at how you can create decorators that work well with Clize.
Creating decorators is useful if you want to share behaviour across multiple
functions passed to run
, such as extra parameters or input/output formatting.
Using a decorator to add new parameters and modify the return value¶
Let’s create a decorator that transforms the output of the wrapped function when passed a specific flag.
from sigtools.modifiers import autokwoargs
from sigtools.wrappers import wrapper_decorator
@wrapper_decorator
@autokwoargs
def with_uppercase(wrapped, uppercase=False, *args, **kwargs):
"""
Formatting options:
uppercase: Print output in capitals
"""
ret = wrapped(*args, **kwargs)
if uppercase:
return str(ret).upper()
else:
return ret
wrapper_decorator
lets our with_uppercase
function decorate other
functions:
from clize import run
@with_uppercase
def hello_world(name=None):
"""Says hello world
name: Who to say hello to
"""
if name is not None:
return 'Hello ' + name
else:
return 'Hello world!'
if __name__ == '__main__':
run(hello_world)
Each time the decorated function is run, with_uppercase
will be run with
the decorated function as first argument wrapped
.
wrapper_decorator
will tell Clize that the combined function has the same
signature as:
@kwoargs('uppercase')
def hello_world(name=None, uppercase=False):
pass
This is the signature you would get by “putting” the parameters of the
decorated function in place of the wrapper’s *args, **kwargs
. It is what wrapper_decorator
expects it to do, but that can be changed.
With the correct signature advertised, the command-line interface matches it:
$ python examples/decorators.py --uppercase
HELLO WORLD!
$ python examples/decorators.py john
Hello john
$ python examples/decorators.py john --uppercase
HELLO JOHN
The help system will also pick up on the fact that the function is decorated and will read parameter descriptions from the decorator’s docstring:
$ python decorators.py --help
Usage: decorators.py [OPTIONS] [name]
Says hello world
Positional arguments:
name Who to say hello to
Formatting options:
--uppercase Print output in capitals
Other actions:
-h, --help Show the help
Providing an argument using a decorator¶
When you’re passing new arguments to the wrapped function in addition to
*args, **kwargs
, things get a little more complicated. You have to tell
Clize that some of the wrapped function’s parameters shouldn’t appear in place
of the wrapper’s *args, **kwargs
. call wrapper_decorator
with the number
of positional arguments you insert before *args
, then the names of each
named argument that you pass to the wrapped function.
See also
Picking the appropriate arguments for forwards
The arguments for wrapper_decorator
are the same as in
sigtools.specifiers.forwards
, so you may use this section for further
information.
from sigtools.modifiers import autokwoargs
from sigtools.wrappers import wrapper_decorator
def get_branch_object(repository, branch_name):
return repository, branch_name
@wrapper_decorator(0, 'branch')
@autokwoargs
def with_branch(wrapped,
repository='.', branch='master',
*args, **kwargs):
"""Decorate with this so your function receives a branch object
repository: A directory belonging to the repository to operate on
branch: The name of the branch to operate on
"""
return wrapped(
*args, branch=get_branch_object(repository, branch), **kwargs)
Here we pass 0, 'branch'
to wrapper_decorator
because we call wrapped
with no positional arguments besides *args
, and branch
as named
argument.
You can then use the decorator like before:
from clize import run
@with_branch
@autokwoargs
def diff(branch=None):
"""Show the differences between the committed code and the working tree."""
return "I'm different."
@with_branch
@autokwoargs
def commit(branch=None, *text):
"""Commit the changes.
text: A message to store alongside the commit
"""
return "All saved.: " + ' '.join(text)
@with_branch
@autokwoargs
def revert(branch=None):
"""Revert the changes made in the working tree."""
return "There is no chip, John."
run(diff, commit, revert,
description="A mockup version control system(like git, hg or bzr)")
Using a composed function to process arguments to a parameter¶
You can use clize.parameters.argument_decorator
to have a second function
process an argument while still being able to use parameters of its own:
from clize import run
from clize.parameters import argument_decorator
@argument_decorator
def read_server(arg, *, port=80, _6=False):
"""
Options for {param}:
port: Which port to connect on
_6: Use IPv6?
"""
return (arg, port, _6)
def get_page(server:read_server, path):
"""
server: The server to contact
path: The path of the resource to fetch
"""
print("Connecting to", server, "to get", path)
run(get_page)
read_server
‘s parameters will be available on the CLI. When a value is read
that would feed the server
parameter, read_server
is called with it and
its collected arguments. Its return value is then used as the server
parameter of get_page
:
$ python argdeco.py --help
Usage: argdeco.py [OPTIONS] [--port=INT] [-6] server path
Arguments:
server The server to contact
path The path of the resource to fetch
Options for server:
--port=INT Which port to connect on (default: 80)
-6 Use IPv6?
Other actions:
-h, --help Show the help
A few notes:
- Besides
arg
which receives the original value, you can only use named parameters - The decorator’s docstring is used to document its parameters. It can be preferrable to use a section in order to distinguish them from other parameters.
- Appearances of
{param}
in the docstring are replaced with the parameter’s name.
You can also use this on named parameters as well as on *args
, but the
names of the composited parameters must not conflict with other parameters:
from clize import run
from clize.parameters import argument_decorator
@argument_decorator
def read_server(arg, *, port=80, _6=False):
"""
Options for {param}:
port: Which port to connect on
_6: Use IPv6?
"""
return (arg, port, _6)
def get_page(path, *servers:read_server):
"""
server: The server to contact
path: The path of the resource to fetch
"""
print("Connecting to", servers, "to get", path)
run(get_page)
$ python argdeco.py --help
Usage: argdeco.py [OPTIONS] path [[--port=INT] [-6] servers...]
Arguments:
path The path of the resource to fetch
servers...
Options for servers:
--port=INT Which port to connect on (default: 80)
-6 Use IPv6?
Other actions:
-h, --help Show the help
$ python argdeco.py -6 abc
argdeco.py: Missing required arguments: servers
Usage: argdeco.py [OPTIONS] path [[--port=INT] [-6] servers...]
$ python argdeco.py /eggs -6 abc
Connecting to (('abc', 80, True),) to get /eggs
$ python argdeco.py /eggs -6 abc def
Connecting to (('abc', 80, True), ('def', 80, False)) to get /eggs
$ python argdeco.py /eggs -6 abc def --port 8080 cheese
Connecting to (('abc', 80, True), ('def', 80, False), ('cheese', 8080, False)) to get /eggs
Congratulations, you’ve reached the end of the tutorials! You can check out the parameter reference or see how you can extend the parser.
Guides¶
These documents document specific aspects or usages of Clize.
Extending the parser¶
Clize allows the parser to be extended through, most notably, new parameters. They allow you to introduce new argument parsing behaviour within the parser’s contraints:
- The finality of argument parsing in Clize is to determine
func
,args
andkwargs
in order to dofunc(*args, **kwargs)
. - Arguments that start with
-
are looked up in the named parameters table by their first letter when there is only one dash, or until the end of the argument or=
when there are two dashes. - Other arguments are processed by the positional parameters in the order they are stored.
This document explains each step of the CLI inference and argument parsing process. An example shows how you can add a custom kind of parameter.
Execution overview¶
clize.run
is called with either a function, or a sequence or mapping of functions.- It forwards that to
Clize.get_cli
in order to get a cli object to run. - If there is more than one function,
Clize.get_cli
usesSubcommandDispatcher
to wrap it, otherwise it creates a newClize
instance with it and returns it. run
calls that cli object withsys.argv
unpacked (ie.obj(*sys.argv)
).- Assuming that cli object is a
Clize
instance, it will look at the function that was passed and determine aCliSignature
object from it. Clize
calls the cli signature’sread_arguments
method with the command-line arguments, which returns aCliBoundArguments
instance.- That
CliBoundArguments
instance carries information such as the arguments that the function will be called with or the instruction to replace that function with another entirely.Clize
then runs the chosen function andclize.run
prints its return value.
Parameter conversion¶
In step 5 above, CliSignature.from_signature
converts each parameter. Here
is the process followed for each parameter:
- The annotation for each parameter is read as a sequence. If it isn’t one then it is wrapped in one.
- The annotations are searched for
clize.parser.Parameter.IGNORE
. If found, the parameter is dropped with no further processing. - The annotations are searched for a parameter converter function. If none is found,
default_converter
is used. - The parameter converter is called with the
inspect.Parameter
object representing the parameter and the sequence of annotations without the parameter converter. Its return value, expected to be aclize.parser.Parameter
instance, is added to the list of parameters for the resultingCliSignature
instance.
The default parameter converter¶
The default parameter converter works as follows:
- It looks at the parameter’s type and checks whether it is a named or positional parameter. This is used to check if it is legal to assign aliases to it and to determine what cli parameter class will be used to represent it.
- It looks at the parameter’s default value and extracts its type, expecting that it is a valid value converter. If there isn’t one the parameter is marked as required.
- The annotations sequence is iterated on:
- If the annotation is a
Parameter
instance, it is returned immediately with no processing. - If the annotation is a value converter it is used instead of the default value’s type. Specifying a value converter is required when the default value’s type isn’t a valid one itself.
- If it is a string, it is used as an alias unless the parameter is positional.
- If the annotation is a
- Finally, depending on the above, a parameter class is picked, instantiated
and returned:
PositionalParameter
if the parameter was positional,ExtraPosArgsParameter
for a*args
parameter,OptionParameter
for a named parameter that takes an argument,IntOptionParameter
if that argument is of typeint
FlagParameter
for a named parameter withFalse
as default andbool
as type,- An error is raised for
**kwargs
parameters, as their expected equivalent in a CLI is largely subjective. If you want to forward arguments to another function, consider using function compositing instead of having a CLI parameter handle it.
The argument parser¶
The argument parsing is orchestrated by CliBoundArguments
during its
initialization. For each argument of its input, it selects the appropriate
Parameter
instance to handle it. If the argument on the input starts with
-
it looks in the CliSignature.named
dictionary. If not, it picks the
next positional parameter from CliSignature.positional
. The parameter’s
read_argument
and apply_generic_flags
methods are
called.
-
Parameter.
read_argument
(ba, i)[source]¶ Reads one or more arguments from
ba.in_args
from positioni
.Parameters: - ba (clize.parser.CliBoundArguments) – The bound arguments object this call is expected to mutate.
- i (int) – The current position in
ba.args
.
This method is expected to mutate ba
, an instance of CliBoundArguments
.
In particular, it should add any relevant arguments to ba
‘s
args
and kwargs
attributes which
are used when calling the wrapped callable as in func(*args, **kwargs)
. It
can also set the func
attribute which overrides the
Clize
object’s wrapped callable.
Part of the parameter’s behavior is split from read_argument
into
apply_generic_flags
in order to facilitate subclassing:
-
Parameter.
apply_generic_flags
(ba)[source]¶ Called after
read_argument
in order to set attributes onba
independently of the arguments.Parameters: ba (clize.parser.CliBoundArguments) – The bound arguments object this call is expected to mutate. The base implementation of this method applies the
last_option
setting if applicable and discards itself fromCliBoundArguments.unsatisfied
The both of these methods are expected to discard the parameter from
unsatisfied
, the list of still-unsatisfied required
parameters, when applicable. The sticky
,
posarg_only
and skip
can also be
modified to change the ongoing argument reading process.
Example: Implementing one_of
¶
clize.parameters.one_of
creates a parameter annotation that modifies the
parameter to only allow values from a given list:
from clize import run, parameters
def func(breakfast:parameters.one_of('ham', 'spam')):
"""Serves breakfast
breakfast: what food to serve
"""
print("{0} is served!".format(breakfast))
run(func)
The breakfast
parameter now only allows ham
and spam
:
$ python breakfast.py ham
ham is served!
$ python breakfast.py spam
spam is served!
$ python breakfast.py eggs
breakfast.py: Bad value for breakfast: eggs
Usage: breakfast.py breakfast
A list is produced when list
is supplied:
$ python breakfast.py list
breakfast.py: Possible values for breakfast:
ham
spam
Also, it hints at the list
keyword on the help page:
$ python breakfast.py --help
Usage: breakfast.py breakfast
Serves breakfast
Arguments:
breakfast what food to serve (use "list" for options)
Other actions:
-h, --help Show the help
one_of
is implemented in Clize as a wrapper around
mapped
which offers several more features. In this example
we will only reimplement the features described above.
Creating a parameter class for us to edit¶
from clize import run, parser
class OneOfParameter(object):
def __init__(self, values, **kwargs):
super().__init__(**kwargs)
self.values = values
def one_of(*values):
return parser.use_mixin(OneOfParameter, kwargs={'values': values})
def func(breakfast:one_of('ham', 'spam')):
"""Serves breakfast
breakfast: what food to serve
"""
print("{0} is served!".format(breakfast))
run(func)
Here we used parser.use_mixin
to implement the parameter annotation. It will
create a parameter instance that inherits from both OneOfParameter
and the
appropriate class for the parameter being annotated:
PositionalParameter
, OptionParameter
or
ExtraPosArgsParameter
. This means our class will be able to override
some of those classes’ methods.
For now, it works just like a regular parameter:
$ python breakfast.py abcdef
abcdef is served!
Changing coerce_value
to validate the value¶
PositionalParameter
, OptionParameter
and
ExtraPosArgsParameter
all use ParameterWithValue.coerce_value
. We
override it to only accept the values we recorded:
from clize import errors
class OneOfParameter(parser.ParameterWithValue):
def __init__(self, values, **kwargs):
super().__init__(**kwargs)
self.values = set(values)
def coerce_value(self, arg, ba):
if arg in self.values:
return arg
else:
raise errors.BadArgumentFormat(arg)
It now only accepts the provided values:
$ python breakfast.py ham
ham is served!
$ python breakfast.py spam
spam is served!
$ python breakfast.py eggs
breakfast.py: Bad value for breakfast: eggs
Usage: breakfast.py breakfast
Displaying the list of choices¶
We can check if the passed value is list
within coerce_value
. When that
is the case, we change func
and swallow the
following arguments. However, to ensure that the
read_argument
method doesn’t alter this, we need to skip
its execution. In order to do this we will raise an exception from
coerce_value
and catch it in read_argument
:
class _ShowList(Exception):
pass
class OneOfParameter(parser.ParameterWithValue):
def __init__(self, values, **kwargs):
super().__init__(**kwargs)
self.values = values
def coerce_value(self, arg, ba):
if arg == 'list':
raise _ShowList
elif arg in self.values:
return arg
else:
raise errors.BadArgumentFormat(arg)
def read_argument(self, ba, i):
try:
super(OneOfParameter, self).read_argument(ba, i)
except _ShowList:
ba.func = self.show_list
ba.args[:] = []
ba.kwargs.clear()
ba.sticky = parser.IgnoreAllArguments()
ba.posarg_only = True
def show_list(self):
for val in self.values:
print(val)
On ba
, setting func
overrides the function to be run
(normally the function passed to run
). args
and
kwargs
are the positional and keyword argument that will
be passed to that function. Setting sticky
to an
IgnoreAllArguments
instance will swallow all positional arguments instead of
adding them to args
, and posarg_only
makes keyword arguments be processed as if they were positional arguments so
they get ignored too.
$ python breakfast.py list
ham
spam
$ python breakfast.py list --ERROR
ham
spam
The list is printed, even if erroneous arguments follow.
Adding a hint to the help page¶
Clize uses Parameter.show_help
to produce the text used to describe
parameters. It uses Parameter.help_parens
to provide the content inside the
parenthesis after the parameter description.
class OneOfParameter(parser.ParameterWithValue):
...
def help_parens(self):
for s in super(OneOfParameter, self).help_parens():
yield s
yield 'use "list" for options'
The help page now shows the hint:
$ python breakfast.py --help
Usage: breakfast.py breakfast
Serves breakfast
Arguments:
breakfast what food to serve (use "list" for options)
Other actions:
-h, --help Show the help
The full example is available in examples/bfparam.py
.
Upgrading from older releases¶
This document will instruct you in porting applications using older clize versions to the newest version.
Upgrading from clize 1 and 2¶
Clize 3 now only treats keyword-only parameters on the function as named
parameters and does not convert any parameter from keyword to positional or
vice-versa, much like when the use_kwoargs
parameter is used in Clize 2.
Aliases, and other parameter-related information are now expressed exclusively
through parameter annotations. Decorators from sigtools.modifiers
are the
recommended way to set these up on Python 2.
However, clize.clize
is provided: it imitates the old behaviour but adds a
deprecation warning when used.
Porting code using the @clize
decorator with no arguments¶
Consider this code made to work with Clize 1 or 2:
from clize import clize, run
@clize
def func(positional, option=3):
pass # ...
if __name__ == '__main__':
run(func)
Here, you can drop the @clize
line completely, but you have to convert
option
to a keyword-only parameter. You can use
sigtools.modifiers.autokwoargs
to do so:
from sigtools.modifiers import autokwoargs
from clize import run
@autokwoargs
def func(positional, option=3):
pass # ...
if __name__ == '__main__':
run(func)
Decorating the function with @autokwoargs
will still let you call it
normally, except that any parameter with a default value(here just option
)
will only be accepted as a named argument.
force_positional
¶
force_positional
used to let you specify parameters with defaults that you
don’t want as named options:
from clize import clize, run
@clize(force_positional=['positional_with_default'])
def func(positional, positional_with_default=3, option=6):
pass # ...
if __name__ == '__main__':
run(func)
The exceptions
parameter of autokwoargs
has the same purpose here:
from sigtools.modifiers import autokwoargs
from clize import run
@autokwoargs(exceptions=['positional_with_default'])
def func(positional, positional_with_default=3, option=6):
pass # ...
if __name__ == '__main__':
run(func)
Porting code that used alias
or coerce
¶
The alias
and coerce
were used in order to specify alternate names for
options and functions to convert the value of arguments, respectively:
from clize import clize, run
@clize(
alias={'two': ['second'], 'three': ['third']},
coerce={'one': int, 'three': int})
def func(one, two=2, three=None):
pass # ...
if __name__ == '__main__':
run(func)
You now pass these as annotations on the corresponding parameter. To keep
compatibility with Python 2, we use sigtools.modifiers.annotate
:
from sigtools.modifiers import annotate, autokwoargs
from clize import run
@autokwoargs
@annotate
def func(one=int, two='second', three=('third', int)):
pass # ...
if __name__ == '__main__':
run(func)
require_excess
¶
Indicating that an *args
-like parameter is required is now done by
annotating the parameter with Parameter.REQUIRED
or Parameter.R
for short:
from sigtools.modifiers import annotate
from clize import run, Parameter
@annotate(args=Parameter.R)
def func(*args):
pass # ...
if __name__ == '__main__':
run(func)
extra
and make_flag
¶
Alternate actions as shown in Clize 2’s tutorial are now done by passing the
function directly to run
as shown in the tutorial. Unlike previously, the alternate command function is passed to the
clizer just like the main one.
For other use cases, you should find the appropriate parameter class from
clize.parser
or subclass one, instantiate it and pass it in a sequence as the
extra
parameter of Clize
or run
. If the parameter matches one
actually present on the source function, annotate that parameter with your
Parameter
instance instead of passing it to extra
.
Interoperability with arbitrary callables¶
Clize operates as a callable that takes each item from sys.argv
or something
supposed to replace it. It is therefore easy to substitute it with another
callable that has such parameters.
Avoiding automatic CLI inference¶
When an object is passed to run, either as sole command, one in many
subcommands or as an alternative action, it attempts to make a CLI object out of it if it isn’t one already. It simply checks if there is a
cli
attribute and uses it, or it wraps it with Clize
.
To insert an arbitrary callable, you must therefore place it as the cli
attribute of whatever object you pass to run
.
clize.Clize.as_is
does exactly that. You can use it as a decorator or when
passing it to run:
import argparse
from clize import Clize, parameters, run
@Clize.as_is
def echo_argv(*args):
print(*args, sep=' | ')
def using_argparse(name: parameters.pass_name, *args):
parser = argparse.ArgumentParser(prog=name)
parser.add_argument('--ham')
ns = parser.parse_args(args=args)
print(ns.ham)
run(echo_argv, Clize.as_is(using_argparse))
$ python interop.py echo-argv ab cd ef
interop.py echo-argv | ab | cd | ef
$ python interop.py using-argparse --help
usage: interop.py using-argparse [-h] [--ham HAM]
optional arguments:
-h, --help show this help message and exit
--ham HAM
$ python interop.py using-argparse spam
usage: interop.py using-argparse [-h] [--ham HAM]
interop.py using-argparse: error: unrecognized arguments: spam
$ python interop.py using-argparse --ham spam
spam
Providing a description in the parent command’s help¶
If you try to access the above program’s help screen, Clize will just leave the description for each external command empty:
: .tox/docs/bin/python interop.py --help
Usage: interop.py command [args...]
Commands:
echo-argv
using-argparse
Clize expects to find a description as cli.helper.description
. You can
either create an object there or let Clize.as_is
do it for you:
@Clize.as_is(description="Prints argv separated by pipes")
def echo_argv(*args):
print(*args, sep=' | ')
...
run(echo_argv,
Clize.as_is(using_argparse,
description="Prints the value of the --ham option"))
$ python interop.py --help
Usage: interop.py command [args...]
Commands:
echo-argv Prints argv separated by pipes
using-argparse Prints the value of the --ham option
Advertising command usage¶
To produce the --help --usage
output, Clize uses cli.helper.usages()
to
produce an iterable of (command, usage)
pairs. When it can’t determine it,
it shows a generic usage signature instead.
You can use Clize.as_is
‘s usages=
parameter to provide it:
run(echo_argv,
Clize.as_is(using_argparse,
description="Prints the value of the --ham option"),
usages=['--help', '[--ham HAM]'])
$ python interop.py --help --usage
interop.py --help [--usage]
interop.py echo-argv [args...]
interop.py using-argparse --help
interop.py using-argparse [--ham HAM]
The example is available as examples/interop.py
.
Reference¶
The user reference lists all capabilities of each kind of parameter. The API reference comes in handy if you’re extending clize.
User reference¶
Clize deduces what kind of parameter to pick for the CLI depending on what kind of parameter is found on the Python function as well as its annotations.
Note
Python 2 compatibility
In this document we will be showing examples that use Python 3 syntax such
as annotations and keyword-only parameters for conciseness. To translate
those into Python 2, you can use sigtools.modifiers.kwoargs
and
sigtools.modifiers.annotate
.
For instance, given this Python 3 function:
def func(ab:int, *, cd:'c'=2):
pass
You would write in Python 2:
from sigtools import modifiers
@modifiers.kwoargs('cd')
@modifiers.annotate(ab=int, cd='c')
def func(ab, cd=2):
pass
You can pass annotations as a sequence:
def func(*, param:('p', int)): pass
def func(*, param:['p', int]): pass
When only one annotation is needed, you can omit the sequence:
def func(*, param:'p'): pass
def func(*, param:('p',)): pass
def func(*, param:['p']): pass
Annotations for parameters that handle a value¶
The positional and options parameters detailed later both handle the following features:
Specifying a value converter¶
A function or callable decorated with parser.value_converter
passed as
annotation will be used during parsing to convert the value from the string
found in sys.argv
into a value suitable for the annotated function.
from clize import run, parser
@parser.value_converter
def wrap_xy(arg):
return 'x' + arg + 'y'
def func(a, b:wrap_xy):
print(repr(a), repr(b))
run(func)
$ python valconv.py abc def
'abc' 'xdefy'
def
was transformed into xdefy
because of the value converter.
Besides callables decorated with parser.value_converter
, the built-in
functions int
, float
and bool
are also recognized as value converters.
Specifying a default value¶
The parameter’s default value is used without conversion. If no value converter is specified, its type is used instead. When a default value is specified, the parameter becomes optional.
>>> def func(par=3):
... print(repr(par))
...
>>> run(func, exit=False, args=['func', '46'])
46
>>> run(func, exit=False, args=['func'])
3
Therefore, be careful not to use values of types for which the constructor does not handle strings, unless you specify a converter:
>>> from datetime import datetime
>>> now = datetime.utcnow()
>>> def fail(par=now):
... print(repr(par))
...
>>> run(fail, exit=False, args=['func', '...'])
Traceback (most recent call last):
...
TypeError: an integer is required (got type str)
>>> from dateutil.parser import parse
>>> from datetime import datetime
>>> now = datetime.utcnow()
>>> def func(par:parse=now):
... print(par)
...
>>> run(func, exit=False, args=['func', '1/1/2016'])
2016-01-01 00:00:00
Ignoring the source parameter’s default value¶
-
Parameter.
REQUIRED
¶ Annotate a parameter with this to force it to be required, even if there is a default value in the source.
>>> from clize import run, Parameter >>> def func(par:Parameter.REQUIRED=3): ... pass ... >>> run(func, exit=False, args=['func']) func: Missing required arguments: par Usage: func par
Positional parameters¶
Normal parameters in Python are turned into positional parameters on the CLI.
Plain arguments on the command line (those that don’t start with a -
) are
processed by those and assigned in the order they appear:
from clize import run
def func(posparam1, posparam2, posparam3):
print('posparam1', posparam1)
print('posparam2', posparam2)
print('posparam3', posparam3)
run(func)
$ python posparams.py one two three
posparam1 one
posparam2 two
posparam3 three
It also shares the features detailed in Annotations for parameters that handle a value.
Parameter that collects remaining positional arguments¶
An *args
-like parameter in Python becomes a repeatable positional parameter
on the CLI:
from clize import run
def func(param, *args):
print('param', param)
print('args', args)
run(func)
$ python argslike.py one two three
param one
args ('two', 'three')
-
Parameter.
REQUIRED
When used on an
*args
parameter, requires at least one value to be provided.
You can use clize.parameters.multi
for more options.
Named parameters¶
Clize treats keyword-only parameters as named parameters, which, instead of
their position, get designated by they name preceeded by --
, or by -
if
the name is only one character long.
There are a couple kinds of named parameters detailed along with examples in the sections below.
They all understand annotations to specify alternate names for them: Simply pass them as strings in the parameter’s annotation:
from clize import run
def func(*, par:('p', 'param')):
print('par', par)
run(func)
$ python named.py --par value
par value
$ python named.py -p value
par value
$ python named.py --param value
par value
All parameter names are converted by removing any underscores (_
) off the
extremities of the string and replacing the remaining ones with dashes (-
).
Python 2 support for named parameters¶
Python 2 has no keyword-only parameters. To fill that gap, you can use the
decorators from sigtools.modifiers
to emulate them.
@DECORATOR
def func(ab, cd, de=None, fg=None, hi=None):
...
@DECORATOR |
Parameters that become keyword-only |
---|---|
@kwoargs('cd', 'fg') |
cd and fg |
@kwoargs(start='fg') |
fg and all following parameters |
@autokwoargs |
All parameters with defaut values |
@autokwoargs(exceptions=['fg']) |
Same, except for fg |
Named parameters that take an argument¶
Keyword-only parameters in Python become named parameters on the CLI: They get designated by their name rather than by their position:
from clize import run
def func(arg, *, o, par):
print('arg', arg)
print('o', o)
print('par', par)
run(func)
$ python opt.py -o abc def --par ghi
arg def
o abc
par ghi
$ python opt.py -oabc --par=def ghi
arg ghi
o abc
par def
The parameter is designated by prefixing its name with two dashes (eg.
--par
) or just one dash if the name is only one character long (eg.
-o
). The value is given either as a second argument (first example) or
glued to the parameter name for the short form, glued using an equals sign
(=
) for the long form.
It shares the features of Annotations for parameters that handle a value and Named parameters.
Named parameters that take an integer argument¶
A variant of Named parameters that take an argument used when the value type from Annotations for parameters that handle a value is int
. The only difference is that when designating the parameter
using the short glued form, you can chain other short named parameters
afterwards:
from clize import run
def func(*, i: int, o):
print('i', i)
print('o', o)
run(func)
$ python intopt.py -i42o abcdef
i 42
o abcdef
Flag parameters¶
Flag parameters are named parameters that unlike options
do not take an argument. Instead, they set their corresponding parameter in
Python to True
if mentionned.
You can create them by having a keyword-only parameter take False
as default
value:
from clize import run
def func(*, flag=False):
print('flag', flag)
run(func)
$ python flag.py
flag False
$ python flag.py --flag
flag True
$ python flag.py --flag=0
flag False
Additionally, you can chain their short form on the command line with other short parameters:
from clize import run
def func(*, flag:'f'=False, other_flag:'g'=False, opt:'o'):
print('flag', flag)
print('other_flag', other_flag)
print('opt', opt)
run(func)
$ python glueflag.py -fgo arg
flag True
other_flag True
opt arg
$ python glueflag.py -fo arg
flag True
other_flag False
opt arg
Mapped parameters¶
-
clize.parameters.
mapped
(values, *, list_name='list', case_sensitive=None)[source]¶ Creates an annotation for parameters that maps input values to Python objects.
Parameters: - values (sequence) – A sequence of
pyobj, names, description
tuples. For each item, the user can specify a name fromnames
and the parameter will receive the correspondingpyobj
value.description
is used when listing the possible values. - list_name (str) – The value the user can use to show a list of possible values and their description.
- case_sensitive (bool) – Force case-sensitiveness for the input values. The default is to guess based on the contents of values.
greeting = parameters.mapped([ ('Hello', ['hello', 'hi'], 'A welcoming message'), ('Goodbye', ['goodbye', 'bye'], 'A parting message'), ]) @modifiers.kwoargs('kind') @modifiers.annotate(kind=('k', greeting)) def main(name='world', kind='Hello'): """ name: Who is the message for? kind: What kind of message should be given to name? """ return '{0} {1}!'.format(kind, name)
$ python -m examples.mapped -k list python -m examples.mapped: Possible values for --kind: hello, hi A welcoming message goodbye, bye A parting message $ python -m examples.mapped -k hello Hello world! $ python -m examples.mapped -k hi Hello world! $ python -m examples.mapped -k bye Goodbye world! $ python -m examples.mapped Hello world!
- values (sequence) – A sequence of
Repeatable parameters¶
-
clize.parameters.
multi
(min=0, max=None)[source]¶ For option parameters, allows the parameter to be repeated on the command-line with an optional minimum or maximum. For
*args
-like parameters, just adds the optional bounds.@modifiers.kwoargs('listen') @modifiers.annotate(listen=('l', parameters.multi(min=1, max=3))) def main(listen): """Listens on the given addresses listen: An address to listen on. """ for address in listen: print('Listening on {0}'.format(address))
$ python -m examples.multi -l bacon Listening on bacon $ python -m examples.multi -l bacon -l ham -l eggs Listening on bacon Listening on ham Listening on eggs $ python -m examples.multi -l bacon -l ham -l eggs -l spam python -m examples.multi: Received too many values for --listen Usage: python -m examples.multi [OPTIONS] $ python -m examples.multi python -m examples.multi: Missing required arguments: --listen Usage: python -m examples.multi [OPTIONS]
Decorated arguments¶
-
clize.parameters.
argument_decorator
(f)[source]¶ Decorates a function to create an annotation for adding parameters to qualify another.
@argument_decorator def capitalize(arg, *, capitalize:('c', 'upper')=False, reverse:'r'=False): """ Options to qualify {param}: capitalize: Make {param} uppercased reverse: Reverse {param} """ if capitalize: arg = arg.upper() if reverse: arg = arg[::-1] return arg def main(*args:capitalize): """ args: stuff """ return ' '.join(args)
$ python -m examples.argdeco --help Usage: python -m examples.argdeco [OPTIONS] [[-c] [-r] args...] Arguments: args... stuff Options to qualify args: -c, --capitalize, --upper Make args uppercased -r, --reverse Reverse args Other actions: -h, --help Show the help $ python -m examples.argdeco abc -c def ghi abc DEF ghi
Annotations that work on any parameter¶
The following objects can be used as annotation on any parameter:
Parameter converters¶
Callables decorated with clize.parser.parameter_converter
are used
instead of the default converter to construct a
CLI parameter for the annotated Python parameter.
The callable can return a Parameter
instance or Parameter.IGNORE
to
instruct clize to drop the parameter.
>>> from clize import run, parser
>>> @parser.parameter_converter
... def print_and_ignore(param, annotations):
... print(repr(param), annotations)
... return parser.Parameter.IGNORE
...
>>> def func(par:(print_and_ignore,int)):
... pass
...
>>> run(func, exit=False, args=['func', '--help'])
<Parameter at 0x7fc6b0c3dae8 'par'> (<class 'int'>,)
Usage: func
Other actions:
-h, --help Show the help
Unless you are creating new kinds of parameters this should not be useful to you directly. Note that custom parameter converters are likely to use different conventions than those described in this reference.
See also
Parameter instances¶
A Parameter
instance seen in an annotation will be used to represent that
parameter on the CLI, without any further processing. Using a parameter
converter is recommended over this.
Skipping parameters¶
-
Parameter.
IGNORE
= clize.Parameter.IGNORE¶ Annotate a parameter with this and it will be dropped from the resulting CLI signature.
Note that it is dangerous to use this on anything except:
- On
*args
and**kwargs
-like parameters, - On keyword parameters with defaults.
For instance, clize’s default converter does not handle
**kwargs
:>>> from clize import run, Parameter >>> def fail(**kwargs): ... pass ... >>> run(fail, exit=False) Traceback (most recent call last): ... ValueError: This converter cannot convert parameter 'kwargs'.
However, if we decorate that parameter with
Parameter.IGNORE
, clize ignores it:>>> def func(**kwargs:Parameter.IGNORE): ... pass ... >>> run(func, exit=False) >>> run(func, exit=False, args=['func', '--help']) Usage: func Other actions: -h, --help Show the help
- On
Hiding parameters from the help¶
-
Parameter.
UNDOCUMENTED
= clize.Parameter.UNDOCUMENTED¶ Parameters annotated with this will be omitted from the documentation (
--help
).>>> from clize import run, Parameter >>> def func(*, o1, o2:Parameter.UNDOCUMENTED): ... pass ... >>> run(func, exit=False, args=['func', '--help']) Usage: func [OPTIONS] Options: --o1=STR Other actions: -h, --help Show the help
Forcing arguments to be treated as positional¶
-
Parameter.
LAST_OPTION
= clize.Parameter.LAST_OPTION¶ Annotate a parameter with this and all following arguments will be processed as positional.
>>> from clize import run, Parameter >>> def func(a, b, c, *, d:Parameter.LAST_OPTION, e=''): ... print("a:", a) ... print("b:", b) ... print("c:", c) ... print("d:", d) ... print("e:", e) ... Usage: [OPTIONS] a b c >>> run(func, exit=False, args=['func', 'one', '-d', 'alpha', '-e', 'beta']) a: one b: -e c: beta d: alpha e:
Here,
-e beta
was received by theb
andc
parameters rather thane
, because it was processed after-d alpha
, which triggered the parameterd
which had the annotation.
Retrieving the executable name¶
-
clize.parameters.
pass_name
(param, annotations)[source]¶ Parameters decorated with this will receive the executable name as argument.
This can be either the path to a Python file, or
python -m some.module
. It is also appended with sub-command names.from clize import run, parameters def main(name:parameters.pass_name, arg): print('name:', name) print('arg:', arg) def alt(arg, *, name:parameters.pass_name): print('arg:', arg) print('name:', name) run(main, alt=alt)
$ python pn.py ham name: pn.py arg: ham $ python -m pn ham name: python -m pn arg: ham $ python pn.py --alt spam arg: spam name: pn.py --alt $ python -m pn --alt spam arg: spam name: python -m pn --alt
Inserting arbitrary values¶
-
clize.parameters.
value_inserter
(value_factory)[source]¶ Create an annotation that hides a parameter from the command-line and always gives it the result of a function.
Parameters: value_factory (function) – Called to determine the value to provide for the parameter. The current parser.CliBoundArguments
instance is passed as argument, ie.value_factory(ba)
.from clize import run, parameters @parameters.value_inserter def insert_ultimate_answer(ba): return 42 def main(arg, ans:insert_ultimate_answer): print('arg:', arg) print('ans:', ans) run(main)
$ python ins.py eggs arg: eggs ans: 42
Customizing the help using the docstring¶
Clize draws the text of the --help
output from the wrapped function’s
docstring as well as of its sigtools.wrappers.wrapper_decorator
-based
decorators.
While it allows some amount of customization, the input must follow certain rules and the output is formatted by Clize.
The docstring is divided in units of paragraphs. Each paragraph is separated by two newlines.
Documenting positional parameters¶
To document a parameter, start a paragraph with the name of the parameter you
want to document followed by a colon (:
), followed by text:
from clize import run
def func(one, and_two):
"""
one: Documentation for the first parameter.
and_two: Documentation for the second parameter.
"""
run(func)
$ python docstring.py --help
Usage: docstring.py one and-two
Arguments:
one Documentation for the first parameter.
and-two Documentation for the second parameter.
Other actions:
-h, --help Show the help
Documentation for positional parameters is always shown in the order they appear in the function signature.
Description and footnotes¶
You can add a description as well as footnotes:
from clize import run
def func(one, and_two):
"""
This is a description of the program.
one: Documentation for the first parameter.
and_two: Documentation for the second parameter.
These are footnotes about the program.
"""
run(func)
$ python docstring.py --help
Usage: docstring.py one and-two
This is a description of the program.
Arguments:
one Documentation for the first parameter.
and-two Documentation for the second parameter.
Other actions:
-h, --help Show the help
These are footnotes about the program.
Adding additional information¶
If you wish, you may add additional information about each parameter in a new paragraph below it:
from clize import run
def func(one, and_two):
"""
This is a description of the program.
one: Documentation for the first parameter.
More information about the first parameter.
and_two: Documentation for the second parameter.
More information about the second parameter.
_:_
These are footnotes about the program.
"""
run(func)
To distinguish and_two
‘s information and the footnotes, we inserted a dummy
parameter description between them (_:_
).
$ python docstring.py --help
Usage: docstring.py one and-two
This is a description of the program.
Arguments:
one Documentation for the first parameter.
More information about the first parameter.
and-two Documentation for the second parameter.
More information about the second parameter.
Other actions:
-h, --help Show the help
These are footnotes about the program.
Ordering named parameters¶
Unlike positional parameters, named parameters will be shown in the order they appear in the docstring:
from clize import run
def func(*, one, and_two):
"""
and_two: Documentation for the second parameter.
one: Documentation for the first parameter.
"""
run(func)
$ python docstring.py --help
Usage: docstring.py [OPTIONS]
Options:
--and-two=STR Documentation for the second parameter.
--one=STR Documentation for the first parameter.
Other actions:
-h, --help Show the help
Creating sections¶
Named parameters can be arranged into sections. You can create a section by
having a paragraph end with a colon (:
) before a parameter definition:
from clize import run
def func(*, one, and_two, three):
"""
Great parameters:
and_two: Documentation for the second parameter.
one: Documentation for the first parameter.
Not-so-great parameters:
three: Documentation for the third parameter.
"""
run(func)
$ python docstring.py --help
Usage: docstring.py [OPTIONS]
Great parameters:
--and-two=STR Documentation for the second parameter.
--one=STR Documentation for the first parameter.
Not-so-great parameters:
--three=STR Documentation for the third parameter.
Other actions:
-h, --help Show the help
Unformatted paragraphs¶
You can insert unformatted text (for instance, code examples) by
finishing a paragraph with a colon (:
) and starting the unformatted text with at
least one space of indentation:
from clize import run
def func():
"""
This text
is automatically formatted.
However, you may present code blocks like this:
Unformatted text
More unformatted
text.
"""
$ python docstring.py --help
Usage: docstring.py
This text is automatically formatted. However, you may present code blocks
like this:
Unformatted text
More unformatted
text.
Other actions:
-h, --help Show the help
run(func)
A paragraph with just a colon (:
) will be omitted from the output, but still
trigger unformatted text.
API Reference¶
Running functions¶
-
clize.
run
(*fn, args=None, catch=(), exit=True, out=None, err=None, **kwargs)[source]¶ Runs a function or CLI object with
args
, prints the return value if not None, or catches the given exception types as well asclize.UserError
and prints their string representation, then exit with the appropriate status code.Parameters: - args (sequence) – The arguments to pass the CLI, for instance
('./a_script.py', 'spam', 'ham')
. If unspecified, usessys.argv
. - catch (sequence of exception classes) – Catch these exceptions and print their string representation rather than letting Python print an uncaught exception traceback.
- exit (bool) – If true, exit with the appropriate status code once the function is done.
- out (file) – The file in which to print the return value of the
command. If unspecified, uses
sys.stdout
- err (file) – The file in which to print any exception text.
If unspecified, uses
sys.stderr
.
- args (sequence) – The arguments to pass the CLI, for instance
-
class
clize.
Clize
(fn=None, **kwargs)[source]¶ Wraps a function into a CLI object that accepts command-line arguments and translates them to match the wrapped function’s parameters.
Parameters: - alt (sequence) – Alternate actions the CLI will handle.
- help_names (sequence of strings) – Names to use to trigger the help.
- helper_class (a type like
ClizeHelp
) – A callable to produce a helper object to be used when the help is triggered. If unset, usesClizeHelp
. - hide_help (bool) – Mark the parameters used to trigger the help as undocumented.
-
parameters
()[source]¶ Returns the parameters used to instantiate this class, minus the wrapped callable.
-
classmethod
keep
(fn=None, **kwargs)[source]¶ Instead of wrapping the decorated callable, sets its
cli
attribute to aClize
instance. Useful if you need to use the decorator but must still be able to call the function regularily.
-
classmethod
as_is
(obj=None, *, description=None, usages=None)[source]¶ Returns a CLI object which uses the given callable with no translation.
The following parameters improve the decorated object’s compatibility with Clize’s help output:
Parameters: - description – A description for the command.
- usages – A list of usages for the command.
-
classmethod
get_cli
(obj, **kwargs)[source]¶ Makes an attempt to discover a command-line interface for the given object.
The process used is as follows:
- If the object has a
cli
attribute, it is used with no further transformation. - If the object is callable,
Clize
or whichever object this class method is used from is used to build a CLI.**kwargs
are forwarded to its initializer. - If the object is iterable,
SubcommandDispatcher
is used on the object, and itscli
method is used.
Most notably,
clize.run
uses this class method in order to interpret the given object(s).- If the object has a
-
helper
[source]¶ A cli object(usually inherited from
help.Help
) when the user requests a help message. See the constructor for ways to affect this attribute.
-
signature
[source]¶ The
parser.CliSignature
object used to parse arguments.
-
read_commandline
(args)[source]¶ Reads the command-line arguments from args and returns a tuple with the callable to run, the name of the program, the positional and named arguments to pass to the callable.
Raises: ArgumentError
Parser¶
-
class
clize.parser.
CliSignature
(parameters)[source]¶ A collection of parameters that can be used to translate CLI arguments to function arguments.
Parameters: parameters (iterable) – The parameters to use. -
converter
= clize.parser.default_converter¶ The converter used by default in case none is present in the annotations.
-
parameters
¶ An ordered dict of all parameters of this cli signature.
-
positional
¶ List of positional parameters.
-
alternate
¶ List of parameters that initiate an alternate action.
-
aliases
= {}¶ Maps parameter names to
NamedParameter
instances.
-
required
= set()¶ A set of all required parameters.
-
classmethod
from_signature
(sig, extra=(), **kwargs)[source]¶ Takes a signature object and returns an instance of this class deduced from it.
Parameters: - sig (inspect.Signature) – The signature object to use.
- extra (iterable) – Extra parameter instances to include.
-
read_arguments
(args, name)[source]¶ Returns a
CliBoundArguments
instance for this CLI signature bound to the given arguments.Parameters: - args (sequence) – The CLI arguments, minus the script name.
- name (str) – The script name.
-
-
clize.parser.
parameter_converter
(obj)[source]¶ Decorates a callable to be interpreted as a parameter converter when passed as an annotation.
It will be called with an
inspect.Parameter
object and a sequence of objects passed as annotations, without the parameter converter itself. It is expected to return aclize.parser.Parameter
instance orParameter.IGNORE
.
-
clize.parser.
default_converter
(param, annotations)¶ The default parameter converter. It is described in detail in The default parameter converter.
-
clize.parser.
use_class
(*, pos=<function unimplemented_parameter at 0x7ffbd56e9840>, varargs=<function unimplemented_parameter at 0x7ffbd56e9840>, named=<function unimplemented_parameter at 0x7ffbd56e9840>, varkwargs=<function unimplemented_parameter at 0x7ffbd56e9840>, kwargs={})[source]¶ Creates a parameter converter similar to the default converter that picks one of 4 factory functions depending on the type of parameter.
Parameters: - pos (callable that returns a
Parameter
instance) – The parameter factory for positional parameters. - varargs (callable that returns a
Parameter
instance) – The parameter factory for*args
-like parameters. - named (callable that returns a
Parameter
instance) – The parameter factory for keyword parameters. - varkwargs (callable that returns a
Parameter
instance) – The parameter factory for**kwargs
-like parameters. - kwargs (collections.abc.Mapping) – additional arguments to pass to the chosen factory.
- pos (callable that returns a
-
clize.parser.
use_mixin
(cls, *, kwargs={})[source]¶ Like
use_class
, but creates classes inheriting fromcls
and one ofPositionalParameter
,ExtraPosArgsParameter
, andOptionParameter
Parameters: - cls – The class to use as mixin.
- kwargs (collections.abc.Mapping) – additional arguments to pass to the chosen factory.
-
class
clize.parser.
CliBoundArguments
(sig, args, name)[source]¶ Command line arguments bound to a
CliSignature
instance.Parameters: - sig (CliSignature) – The signature to bind against.
- args (sequence) – The CLI arguments, minus the script name.
- name (str) – The script name.
-
sig
¶ The signature being bound to.
-
in_args
¶ The CLI arguments, minus the script name.
-
name
¶ The script name.
-
args
= []¶ List of arguments to pass to the target function.
-
kwargs
= {}¶ Mapping of named arguments to pass to the target function.
-
meta
= {}¶ A dict for parameters to store data for the duration of the argument processing.
-
post_name
= []¶ List of words to append to the script name when passed to the target function.
The following attributes only exist while arguments are being processed:
-
posparam
= iter(sig.positional)¶ The iterator over the positional parameters used to process positional arguments.
-
skip
= 0¶ Amount of arguments to skip.
-
unsatisfied
= set(<required parameters>)¶ Required parameters that haven’t yet been satisfied.
-
class
clize.parser.
Parameter
(display_name, undocumented=False, last_option=None)[source]¶ Bases:
object
Represents a CLI parameter.
Parameters: - display_name (str) – The ‘default’ representation of the parameter.
- undocumented (bool) – If true, hides the parameter from the command help.
- last_option – If
True
, the parameter will set theposarg_only
flag on the bound arguments.
Also available as
clize.Parameter
.-
LAST_OPTION
= clize.Parameter.LAST_OPTION¶ Annotate a parameter with this and all following arguments will be processed as positional.
-
IGNORE
= clize.Parameter.IGNORE¶ Annotate a parameter with this and it will be dropped from the resulting CLI signature.
-
UNDOCUMENTED
= clize.Parameter.UNDOCUMENTED¶ Parameters annotated with this will be omitted from the documentation (
--help
).
-
REQUIRED
= clize.Parameter.REQUIRED¶ Annotate a parameter with this to force it to be required.
Mostly only useful for
*args
parameters. In other cases, simply don’t provide a default value.
-
required
= False¶ Is this parameter required?
-
is_alternate_action
= False¶ Should this parameter appear as an alternate action or as a regular parameter?
-
extras
= ()¶ Iterable of extra parameters this parameter incurs
-
display_name
= None¶ The name used in printing this parameter.
-
undocumented
= None¶ If true, this parameter is hidden from the documentation.
-
last_option
= None¶ If true, arguments after this parameter is triggered will all be processed as positional.
-
read_argument
(ba, i)[source]¶ Reads one or more arguments from
ba.in_args
from positioni
.Parameters: - ba (clize.parser.CliBoundArguments) – The bound arguments object this call is expected to mutate.
- i (int) – The current position in
ba.args
.
-
apply_generic_flags
(ba)[source]¶ Called after
read_argument
in order to set attributes onba
independently of the arguments.Parameters: ba (clize.parser.CliBoundArguments) – The bound arguments object this call is expected to mutate. The base implementation of this method applies the
last_option
setting if applicable and discards itself fromCliBoundArguments.unsatisfied
-
unsatisfied
(ba)[source]¶ Called after processing arguments if this parameter required and not discarded from
CliBoundArguments.unsatisfied
.
-
show_help
(desc, after, f, cols)[source]¶ Called by
ClizeHelp
to produce the parameter’s description in the help output.
-
show_help_parens
()[source]¶ Return a string to complement a parameter’s description in the
--help
output.
-
help_parens
()[source]¶ Return an iterable of strings to complement a parameter’s description in the
--help
output. Used byshow_help_parens
-
class
clize.parser.
ParameterWithSourceEquivalent
(argument_name, **kwargs)[source]¶ Bases:
clize.parser.Parameter
Parameter that relates to a function parameter in the source.
Parameters: argument_name (str) – The name of the parameter.
-
class
clize.parser.
HelperParameter
(**kwargs)[source]¶ Bases:
clize.parser.Parameter
Parameter that doesn’t appear in CLI signatures but is used for instance as the
.sticky
attribute of the bound arguments.
-
class
clize.parser.
ParameterWithValue
(conv=<function identity at 0x7ffbd56e8ea0>, default=<unset>, **kwargs)[source]¶ Bases:
clize.parser.Parameter
A parameter that takes a value from the arguments, with possible default and/or conversion.
Parameters: - conv (callable) – A callable to convert the value or raise
ValueError
. Defaults toidentity
. - default – A default value for the parameter or
util.UNSET
.
-
conv
= None¶ The function used for coercing the value into the desired format or type.
-
default
= None¶ The default value used for the parameter, or
util.UNSET
if there is no default value. Usually only used for displaying the help.
-
required
¶ Tells if the parameter has no default value.
-
coerce_value
(arg, ba)[source]¶ Coerces
arg
using theconv
function. Raiseserrors.BadArgumentFormat
if the coercion function raisesValueError
.
- conv (callable) – A callable to convert the value or raise
-
clize.parser.
value_converter
(func=None, *, name=None)[source]¶ Callables decorated with this can be used as a value converter.
-
class
clize.parser.
NamedParameter
(aliases, **kwargs)[source]¶ Bases:
clize.parser.Parameter
Equivalent of a keyword-only parameter in Python.
Parameters: aliases (sequence of strings) – The arguments that trigger this parameter. The first alias is used to refer to the parameter. The first one is picked as display_name
if unspecified.-
aliases
= None¶ The parameter’s aliases, eg. “–option” and “-o”.
-
classmethod
alias_key
(name)[source]¶ Sort key function to order aliases in source order, but with short forms(one dash) first.
-
short_name
¶ Retrieves the shortest alias for displaying the parameter signature.
-
-
class
clize.parser.
FlagParameter
(value, **kwargs)[source]¶ Bases:
clize.parser.OptionParameter
A named parameter that takes no argument.
Parameters: - value – The value when the argument is present.
- false_value – The value when the argument is given one of the
false value triggers using
--param=xyz
.
-
required
= False¶
-
false_triggers
= ('0', 'n', 'no', 'f', 'false')¶ Values for which
--flag=X
will consider the argument false and will passfalse_value
to the function. In all other casesvalue
is passed.
-
value
= None¶ The value passed to the function if the flag is triggered without a specified value.
-
read_argument
(ba, i)[source]¶ Overrides
NamedParameter
‘s value-getting behavior to allow no argument to be passed after the flag is named.
-
class
clize.parser.
OptionParameter
(aliases, **kwargs)[source]¶ Bases:
clize.parser.NamedParameter
,clize.parser.ParameterWithValue
,clize.parser.ParameterWithSourceEquivalent
A named parameter that takes an argument.
-
read_argument
(ba, i)[source]¶ Stores the argument in
CliBoundArguments.kwargs
if it isn’t already present.
-
-
class
clize.parser.
IntOptionParameter
(aliases, **kwargs)[source]¶ Bases:
clize.parser.OptionParameter
A named parameter that takes an integer as argument. The short form of it can be chained with the short form of other named parameters.
-
class
clize.parser.
PositionalParameter
(conv=<function identity at 0x7ffbd56e8ea0>, default=<unset>, **kwargs)[source]¶ Bases:
clize.parser.ParameterWithValue
,clize.parser.ParameterWithSourceEquivalent
Equivalent of a positional-only parameter in Python.
-
read_argument
(ba, i)[source]¶ Stores the argument in
CliBoundArguments.args
.
-
-
class
clize.parser.
MultiParameter
(min, max, **kwargs)[source]¶ Bases:
clize.parser.ParameterWithValue
Parameter that can collect multiple values.
-
min
= None¶ The minimum amount of values this parameter accepts.
-
max
= None¶ The maximum amount of values this parameter accepts.
-
required
¶ Returns if there is a minimum amount of values required.
-
read_argument
(ba, i)[source]¶ Adds passed argument to the collection returned by
get_collection
.
-
-
class
clize.parser.
ExtraPosArgsParameter
(required=False, min=None, max=None, **kwargs)[source]¶ Bases:
clize.parser.MultiParameter
,clize.parser.PositionalParameter
Parameter that forwards all remaining positional arguments to the callee.
Used to convert
*args
-like parameters.-
get_collection
(ba)[source]¶ Uses
CliBoundArguments.args
to collect the remaining arguments.
-
-
class
clize.parser.
AppendArguments
(**kwargs)[source]¶ Bases:
clize.parser.HelperParameter
,clize.parser.MultiParameter
Helper parameter that collects multiple values to be passed as positional arguments to the callee.
Similar to
ExtraPosArgsParameter
but does not correspond to a parameter in the source.-
get_collection
(ba)[source]¶ Uses
CliBoundArguments.args
to collect the remaining arguments.
-
-
class
clize.parser.
IgnoreAllArguments
(**kwargs)[source]¶ Bases:
clize.parser.HelperParameter
,clize.parser.Parameter
Helper parameter for
FallbackCommandParameter
that ignores the remaining arguments.
-
class
clize.parser.
FallbackCommandParameter
(func, **kwargs)[source]¶ Bases:
clize.parser.NamedParameter
Parameter that sets an alternative function when triggered. When used as an argument other than the first all arguments are discarded.
-
is_alternate_action
= True¶
-
func
= None¶ The function that will be called if this parameter is mentionned.
-
-
class
clize.parser.
AlternateCommandParameter
(func, **kwargs)[source]¶ Bases:
clize.parser.FallbackCommandParameter
Parameter that sets an alternative function when triggered. Cannot be used as any argument but the first.
Exceptions¶
-
exception
clize.errors.
UserError
[source]¶ Bases:
ValueError
An error to be printed to the user.
-
exception
clize.errors.
ArgumentError
(message=None)[source]¶ Bases:
clize.errors.UserError
An error related to the arguments passed through the command-line interface
-
exception
clize.errors.
MissingRequiredArguments
(missing)[source]¶ Bases:
clize.errors.ArgumentError
Raised when required parameters have not been provided an argument
-
exception
clize.errors.
TooManyArguments
(extra)[source]¶ Bases:
clize.errors.ArgumentError
Raised when too many positional arguments have been passed for the parameters to consume.
-
exception
clize.errors.
DuplicateNamedArgument
(message=None)[source]¶ Bases:
clize.errors.ArgumentError
Raised when a named option or flag has been passed twice.
-
exception
clize.errors.
UnknownOption
(name)[source]¶ Bases:
clize.errors.ArgumentError
Raised when a named argument has no matching parameter.
-
exception
clize.errors.
MissingValue
(message=None)[source]¶ Bases:
clize.errors.ArgumentError
Raised when an option received no value.
-
exception
clize.errors.
NotEnoughValues
(message=None)[source]¶ Bases:
clize.errors.ArgumentError
Raised when MultiOptionParameter is given less values than its min parameter.
-
exception
clize.errors.
TooManyValues
(message=None)[source]¶ Bases:
clize.errors.ArgumentError
Raised when MultiOptionParameter is given more values than its max parameter.
-
exception
clize.errors.
CliValueError
[source]¶ Bases:
ValueError
Specialization of
ValueError
for showing a message to the user along with the error rather than just the incorrect value.
-
exception
clize.errors.
BadArgumentFormat
(text)[source]¶ Bases:
clize.errors.ArgumentError
Raised when an argument cannot be converted to the correct format.
-
exception
clize.errors.
ArgsBeforeAlternateCommand
(param)[source]¶ Bases:
clize.errors.ArgumentError
Raised when there are arguments before a non-fallback alternate command.
-
class
clize.errors.
SetErrorContext
(exc_type, **attributes)[source]¶ Bases:
object
Context manager that sets attributes on exceptions that are raised past it
Parameters: - exc_type – The exception type to operate on.
- attributes – The attributes to set on the matching exceptions. They will only be set if yet unset on the exception.
Compability with older clize releases¶
-
clize.
clize
(fn=None, *, alias={}, force_positional=(), coerce={}, require_excess=False, extra=(), use_kwoargs=None)[source]¶ Compatibility with clize<3.0 releases. Decorates a function in order to be passed to
clize.run
. See Upgrading from clize 1 and 2.
-
clize.
make_flag
(source, names, default=False, type=None, help='', takes_argument=0)[source]¶ Compatibility with clize<3.0 releases. Creates a parameter instance. See Upgrading from clize 1 and 2.
Project documentation¶
Information on how Clize is organized as a project.
Release notes¶
3.0 (2015-05-13)¶
Version 3.0 packs a full rewrite. While it retains backwards-compatibility, the old interface is deprecated. See Upgrading from clize 1 and 2.
- The argument parsing logic has been split between a loop over the parameters and parameter classes. New parameter classes can be made to implement cusom kinds of parameters.
- The CLI inference is now based on
sigtools.specifiers.signature
rather thaninspect.getfullargspec
. This enables a common interface for the function signature to be manipulated prior to being passed to Clize. Namely, the__signature__
attribute can be overriden orsigtools
‘s lazyforger_function
method can be employed. - The
@clize
decorator is deprecated in favor of directly passing functions torun
, thus leaving the original function intact. - Named parameters are now obtained exclusively through keyword-only
parameters. Other information about each parameter is communicated through
parameter annotations.
sigtools.modifiers
provides backwards-compatibility for Python 2. - As a result of implementing the function signature-based abstraction, there are ways to set up decorators that work with Clize.
- The help system now accepts subsection headers for named parameters.
- Coercion functions have been renamed to value converters. Except for a few notable exceptions, they must be tagged with a decorator. This also applies to the type of supplied default values.
- Alternate actions (for instance
--version
) can be supplied directly to run. - Several Parameter converter annotations have been added, including parameters with a limited choice of values, repeatable parameters, parameters that always supply the same value, and more.
2.0 (2012-10-07)¶
This release and earlier were documented post-release.
Version 2.0 adds subcommands and support for function annotations and keyword-only parameters.
1.0 (2011-04-04)¶
Initial release.
Contributing¶
Thanks for considering helping out. We don’t bite. :-)
Reporting issues¶
Bugs and other tasks are tracked on GitHub.
Check whether the issue exists already. (Be sure to also check closed ones.)
Report which version of Clize the issue appears on. You can obtain it using:
pip show clize
For documentation-related bugs, you can either look at the version in the page URL, click the “Read the docs” insigna in the bottom-left corner or the hamburger menu on mobile.
When applicable, show how to trigger the bug and what was expected instead. Writing a testcase for it is welcome, but not required.
Submitting patches¶
Patches are submitted for review through GitHub pull requests.
- Follow PEP 8.
- When fixing a bug, include a test case in your patch. Make sure correctly tests against the bug: It must fail without your fix, and succeed with it. See Running the test suite.
- Submitting a pull request on GitHub implies your consent for merging, therefore authorizing the maintainer(s) to distribute your modifications under the project’s license.
Implementing new features¶
Before implementing a new feature, please open an issue on GitHub to discuss it. This ensures you do not work on a feature that would be refused inclusion.
Add tests for your feature to the test suite and make sure it completes
on all supported versions of Python. Make sure it is fully
tested using the cover
target.
Feel free to submit a pull request as soon as you have changes you need feedback on. In addition, TravisCI will run the test suite on all supported platforms and will perform coverage checking for you on the pull request page.
Running the test suite¶
The test suite can be run across all supported versions using, tox
:
pip install --user tox
tox
If you do not have all required Python versions installed or wish to save time when testing you can specify one version of Python to test against:
tox -e pyXY
Where X
and Y
designate a Python version as in X.Y
. For instance,
the following command runs the test suite against Python 3.4 only:
tox -e py34
Branches linked in a pull request will be run through the test suite on TravisCI and the results are linked back in the pull request. You can use this if installing all supported Python versions is impreactical for you.
coverage.py is used to measure code coverage. New code is expected to have full code coverage. You can run the test suite through it using:
tox -e cover
It will print the measured code coverage and generate webpages with
line-by-line coverage information in htmlcov
. Note that the cover
target requires Python 3.4.