Skip to main content

Thin wrapper around the Python 'click' library to allow building class based CLIs

Project description

ultraclick

A powerful class-based wrapper for building elegant command-line interfaces in Python.

ultraclick is a Python library that extends the popular click framework, enabling you to create structured CLI applications using object-oriented principles. It integrates rich-click for beautiful color formatting and enhanced readability.

Table of Contents

Features

ultraclick offers significant advantages over function-based CLI frameworks:

  • Class-based CLI structure: Define your command-line interface using Python classes
  • Nested command groups: Organize commands in a hierarchical structure
  • Class instance state: Share data between commands naturally via instance attributes
  • Context Proxy: Access the Click context directly with click.ctx without passing it as a parameter
  • Context sharing: Share context data between different command levels via ctx.meta
  • Rich output formatting: Colored output and better help text formatting via rich-click
  • Interactive command execution: Preserves colors, progress bars, and interactive output from subprocesses
  • Cross-platform compatibility: Works on Unix, macOS, and Windows
  • Command aliases: Create alternative names for commands (e.g., info as an alias for status or add as an alias for create)
  • Command abbreviations: Type partial commands like conf s instead of config show when unambiguous
  • Automatic return value handling: Command return values are automatically displayed
  • Clean, maintainable code: Group related commands together with proper encapsulation
  • Full compatibility: Supports all features of Click and RichClick

Installation

From PyPI (recommended)

pip install ultraclick

From Source

# Clone the repository
git clone https://github.com/ronny-rentner/ultraclick.git
cd ultraclick

# Create and activate a virtual environment (recommended)
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install the package in development mode (will install dependencies automatically)
pip install -e .

Demo Application

The repository includes a comprehensive demo that showcases ultraclick's features. After installation and activating your virtual environment, try the following commands:

./demo.py --help
./demo.py --profile production --verbose status
./demo.py config
./demo.py resource
./demo.py resource --resource-type database create mydb --size large --region eu-west
./demo.py config set debug true
./demo.py config update debug false
./demo.py r l
./demo.py --profile staging r --resource-type storage l

Tab Completion

Enable tab completion for the demo application in Bash:

eval "$(_DEMO_PY_COMPLETE=bash_source python ./demo.py)"

Now you can use Tab to complete commands, options, and arguments.

Help Output

Sample help outputs from the demo application:

Main Help

 Usage: demo [OPTIONS] COMMAND [ARGS]...                                        
                                                                                
 Main demo application showcasing ultraclick's features.                        
                                                                                
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --verbose                                    Enable verbose output           │
│ --profile    TEXT                            Configuration profile to use    │
│ --env        [development|staging|productio  Environment to run in           │
│              n]                                                              │
│ --version                                    Show the version and exit.      │
│ --help                                       Show this message and exit.     │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ config    Configuration commands for the application. Demonstrates context   │
│           sharing between subcommands.                                       │
│ info      Show application status.                                           │
│ resource  Resource management commands. Demonstrates parameter handling and  │
│           nested command structure.                                          │
│ status    Show application status.                                           │
╰──────────────────────────────────────────────────────────────────────────────╯

Config Command Help

 Usage: demo config [OPTIONS] COMMAND [ARGS]...                                 
                                                                                
 Configuration commands for the application. Demonstrates context sharing       
 between subcommands.                                                           
 This command group shows help when called directly (default behavior).         
                                                                                
╭─ Options ────────────────────────────────────────────────────────────────────╮
│ --config-dir    PATH  Configuration directory                                │
│ --help                Show this message and exit.                            │
╰──────────────────────────────────────────────────────────────────────────────╯
╭─ Commands ───────────────────────────────────────────────────────────────────╮
│ get       Get a configuration value.                                         │
│ set       Set a configuration value.                                         │
│ show      Display current configuration settings.                            │
╰──────────────────────────────────────────────────────────────────────────────╯

Demo Code

Check out gwctl for a real-world application built with ultraclick.

#!/usr/bin/env python
"""
ultraclick Demo Application

This demo systematically showcases ultraclick's main features:
1. Class-based CLI structure
2. Nested command groups
3. Automatic context sharing
4. Command aliases
5. Command abbreviations
6. Automatic return value handling
"""

import pathlib

import ultraclick as click


class ConfigCommand:
    """
    Configuration commands for the application.
    Demonstrates context sharing between subcommands.

    This command group shows help when called directly (default behavior).
    """
    @click.option("--config-dir", type=pathlib.Path, default="./config", help="Configuration directory")
    def __init__(self, config_dir):
        # Store parameters as instance variables
        self.config_dir = config_dir
        
        # Access shared data from parent command
        self.profile = click.ctx.meta["profile"]
        
        # Share this command's data with child commands
        click.ctx.meta["config_dir"] = config_dir

    @click.command()
    def show(self):
        """Display current configuration settings."""
        path_prefix = './' if not self.config_dir.is_absolute() else ''
        return (
            f"Active Profile: {self.profile}\n"
            f"Config Directory: {path_prefix}{self.config_dir}"
        )

    @click.command()
    @click.argument("name")
    @click.argument("value")
    def set(self, name, value):
        """Set a configuration value."""
        return f"Setting {name}={value} in profile '{self.profile}'"

    # Command alias demonstration - using decorator approach
    update = click.alias(set)

    @click.command()
    @click.argument("name")
    def get(self, name):
        """Get a configuration value."""
        return f"Getting '{name}' from profile '{self.profile}'"

    # Another command alias - using decorator approach
    fetch = click.alias(get)


