{"id":3926,"library":"cliff","title":"cliff Command Line Interface Formulation Framework","description":"cliff (Command Line Interface Formulation Framework) is a Python library for building structured command-line applications, commonly used for OpenStack clients and other complex CLIs. It provides base classes for application structure, command registration, argument parsing, and consistent output formatting. The current version is 4.13.3, and it maintains a regular release cadence with active development.","status":"active","version":"4.13.3","language":"en","source_language":"en","source_url":"https://github.com/openstack/cliff","tags":["CLI","framework","command-line","application development","OpenStack"],"install":[{"cmd":"pip install cliff","lang":"bash","label":"Install cliff"}],"dependencies":[],"imports":[{"note":"Base class for the CLI application itself.","symbol":"App","correct":"from cliff.app import App"},{"note":"Base class for individual CLI commands. Often confused with the top-level 'cliff' module.","wrong":"from cliff import Command","symbol":"Command","correct":"from cliff.command import Command"},{"note":"A Command subclass for commands that list items, expecting (column_names, data) as return.","symbol":"Lister","correct":"from cliff.lister import Lister"},{"note":"A Command subclass for commands that show details of a single item, expecting (column_names, data) as return.","symbol":"ShowOne","correct":"from cliff.showone import ShowOne"}],"quickstart":{"code":"import sys\nfrom cliff.app import App\nfrom cliff.command import Command\nfrom cliff.commandmanager import CommandManager\n\nclass MyCommand(Command):\n    \"\"\"A simple example command.\"\"\"\n\n    def get_parser(self, prog_name):\n        parser = super().get_parser(prog_name)\n        parser.add_argument(\n            '--name',\n            dest='name',\n            default='World',\n            help='Name to greet'\n        )\n        return parser\n\n    def take_action(self, parsed_args):\n        print(f\"Hello, {parsed_args.name}!\")\n\nclass MyCLIApp(App):\n\n    def __init__(self):\n        super().__init__(\n            description='My simple cliff-based CLI',\n            version='1.0',\n            command_manager=CommandManager('mycli_entrypoints'),\n            deferred_help=True,\n        )\n\n    def initialize_app(self, argv):\n        self.LOG.debug('initialize_app')\n\n    def prepare_to_run(self, argv):\n        self.LOG.debug('prepare_to_run')\n\n    def clean_up(self, cmd, result, err):\n        self.LOG.debug('clean_up')\n        if err:\n            self.LOG.debug(f'An error occurred: {err}')\n\n\ndef main(argv=sys.argv[1:]):\n    # For a real app, commands are typically registered via setup.cfg or pyproject.toml entry points.\n    # Example: In pyproject.toml, under [project.entry-points.\"mycli_entrypoints\"]\n    #          'mycommand = my_module:MyCommand'\n    #          And under [project.scripts]\n    #          'mycli = my_module:main'\n    # For this quickstart, we manually register the command:\n    app = MyCLIApp()\n    app.command_manager.add_command('mycommand', MyCommand)\n\n    return app.run(argv)\n\nif __name__ == '__main__':\n    # Simulate running 'mycli mycommand --name Registry' from the command line\n    sys.exit(main(['mycommand', '--name', 'Registry']))\n","lang":"python","description":"This quickstart demonstrates a minimal `cliff` application with one command. To make this a discoverable CLI tool, you would typically define entry points in your `pyproject.toml` (or `setup.cfg`). For example, under `[project.entry-points.\"mycli_entrypoints\"]`, you would add `mycommand = my_module:MyCommand` for command discovery, and under `[project.scripts]`, you would add `mycli = my_module:main` to create the executable. The example manually registers the command for simplicity, allowing it to be run directly."},"warnings":[{"fix":"Ensure your project runs on Python 3.10 or newer. Update your `pyproject.toml` or `setup.cfg` to use `setuptools-scm` or `setuptools` for package metadata and entry points, removing any 'pbr' specific configurations.","message":"Python 3.10+ is now required. Additionally, build system dependencies shifted from 'pbr' to 'setuptools-scm' or direct 'setuptools' for project setup.","severity":"breaking","affected_versions":"4.0.0 and later"},{"fix":"Configure logging using Python's standard `logging` module before `App.run()` is called. `cliff` provides `App.configure_logging()` for basic setup or you can implement a custom configuration.","message":"The `log_file` option for `App.run()` and related logging configuration methods have been removed.","severity":"breaking","affected_versions":"4.0.0 and later"},{"fix":"Verify your `pyproject.toml` (or `setup.cfg`) correctly defines entry points under the `[project.entry-points.\"<your_entry_point_group>\"]` section, mapping command names to their respective `Command` class paths.","message":"Commands are discovered via Setuptools entry points (e.g., `[cliff.commands]` or custom groups like `[mycli_entrypoints]` in `setup.cfg` or `pyproject.toml`). Misconfiguring or omitting these entry points will prevent your commands from being found by the CLI application.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Ensure `take_action` methods for `Lister` and `ShowOne` commands return a tuple `(column_names, data)` conforming to these types. Incorrect structures will lead to output errors or unexpected behavior.","message":"`Lister` and `ShowOne` command types expect specific return value structures. `Lister` expects `(column_names, data_rows)` and `ShowOne` expects `(column_names, data_item)` where `data_rows` is a list of tuples/lists and `data_item` is a single tuple/list.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}