Pyjo.GetOpt - Command line options

from Pyjo.GetOpt import GetOpt

getopt = GetOpt()

# The value goes to the result
getopt.option('m|mode=s')

opts = getopt.parse(['-m', 'production', 'myapp.py'])
if not opts:
    raise SystemExit('Usage: ...')
print(opts.mode)

# Or import the module, as in Google Python Style Guide

import Pyjo.GetOpt

getopt = Pyjo.GetOpt.new()

# The value goes to the result
getopt.option('m|mode=s')

# The values go to a list
listen = []
getopt.option('l|listen=s', listen)

# A callback gets the value
@getopt.on('i|inactivity-timeout=i')
def timeout(name, value):
    print(f'{name}: {value}')

opts = getopt.parse(['-m', 'production', '-l', 'http://*:8080', 'myapp.py'])
if not opts:
    raise SystemExit('Usage: ...')
print(opts.mode)

Pyjo.GetOpt extracts options from a list of command line arguments, the way Getopt::Long of Perl does with the configuration that Pyjo.Util.getopt() gives it, as the commands of Mojolicious do. It is the engine of Pyjo.Util.getopt(), with decorators for the callbacks of the options.

An option is -name or --name, with its value after it or after =, as --mode production, --mode=production or -m production. The names are case sensitive and are not abbreviated, and the options of a single letter are not bundled. The arguments that are not options stay in the list, in their order, and -- ends the options.

An unknown option, an option without its value and a value of a wrong type are errors: their messages go to sys.stderr, as warnings, the parsing goes on, and the result is false.

Options

The specification of an option is its names, separated by |, and what it takes.

# A flag, True
getopt.option('v|verbose')

# A flag that --no-color and --nocolor negate, False
getopt.option('color!')

# A counter, which each -v increments
getopt.option('v|verbose+')

# A string, an integer or a float
getopt.option('m|mode=s')
getopt.option('b|backlog=i')
getopt.option('r|ratio=f')

# An optional value, which is "" or 0 without it
getopt.option('p|proxy:s')

# A list of values in the result
getopt.option('H|header=s@')

# A dict of the keys and the values of --define key=value in the result
getopt.option('D|define=s%')

Next to what Getopt::Long has, an option can have a default, a type, which converts its value, and the values that it accepts, as the arguments of argparse.

getopt.option('M|method=s', default='GET')
getopt.option('home=s', type=Pyjo.File.path)
getopt.option('m|mode=s', choices=['development', 'production'])

The name of an option in the result, and the name that a callback gets, is its first name that is longer than one letter, or its only name, with _ for -: inactivity_timeout for i|inactivity-timeout=i.

Environment

With env_prefix, an option that is not given has the value of the environment variable of the prefix and its name in upper case, as PYJO_INACTIVITY_TIMEOUT for i|inactivity-timeout=i, which is converted and checked as a value of the command line, before the default, the way Cobra and Viper of Go have it. An option of one letter has none, and an empty variable is not set. A flag is false as 0, false, no or off, a counter is the number, and an option of a list or a dict takes values separated by commas, as PYJO_LISTEN=http://*:80,https://*:443.

# PYJO_WORKERS=12 python myapp.py prefork
getopt = Pyjo.GetOpt.new(env_prefix='PYJO_').option('w|workers=i', default=4)

The other way around, the target env() sets an environment variable to the value of an option, as a script of Mojolicious binds an option to $ENV{...}, for the code that reads the variable later, as the application its mode.

# python myapp.py --mode production sets PYJO_MODE
getopt = Pyjo.GetOpt.new().option('m|mode=s', Pyjo.GetOpt.env('PYJO_MODE'))

Usage

The usage of a command, which Pyjo.Util.extract_usage() reads from its documentation, lists its options in a block after a line Options:, an option with a short name as -h, --help or -V, and one with a long name only as `` –home <path>``, aligned with the long names of the others, and its description after them, in a column of its own. format_usage() lays out these blocks, so that a new option or a longer one needs no alignment by hand.

Options:
  -h, --help          Show this summary of available options
      --home <path>   Path to home directory of your application, defaults to
                      the value of PYJO_HOME or auto-detection

See also

Pyjo.Util.getopt(), https://mojolicious.org.

Inspired by Getopt::Long::Parser, the object interface of Getopt::Long, which getopt of Mojo::Util configures.

Classes

class Pyjo.GetOpt.Pyjo_GetOpt(*, pass_through: bool = False, env_prefix: str | None = None)[source]

Pyjo.GetOpt inherits all methods from Pyjo.Base and implements the following new ones.

on(spec: str, cb: None = None, *, type: Callable[[Any], Any] | None = None, choices: Sequence[Any] | None = None) → Callable[[F], F][source]
on(spec: str, cb: F, *, type: Callable[[Any], Any] | None = None, choices: Sequence[Any] | None = None) → F
cb = getopt.on('b|backlog=i', lambda name, value: ...)

@getopt.on('b|backlog=i')
def backlog(name, value): ...

Add an option whose callback gets its name and its value, or a tuple of the key and the value of a hash, as a decorator without the callback. type and choices are those of option().

option(spec: str, target: Target = None, *, default: Any = None, type: Callable[[Any], Any] | None = None, choices: Sequence[Any] | None = None) → Self[source]
getopt = getopt.option('m|mode=s')
getopt = getopt.option('l|listen=s', [])
getopt = getopt.option('D|define=s%', {})
getopt = getopt.option('b|backlog=i', lambda name, value: ...)
getopt = getopt.option('M|method=s', default='GET')
getopt = getopt.option('home=s', type=Pyjo.File.path)
getopt = getopt.option('m|mode=s', choices=['development', 'production'])

Add an option, whose value goes to the result, to a list, to a dict or to a callback. default is the value in the result of an option that is not given. type converts a value, after the type of the specification, and a ValueError, a TypeError or a LookupError of it makes the value invalid, as a value that is not in choices.

parse(args: list[str] | None = None) → Pyjo_GetOpt_Result[source]
opts = getopt.parse()
opts = getopt.parse(['--mode', 'production', 'myapp.py'])

Extract the options from the list of arguments, which defaults to the ones of sys.argv, and remove them from it. The result has the values of the options without a target, and is false after an error.

class Pyjo.GetOpt.Pyjo_GetOpt_Result(values: dict[str, Any], success: bool)[source]

The result of parse(), the values of the options as attributes, which is false after an error.

Pyjo.GetOpt.env(name: str) → Callable[[str, Any], None][source]
target = Pyjo.GetOpt.env('PYJO_MODE')

A target of an option that sets the environment variable name to its value, 1 for a flag and 0 for a negated one, see Environment.

# --foreground sets PYJO_HOT_FOREGROUND to 1
getopt.option('f|foreground', Pyjo.GetOpt.env('PYJO_HOT_FOREGROUND'))
Pyjo.GetOpt.format_usage(usage: str, width: int = 77) → str[source]
usage = Pyjo.GetOpt.format_usage(usage)
usage = Pyjo.GetOpt.format_usage(usage, width=79)

Lay out the blocks of options of a usage message, see Usage: the descriptions in a column three spaces after the longest option of the block, wrapped to the width of the lines, 77 by default, and the rest of the message as it is.

# The usage of a command, laid out
print(Pyjo.GetOpt.format_usage(extract_usage()))