class ResourceCommand:
    """
    Resource management commands.
    Demonstrates parameter handling and nested command structure.

    This command group performs an action when called directly (no help shown).
    """
    @click.option("--resource-type", type=click.Choice(['server', 'database', 'storage']),
                  default="server", help="Type of resource to manage")
    def __init__(self, resource_type):
        self.resource_type = resource_type
        
        # Access shared data from parent command
        self.profile = click.ctx.meta["profile"]

        # Custom behavior when no subcommand is provided
        if click.ctx.invoked_subcommand is None:
            # Prevent automatic help display
            click.ctx.meta['show_help_on_no_command'] = False
            
            # Show custom summary instead
            click.echo(
                f"Resource Management Summary:\n"
                f"• Current Resource Type: {self.resource_type}\n"
                f"• Available Types: server, database, storage\n"
                f"• Active Profile: {self.profile}"
            )

    @click.command()
    @click.argument("name")
    @click.option("--size", default="medium", help="Resource size (small, medium, large)")
    @click.option("--region", default="us-east", help="Deployment region")
    def create(self, name, size, region):
        """Create a new resource."""
        return (
            f"Creating {self.resource_type} '{name}'\n"
            f"Size: {size}\n"
            f"Region: {region}\n"
            f"Using profile: {self.profile}"
        )

    @click.command()
    @click.argument("name")
    def delete(self, name):
        """Delete a resource."""
        return f"Deleting {self.resource_type} '{name}'"

    @click.command()
    @click.argument("names", nargs=-1)
    def list(self, names):
        """List resources, optionally filtered by name."""
        if not names:
            return f"Listing all {self.resource_type}s (Profile: {self.profile})"
        else:
            return f"Filtered {self.resource_type} list: {', '.join(names)} (Profile: {self.profile})"


class MainApp:
    """
    Main demo application showcasing ultraclick's features.
    """
    # Define nested command groups
    config = ConfigCommand
    resource = ResourceCommand

    @click.option("--verbose", is_flag=True, help="Enable verbose output")
    @click.option("--profile", default="default", help="Configuration profile to use")
    @click.option("--env", default="development",
                 type=click.Choice(['development', 'staging', 'production']),
                 help="Environment to run in")
    @click.version_option(version="1.0")
    def __init__(self, verbose, profile, env):
        # Store options as instance variables
        self.verbose = verbose
        self.profile = profile
        self.env = env

        # Share data with child commands
        click.ctx.meta["verbose"] = verbose
        click.ctx.meta["profile"] = profile
        click.ctx.meta["env"] = env

        if verbose:
            click.output.success(f"Verbose mode enabled in {env} environment")

    @click.command()
    def status(self):
        """Show application status."""
        return (
            f"Status: Running\n"
            f"Environment: {self.env}\n"
            f"Verbose: {self.verbose}\n"
            f"Profile: {self.profile}"
        )
    
    # Command alias using the decorator approach
    info=click.alias(status)

if __name__ == "__main__":
    click.group_from_class(MainApp, name="demo")()

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

ultraclick-0.1.1.tar.gz (32.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ultraclick-0.1.1-py3-none-any.whl (22.5 kB view details)

Uploaded Python 3

File details

Details for the file ultraclick-0.1.1.tar.gz.

File metadata

  • Download URL: ultraclick-0.1.1.tar.gz
  • Upload date:
  • Size: 32.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for ultraclick-0.1.1.tar.gz
Algorithm Hash digest
SHA256 260a1cf7ec40628d07f88f46b9c35c5a1ee43efe185fd17ddecd635018533cb7
MD5 8c0819dac5e3871d393038d1105995cd
BLAKE2b-256 28145d07521093a2b4909df1d229eb9120ccedf1e979ffd49064b892792d6e76

See more details on using hashes here.

Provenance

The following attestation bundles were made for ultraclick-0.1.1.tar.gz:

Publisher: release.yml on ronny-rentner/ultraclick

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file ultraclick-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: ultraclick-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 22.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for ultraclick-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0d4c14087d74d9f82924212cc2d9974425a6f37876cbedfa817cea1ec0b57f05
MD5 f7e438699a1907adc7c2c88acd674b82
BLAKE2b-256 31c523263e08131b07dc8788149924622cb7af56c1144610b3198a2f9d4fdefe

See more details on using hashes here.

Provenance

The following attestation bundles were made for ultraclick-0.1.1-py3-none-any.whl:

Publisher: release.yml on ronny-rentner/ultraclick

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page