Extended features for the Python click library
Project description
clickext
Extended features for the Python click library. Includes global logging configuration and error handling for pretty console output, aliased commands, command groups with global and shared subcommand options, mutually exclusive options, verbosity level options, and a configuration file option.
Requirements
- Python 3.10.x, 3.11.x
- click 8.x.x
Installation
pip install clickext
Usage
Logging and Error Messages
This functionality is disabled by default. It must be explicitly enabled by calling clickext.init_logging
or using the clickext.verbose
or clickext.verbosity
decorators on a command.
The logging facility provides a way to capture all informational output, emit console-friendly messages, and control the output that is displayed based on the logging level. click.ClickException
, click.UsageError
, their children, warnings issued by warning.warn
and any uncaught exceptions are handled by the clickext.log.ConsoleHandler
. Exception information, including the traceback, is available when the log level is set to logging.DEBUG
. Higher log levels will only print a user-friendly error message. The default level is logging.INFO
.
All informational messages intended for the console that an application user may want to suppress should be sent in a logging call rather than direct calls to print
, click.echo
, or similar, so they can be handled and displayed consistently according to the logging configuration. Messages that should always be displayed (e.g., the expected result of an invoked command) should be displayed with click.echo
and not sent to a logger.
Messages are formatted by default with a styled log level prefix followed by the message, except for logging.INFO
level messages which are not prefixed. The style for each level can be customized by passing a mapping of log levels to click.style
parameters in the clickext.init_logging
call. Setting a level to None
will remove the prefix and styles from the message. For example: {logging.INFO: {"fg": "green"}, logging.DEBUG: None}
will format logging.INFO
level messages as "Info: {msg}", with "Info:" in green text, and logging.DEBUG
messages as "{msg}" with no prefix.
An additional log level named QUIET
is defined when logging is initialized and can be used to provide a "quiet mode" that hides all informational output sent to a logger.
Logging is configured on the root logger in order to capture and format all logging and warning output regardless of where it originates. Any existing configuration will be replaced by the clickext logging facility. Additional handlers that do not write to stdout/stderr can be attached to the application logger normally, and to the root logger by passing them in the clickext.init_logging
call. The application logger level and propagate
properties are configured automatically when logging is initialized and should not be changed.
Example:
import logging
import click
import clickext
logger = logging.getLogger("__package__")
clickext.init_logging(logger, logging.INFO)
@click.command(cls=clickext.ClickextCommand)
def cmd():
logger.info("some basic info")
logger.error("uh-oh")
logger.debug("secrets live here")
Output:
$ cmd
some basic info
Error: uh-oh
Commands with aliases
Command aliases provide alternate names for a single command. This is helpful for commands with long names or to shorten commands with many options/arguments. Aliased commands must be in a clickext.ClickextGroup
command group.
Example:
import click
import clickext
@click.group(cls=clickext.ClickextGroup)
def cli():
pass
@cli.command(cls=clickext.ClickextCommand, aliases=["c"])
def cmd():
click.echo("ok!")
Output:
$ cli cmd
ok!
$ cli c
ok!
Mutually exclusive options
Mutually exclusive options prevent two or more options being passed together. Shared and command-specific options can be mutually exclusive. Global group options can be mutually exclusive with other group options, but not with shared parameters or subcommand options.
Example:
import click
import clickext
@click.command(cls=clickext.ClickextCommand, mx_opts=[("foo", "bar")])
@click.option("--foo", is_flag=True)
@click.option("--bar", is_flag=True)
def cmd(foo, bar):
pass
Output:
$ cmd --foo --bar
Usage: cmd [OPTIONS]
Try 'cmd --help' for help.
Error: Mutually exclusive options: --foo --bar
Shared Parameters
Shared parameters are parameters required by all subcommands in a group. They are defined at the group level and automatically added to all subcommands, but not the group itself. Subcommand signatures must accept the shared parameters as arguments unless the parameter was defined with expose_value=False
.
Example:
import click
import clickext
@click.group(cls=clickext.ClickextGroup, shared_params=["foo", "bar"])
@click.option("--foo", is_flag=True)
@click.option("--bar", is_flag=True)
def cli():
pass
@cli.command(cls=clickext.ClickextCommand)
def cmd1(foo, bar):
for value in [foo, bar]:
if value:
click.echo("Yes!")
else:
click.echo("No!")
@cli.command(cls=clickext.ClickextCommand)
def cmd2(foo, bar):
for value in [foo, bar]:
if value:
click.echo("Also Yes!")
else:
click.echo("Also No!")
Output:
$ cli cmd1 --foo
Yes!
No!
$ cli cmd2 --foo --bar
Also Yes!
Also Yes!
Global Options
Global options are group-level options that may be passed to any subcommand in the group. The options are extracted from the passed arguments before parsing and processed at the group level regardless of where they originally appeared. Global options cannot have the same name as a subcommand or subcommand option; options that accept values should not accept values with the same name as a subcommand.
Example:
import click
import clickext
@click.group(cls=clickext.ClickextGroup, global_opts=["foo", "bar"])
@click.option("--foo", is_flag=True)
@click.option("--bar", is_flag=True)
def cli(foo, bar):
for value in [foo, bar]:
if value:
click.echo("Yes!")
else:
click.echo("No!")
@cli.command(cls=clickext.ClickextCommand)
@click.option("--baz", is_flag=True)
def cmd(baz):
if baz:
click.echo("Yes baz!")
else:
click.echo("No baz!")
Output:
$ cli --foo
Yes!
No!
$ cli cmd --bar
No!
Yes!
No baz!
$ cli --bar cmd --baz --foo
Yes!
Yes!
Yes baz!
Config Option
The clickext.config_option
provides a mechanism for loading configuration from a JSON, TOML, or YAML file and storing it on click.Context.obj
. An optional processor
can be provided to prepare the parsed data for application use.
Example config.json:
{
"a": "x",
"b": "y",
"c": "z"
}
Example:
import click
import clickext
def exclaim(data):
for k, v in data.items():
data[k] = v + "!"
return data
@click.command(cls=clickext.ClickextCommand)
@clickext.config_option('config.json', processor=exclaim)
@click.pass_obj
def cmd(obj)
for k, v in obj.items():
click.echo(k + ": " + v)
Output:
$ cmd
a: x!
b: y!
c: z!
Verbose and Verbosity Options
The clickext.verbose_option
provides a simple verbosity toggle between logging.DEBUG
and the default log level output (logging.INFO
, by default). The clickext.verbosity_option
provides a configurable verbosity level that can be set to any log level by passing that level name as the argument. Logging configuration adds a QUIET
level that can be used to provide a "quiet mode" with no optional output. When either of these options is used logging will be enabled and configured automatically; it is not necessary to call clickext.init_logging
beforehand.
Example verbose switch:
import logging
import click
import clickext
logger = logging.getLogger(__package__)
@click.command(cls=clickext.ClickextCommand)
@clickext.verbose_option(logger)
def cmd():
logger.debug("a debug message")
logger.info("an info message")
Output:
$ cmd
an info message
$ cmd --verbose
Debug: a debug message
an info message
Example verbosity switch:
import logging
import click
import clickext
logger = logging.getLogger(__package__)
@click.command(cls=clickext.ClickextCommand)
@clickext.verbosity_option(logger)
def cmd():
logger.info("an info message")
logger.warning("a warning message")
Output:
$ cmd
an info message
Warning: a warning message
$ cmd --verbosity WARNING
Warning: a warning message
$ cmd --verbosity QUIET
$
License
clickext is released under the MIT License
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file clickext-1.0.5.tar.gz
.
File metadata
- Download URL: clickext-1.0.5.tar.gz
- Upload date:
- Size: 16.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 8a16feace047947476894d5d8d5060808969ad868e53b7d8ac8b32ec7ba456f9 |
|
MD5 | 0f5039bb1e2ffe5ba1c07ab99e7a084b |
|
BLAKE2b-256 | c657f01cbb721af67a41fd3c6d95246002a4ddd6bb706ee222b5c67e5cbafff9 |
File details
Details for the file clickext-1.0.5-py3-none-any.whl
.
File metadata
- Download URL: clickext-1.0.5-py3-none-any.whl
- Upload date:
- Size: 16.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/5.1.1 CPython/3.12.7
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | ac8e82bf992731dfd8a0197fe89024051f62f1e020e0335942a40933a43c115e |
|
MD5 | 9e5f71a0c80c69ef667d484ddc13f729 |
|
BLAKE2b-256 | 0aa682d1558651654b56046f14f85a8819900af6636bd66f7af40cb89b626636 |