args
import args
This module provides a complete, batteries-included framework for
building command-line interfaces. It supports options (flags),
positional arguments, sub-commands with their own option sets, automatic
help generation, type coercion, required arguments, deprecation
warnings, choice validation, abbreviated long-option matching, --
end-of-options, and @file argument expansion.
How a value reaches an option
A long option takes its value either as the next argument or attached
with =; both spellings mean the same thing:
$ zuri run myprogram.zu --name Alice
$ zuri run myprogram.zu --name=Alice
The split is on the first =, so --path=a=b sets path to a=b. The
attached form is the only way to pass a value that begins with a dash,
since --name -5 reads -5 as an option:
$ zuri run myprogram.zu --offset=-5
A short option takes its value as the next argument only. -n Alice
works; -n=Alice does not, because a short token is a bundle of
single-character flags and = is not one of them. Every character in
such a bundle has to name an option, so a typo in -vq is an error
rather than a silently dropped flag.
Quick start
import args
var parser = args.Parser('myprogram')
parser.description = 'A friendly CLI tool.'
parser.add_option('name', 'Person to greet', {short_name: 'n', type: args.STRING})
parser.add_option('count', 'Number of greetings', {short_name: 'c', type: args.INT, value: 1})
var cmd = parser.add_command('call', 'Make a phone call')
cmd.add_option('verbose', 'Enable verbose output', {short_name: 'v'})
parser.parse()
Running the following command:
zuri run myprogram.zu -h
Prints the following help output:
Usage: myprogram [OPTIONS] [COMMAND]
A friendly CLI tool.
OPTIONS:
-h, --help Show this help message and exit
-n, --name <name> Person to greet
-c, --count <count> Number of greetings (default: 1)
COMMANDS:
call Make a phone call
Run "myprogram --help [COMMAND]" for help on a specific command.
Typical invocations:
$ zuri run myprogram.zu -h
$ zuri run myprogram.zu --name Alice --count 3
$ zuri run myprogram.zu call --verbose
$ zuri run myprogram.zu call --help
If we change the last line of the program to echo parser.parse() so
that we can see the result of the parsing, the following CLI call will
yield the given result.
$ zuri run myprogram.zu --name "Kirk"
{options: {name: Kirk, count: 1}, command: nil, indexes: []}
$ zuri run myprogram.zu call
{options: {count: 1}, command: {name: call, value: nil}, indexes: []}
$ zuri run myprogram.zu call -v
{options: {verbose: true, count: 1}, command: {name: call, value: nil}, indexes: []}
Calling name without an option will yield the following result/error:
$ zuri run myprogram.zu --name
error: option --name expects <name>
You may even get help on a command directly like below:
$ zuri run myprogram.zu --help call
Usage: myprogram call [OPTIONS]
Make a phone call
OPTIONS:
-v, --verbose Enable verbose output
GLOBAL OPTIONS:
-h, --help Show this help message and exit
-n, --name <name> Person to greet
-c, --count <count> Number of greetings (default: 1)
Options declared on the parser itself are global: they are accepted before a command and after it alike, and a command’s help lists them under GLOBAL OPTIONS. When a command declares an option of the same name, that option is the one its arguments reach.
Return value of parse() is in the format:
{
options: {name: 'Alice', count: 3},
command: {name: 'call', value: nil},
indexes: []
}
The args API
Every public name in args, wherever it is declared. Each links to the
page that documents it.
| Name | Kind | Summary |
|---|---|---|
args.ArgsError | class | Error raised for argument parsing errors. |
args.BOOL | constant | value type boolean (accepts 1/0, true/false, yes/no, on/off). |
args.CHOICE | constant | value type choice: value must be one of the choices list/dict |
args.INT | constant | value type integer (accepts numbers, floors to integer) |
args.LIST | constant | value type list: the option may be supplied multiple times |
args.NONE | constant | value type none: the option is a boolean flag |
args.NUMBER | constant | value type number |
args.OPTIONAL | constant | value type optional: value is consumed if the next token is not a flag |
args.Parser | class | A configurable command-line parser. |
args.STRING | constant | value type string |
Constants
NONE
args.NONE = 0
value type none: the option is a boolean flag
INT
args.INT = 1
value type integer (accepts numbers, floors to integer)
NUMBER
args.NUMBER = 2
value type number
BOOL
args.BOOL = 3
value type boolean (accepts 1/0, true/false, yes/no,
on/off).
STRING
args.STRING = 4
value type string
LIST
args.LIST = 5
value type list: the option may be supplied multiple times
CHOICE
args.CHOICE = 6
value type choice: value must be one of the choices list/dict
OPTIONAL
args.OPTIONAL = 7
value type optional: value is consumed if the next token is not a flag
Classes
ArgsError
class args.ArgsError < Error
Error raised for argument parsing errors.
Parser
class args.Parser < _Optionable
A configurable command-line parser.
Properties you can set after construction
description(string): paragraph shown between USAGE and OPTIONS.epilog(string): paragraph shown after all sections.allow_abbrev(bool): allow unambiguous long-option prefix matching. Defaults totrue, like Python’s argparse.allow_atfile(bool): expand@filenametokens by reading arguments from that file. Defaults totrue.
Fields
| Field | Type | Description |
|---|---|---|
commands | List of sub-commands registered with add_command. | |
indexes | List of positional arguments registered with add_index. | |
description | ||
epilog | ||
allow_abbrev | ||
allow_atfile | ||
terminal_width | The column width help text wraps to. |
Constructor
args.Parser(name, default_help)
Creates a new parser instance.
Parameters
name(string) — The program name shown in usage lines.default_help(?bool) — Show help when invoked with no arguments. Defaults totrue.
Parser.set_terminal_width()
args.Parser.set_terminal_width(width)
Overrides the column width help text wraps to, in place of the
terminal_width this parser auto-detected at construction time (a real
query of the terminal, the COLUMNS environment variable, or 80, in
that order of preference; see _terminal_width()). Useful both for a
program that wants a fixed layout regardless of environment, and for
tests that need deterministic wrapping independent of whatever terminal
actually ran them.
Equivalent to setting terminal_width directly; this exists purely for
discoverability and to validate its argument.
Parameters
width(number)
Parser.add_option()
args.Parser.add_option(name, help, opts)
Adds an option (flag) to the top-level parser.
opts keys can include any of:
short_name(string): single-character alias (-x).type(int): one of the type constants; defaultNONE.value(any): default value when the option is absent.choices(list|dict): restrict allowed values.required(bool): error if the option is absent.metavar(string): placeholder shown in help, defaulting to the option’s own name, lower-cased.deprecated(bool): print a warning when the option is used.
Parameters
name(string)help(?string)opts(?dict)
Parser.add_command()
args.Parser.add_command(name, help, opts)
Adds a sub-command.
opts keys: - type {int}: expected type for the command’s value
argument - action {function}: called with (options [, value]) after
parsing - choices {list|dict}— restrict allowed values when type is
CHOICE - metavar {string}: placeholder shown in help for the
command’s value, e.g. 'message' for git commit -m <message>
(default: the value type’s name, lower-cased)
Returns the _Command object so you can chain add_option calls:
parser.add_command('push', 'Push changes').
add_option('force', 'Force push', {short_name: 'f'})
Parameters
name(string)help(?string)opts(?dict)
Returns — _Command
Parser.add_index()
args.Parser.add_index(name, help, opts)
Adds a positional (index-based) argument.
opts keys: - type {int}: coercion type; default STRING - value
{any}: default when argument is absent - choices {list|dict}: restrict
allowed values - required {bool}: error if argument is absent (default
false) - metavar {string}: display name in help
Without a value, a positional nobody supplied is simply missing from
parse()’s indexes rather than sitting there as nil.
A positional of type LIST takes every positional word from where it
starts to the end of the command line, flags in between or not, and
arrives in indexes as one list. It has to be the last positional
declared, since nothing after it could ever receive a word.
Parameters
name(string)help(?string)opts(?dict)
Raises ArgsError when a positional is added after a LIST one.
Parser.parse()
args.Parser.parse(custom_args: ?list) -> dict
Parses command-line arguments and returns a dictionary of command, options, and indexes.
By default this reads the real process arguments (os.args, skipping
the interpreter and script path). Pass custom_args (a list of strings)
to parse something else instead, e.g. a config-driven argument list, or
a fixed list in a test.
Result shape:
{
options: dict, # collected option values
command: nil | {name, value}, # command name and value (if any)
indexes: list # collected positional values
}
indexes holds one entry per positional that has a value, in the order
they were declared: what the user supplied, then the declared default of
any that follow. A positional that was not supplied and has no default
is absent rather than nil, so indexes.is_empty() and
indexes.length() answer what they look like they answer, and a program
that wants its own fallback can reach for it:
var path = parsed.indexes.is_empty() ? os.cwd() : parsed.indexes[0]
Parameters
custom_args(?list)
Returns dict
Parser.help()
args.Parser.help()
Print the full help text and exit(0).
2021, Richard Ore and Zuri contributors