click-compose¶
Composable Click callback utilities for building flexible CLI applications.
Installation¶
click-compose supports Python 3.11+.
$ pip install click-compose
Or with uv:
$ uv add click-compose
Usage¶
click-compose provides utilities for composing Click callbacks.
multi_callback¶
multi_callback applies callbacks in order.
Pass a tuple of up to ten callbacks for statically checked type-changing stages.
Each callback must accept the preceding callback’s result.
For same-type callbacks, a typed list of any length is supported.
An empty list returns the input unchanged.
"""Example of using multi_callback."""
import click
from click_compose import multi_callback
def double(
_ctx: click.Context | None, _param: click.Parameter | None, value: int
) -> int:
"""Double the value."""
return value * 2
def add_ten(
_ctx: click.Context | None, _param: click.Parameter | None, value: int
) -> int:
"""Add ten to the value."""
return value + 10
def to_string(
_ctx: click.Context | None, _param: click.Parameter | None, value: int
) -> str:
"""Convert the value to a string."""
return str(object=value)
@click.command()
@click.option(
"--value",
type=int,
callback=multi_callback(callbacks=(double, add_ten, to_string)),
)
def cmd(value: str) -> None:
"""Print the transformed value."""
click.echo(message=value)
sequence_validator¶
sequence_validator wraps a single-value validator to apply it to a sequence of values.
This is particularly useful with Click’s multiple=True option parameter.
"""Example of using sequence_validator."""
import click
from click_compose import sequence_validator
def validate_single_value(
_ctx: click.Context | None, _param: click.Parameter | None, value: int
) -> int:
"""Validate a single value."""
return value
@click.command()
@click.option(
"--values",
multiple=True,
type=int,
callback=sequence_validator(validator=validate_single_value),
)
def cmd(values: tuple[int, ...]) -> None:
"""Example command using sequence_validator."""
click.echo(message=values)
Each element in the sequence is validated individually, and validation errors are raised for the specific element that fails.
deduplicate¶
deduplicate is a Click callback that removes duplicate values from a sequence while preserving the original order.
This is particularly useful with Click’s multiple=True option parameter when you want to ensure unique values.
"""Example of using ``deduplicate``."""
import click
from click_compose import deduplicate
@click.command()
@click.option(
"--tags",
multiple=True,
type=str,
callback=deduplicate,
)
def cmd(tags: tuple[str, ...]) -> None:
"""Example command using ``deduplicate``."""
click.echo(message=f"Unique tags: {', '.join(tags)}")
if __name__ == "__main__":
cmd([])
The callback preserves the first occurrence of each value and removes subsequent duplicates.
For example, if a user provides --tags foo --tags bar --tags foo, the result will be ('foo', 'bar').
API Reference¶
Composable Click callback utilities for building flexible CLI applications.
- click_compose.sequence_validator(*, validator: Callable[[Context | None, Parameter | None, T], U]) Callable[[Context | None, Parameter | None, Sequence[T]], Sequence[U]]¶
Wrap a single-value validator to apply it to a sequence of values.
This function takes a Click callback that validates a single value and returns a new callback that applies the same validation to each element in a sequence. The validator can transform the type of each element.
- Parameters:
validator – A Click callback that validates a single value.
- Returns:
A Click callback that validates a sequence of values.
- click_compose.deduplicate(ctx: Context | None, param: Parameter | None, sequence: Sequence[T]) Sequence[T]¶
Return the sequence with duplicates removed while preserving order.
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1]]) Callable[[Context | None, Parameter | None, _T0], _T1]¶
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2]]) Callable[[Context | None, Parameter | None, _T0], _T2]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3]]) Callable[[Context | None, Parameter | None, _T0], _T3]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4]]) Callable[[Context | None, Parameter | None, _T0], _T4]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4], Callable[[Context | None, Parameter | None, _T4], _T5]]) Callable[[Context | None, Parameter | None, _T0], _T5]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4], Callable[[Context | None, Parameter | None, _T4], _T5], Callable[[Context | None, Parameter | None, _T5], _T6]]) Callable[[Context | None, Parameter | None, _T0], _T6]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4], Callable[[Context | None, Parameter | None, _T4], _T5], Callable[[Context | None, Parameter | None, _T5], _T6], Callable[[Context | None, Parameter | None, _T6], _T7]]) Callable[[Context | None, Parameter | None, _T0], _T7]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4], Callable[[Context | None, Parameter | None, _T4], _T5], Callable[[Context | None, Parameter | None, _T5], _T6], Callable[[Context | None, Parameter | None, _T6], _T7], Callable[[Context | None, Parameter | None, _T7], _T8]]) Callable[[Context | None, Parameter | None, _T0], _T8]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4], Callable[[Context | None, Parameter | None, _T4], _T5], Callable[[Context | None, Parameter | None, _T5], _T6], Callable[[Context | None, Parameter | None, _T6], _T7], Callable[[Context | None, Parameter | None, _T7], _T8], Callable[[Context | None, Parameter | None, _T8], _T9]]) Callable[[Context | None, Parameter | None, _T0], _T9]
- click_compose.multi_callback(*, callbacks: tuple[Callable[[Context | None, Parameter | None, _T0], _T1], Callable[[Context | None, Parameter | None, _T1], _T2], Callable[[Context | None, Parameter | None, _T2], _T3], Callable[[Context | None, Parameter | None, _T3], _T4], Callable[[Context | None, Parameter | None, _T4], _T5], Callable[[Context | None, Parameter | None, _T5], _T6], Callable[[Context | None, Parameter | None, _T6], _T7], Callable[[Context | None, Parameter | None, _T7], _T8], Callable[[Context | None, Parameter | None, _T8], _T9], Callable[[Context | None, Parameter | None, _T9], _T10]]) Callable[[Context | None, Parameter | None, _T0], _T10]
- click_compose.multi_callback(*, callbacks: list[Callable[[Context | None, Parameter | None, T], T]]) Callable[[Context | None, Parameter | None, T], T]
Apply Click callbacks in order.
Tuple literals of up to ten callbacks preserve intermediate types under static type checking. A typed list of callbacks with a shared input and output type may have any length. An empty list produces an identity callback.
- Parameters:
callbacks – The callbacks to apply, in order.
- Returns:
A Click callback that applies every callback in sequence.