Cleo
Cleo is a Python library designed to help developers create beautiful and testable command-line interfaces. It draws significant inspiration from the Symfony Console Component, providing a robust and familiar structure for building CLI applications. The library is actively maintained, with a release cadence that includes support for new Python versions and essential bug fixes, as demonstrated by the recent 2.1.0 update.
Warnings
- breaking Cleo versions 1.0.0 and 2.0.0 removed the `clikit` dependency, signifying a major internal refactoring. Code relying on `clikit` directly or specific `clikit`-based behaviors within Cleo will break.
- breaking The `Terminal` class was removed and replaced with `shutil.get_terminal_size()` from Python's standard library. Direct calls to `cleo.terminal.Terminal` will fail.
- breaking The exception hierarchy changed in versions 1.0.0 / 2.0.0. Specifically, `CleoException` was renamed or replaced by `CleoError`.
- breaking Doc comment-based command configuration (where arguments and options were defined in the command's docstring) was removed in versions 1.0.0 / 2.0.0.
- gotcha Cleo version 1.0.0 was yanked shortly after its release due to compatibility issues with other projects (e.g., Poetry) that depended on its pre-release versions. Version 2.0.0 was released immediately after with no source code changes to effectively replace 1.0.0.
Install
-
pip install cleo
Imports
- Application
from cleo.application import Application
- Command
from cleo.commands.command import Command
- argument
from cleo.helpers import argument
- option
from cleo.helpers import option
- CleoError
from cleo.exceptions import CleoError
Quickstart
import os
from cleo.application import Application
from cleo.commands.command import Command
from cleo.helpers import argument, option
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)
application = Application("My CLI App", "1.0.0")
application.add(GreetCommand())
if __name__ == "__main__":
# Example of how to run, in a real app this would be called via command line
# e.g., `python your_script.py greet John --yell`
# For quickstart, we'll simulate it for programmatic execution and testing
try:
# Simulate a command-line call for demonstration
# In a real scenario, this would be invoked via sys.argv
from cleo.io.buffered_io import BufferedIO
from cleo.io.inputs.string_input import StringInput
from cleo.io.outputs.buffered_output import BufferedOutput
# Example: running 'greet John --yell'
input_stream = StringInput('greet John --yell')
output_stream = BufferedOutput()
error_stream = BufferedOutput()
io = BufferedIO(input_stream, output_stream, error_stream)
application.run(io)
print("\n--- Output ---")
print(output_stream.fetch())
print("--- Error ---")
print(error_stream.fetch())
print("--------------")
# Example: running 'greet'
input_stream_no_args = StringInput('greet')
output_stream_no_args = BufferedOutput()
error_stream_no_args = BufferedOutput()
io_no_args = BufferedIO(input_stream_no_args, output_stream_no_args, error_stream_no_args)
application.run(io_no_args)
print("\n--- Output (No Args) ---")
print(output_stream_no_args.fetch())
print("--- Error (No Args) ---")
print(error_stream_no_args.fetch())
print("------------------------")
except Exception as e:
print(f"An error occurred: {e}")