Cleo allows you to create beautiful and testable command-line interfaces.
npx @tessl/cli install tessl/pypi-cleo@2.2.0Cleo is a comprehensive Python library for creating beautiful and testable command-line interfaces. It provides a high-level API for building CLI applications with features including command definition with arguments and options, automatic help generation, colorized output with custom styling, multiple verbosity levels, command testing utilities, and autocompletion support for bash, zsh, and fish shells.
pip install cleofrom cleo.application import Application
from cleo.commands.command import Command
from cleo.helpers import argument, optionfrom cleo.commands.command import Command
from cleo.helpers import argument, option
from cleo.application import Application
class GreetCommand(Command):
name = "greet"
description = "Greets someone"
arguments = [
argument(
"name",
description="Who do you want to greet?",
optional=True
)
]
options = [
option(
"yell",
"y",
description="If set, the task will yell in uppercase letters",
flag=True
)
]
def handle(self):
name = self.argument("name")
if name:
text = f"Hello {name}"
else:
text = "Hello"
if self.option("yell"):
text = text.upper()
self.line(text)
# Create application and add command
application = Application()
application.add(GreetCommand())
if __name__ == "__main__":
application.run()Cleo follows a hierarchical architecture built around these core components:
This design enables building sophisticated CLI applications with extensive customization capabilities while maintaining clean separation of concerns.
The main Application class that serves as the container for CLI commands. Handles command registration, routing, argument parsing, and execution coordination.
class Application:
def __init__(self, name: str = "console", version: str = "") -> None: ...
def add(self, command: Command) -> Command | None: ...
def get(self, name: str) -> Command: ...
def has(self, name: str) -> bool: ...
def run(self, input: Input | None = None, output: Output | None = None, error_output: Output | None = None) -> int: ...
def find(self, name: str) -> Command: ...
def all(self, namespace: str | None = None) -> dict[str, Command]: ...Command creation and configuration with arguments, options, and command execution logic. This forms the foundation for building individual CLI commands.
class Command(BaseCommand):
name: str | None = None
description: str = ""
arguments: ClassVar[list[Argument]] = []
options: ClassVar[list[Option]] = []
def handle(self) -> int: ... # Abstract method to implement
def argument(self, name: str) -> Any: ...
def option(self, name: str) -> Any: ...
def line(self, text: str, style: str | None = None, verbosity: Verbosity = Verbosity.NORMAL) -> None: ...
def argument(name: str, description: str | None = None, optional: bool = False,
multiple: bool = False, default: Any | None = None) -> Argument: ...
def option(long_name: str, short_name: str | None = None, description: str | None = None,
flag: bool = True, value_required: bool = True, multiple: bool = False,
default: Any | None = None) -> Option: ...Comprehensive I/O management including input handling, output formatting, and error reporting. Supports different input sources and output destinations with verbosity control.
class IO:
def __init__(self, input: Input, output: Output, error_output: Output) -> None: ...
def read(self, length: int, default: str = "") -> str: ...
def read_line(self, length: int = -1, default: str = "") -> str: ...
def write(self, messages: str | Iterable[str], new_line: bool = False, verbosity: Verbosity = Verbosity.NORMAL, type: OutputType = OutputType.NORMAL) -> None: ...
def write_line(self, messages: str | Iterable[str], verbosity: Verbosity = Verbosity.NORMAL, type: OutputType = OutputType.NORMAL) -> None: ...
def write_error(self, messages: str | Iterable[str], new_line: bool = False, verbosity: Verbosity = Verbosity.NORMAL, type: OutputType = OutputType.NORMAL) -> None: ...
def write_error_line(self, messages: str | Iterable[str], verbosity: Verbosity = Verbosity.NORMAL, type: OutputType = OutputType.NORMAL) -> None: ...
def overwrite(self, messages: str | Iterable[str]) -> None: ...
def overwrite_error(self, messages: str | Iterable[str]) -> None: ...
def flush(self) -> None: ...
class Verbosity(Enum):
QUIET = 16
NORMAL = 32
VERBOSE = 64
VERY_VERBOSE = 128
DEBUG = 256
class OutputType(Enum):
NORMAL = 1
RAW = 2
PLAIN = 4Text styling and formatting capabilities including colors, formatting options, and custom styles for rich console output.
class Formatter:
def __init__(self, decorated: bool = False, styles: dict[str, Style] | None = None): ...
def format(self, message: str) -> str: ...
def set_style(self, name: str, style: Style) -> None: ...
class Style:
def __init__(self, foreground: str | None = None, background: str | None = None, options: list[str] | None = None): ...
def foreground(self, foreground: str) -> Style: ...
def background(self, background: str) -> Style: ...
def bold(self, bold: bool = True) -> Style: ...
def apply(self, text: str) -> str: ...Rich interactive UI components including tables, progress indicators, and question prompts for building sophisticated CLI interactions.
class Table:
def __init__(self, io: IO | Output, style: str | None = None): ...
def set_headers(self, headers: list[str]) -> Table: ...
def set_rows(self, rows: Rows) -> Table: ...
def render(self) -> None: ...
class ProgressBar:
def __init__(self, io: IO | Output, max: int = 0): ...
def start(self, max: int | None = None) -> None: ...
def advance(self, step: int = 1) -> None: ...
def finish(self) -> None: ...
class Question:
def __init__(self, question: str, default: Any = None): ...
def ask(self, io: IO) -> Any: ...
def hide(self, hidden: bool = True) -> None: ...Testing utilities for command and application testing with simulated input/output for comprehensive CLI testing.
class CommandTester:
def __init__(self, command: Command): ...
def execute(self, args: str = "", inputs: str | None = None) -> int: ...
class ApplicationTester:
def __init__(self, application: Application): ...
def execute(self, args: str = "", inputs: str | None = None) -> int: ...Complete exception hierarchy for error handling in CLI applications with specific exception types for different error conditions.
class CleoError(Exception):
exit_code: int | None = None
class CleoLogicError(CleoError): ... # Configuration errors
class CleoRuntimeError(CleoError): ... # Runtime errors
class CleoValueError(CleoError): ... # Value errors
class CleoNoSuchOptionError(CleoError): ... # Option not found errors
class CleoUserError(CleoError): ... # User input errors
class CleoMissingArgumentsError(CleoUserError): ... # Missing required arguments
class CleoCommandNotFoundError(CleoUserError): # Command not found
def __init__(self, name: str, commands: list[str] | None = None) -> None: ...
class CleoNamespaceNotFoundError(CleoUserError): # Namespace not found
def __init__(self, name: str, namespaces: list[str] | None = None) -> None: ...