CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-types-click

Typing stubs for click - a command line interface creation kit for Python

Overview
Eval results
Files

exception-handling.mddocs/

Exception Handling

Comprehensive exception hierarchy for handling CLI errors with proper error messages, exit codes, and user feedback. Includes parameter validation errors and usage errors.

Capabilities

Base Exception Classes

Foundation exception classes that provide common error handling functionality.

class ClickException(Exception):
    exit_code: int
    message: str

    def __init__(self, message: str) -> None:
        """
        Base exception for all click-related errors.

        Parameters:
        - message: Error message

        Attributes:
        - exit_code: Exit code for the application (default: 1)
        - message: Error message text

        Usage:
        raise click.ClickException('Something went wrong')
        """

    def format_message(self) -> str:
        """
        Format the exception message.

        Returns:
        Formatted error message
        """

    def show(self, file: Any | None = None) -> None:
        """
        Show the exception message to the user.

        Parameters:
        - file: File to write to (defaults to stderr)
        """

Usage Error Exceptions

Exceptions for command usage and parameter errors.

class UsageError(ClickException):
    ctx: Context | None
    cmd: Command | None

    def __init__(self, message: str, ctx: Context | None = None) -> None:
        """
        Exception for usage errors (wrong parameters, invalid commands, etc.).

        Parameters:
        - message: Error message
        - ctx: Context where error occurred

        Usage:
        if len(args) == 0:
            raise click.UsageError('At least one argument is required')
        """

    def show(self, file: IO[Any] | None = None) -> None:
        """Show usage error with command usage information."""

Parameter Exception Classes

Specific exceptions for parameter validation and processing errors.

class BadParameter(UsageError):
    param: Parameter | None
    param_hint: str | None

    def __init__(
        self,
        message: str,
        ctx: Context | None = None,
        param: Parameter | None = None,
        param_hint: str | None = None,
    ) -> None:
        """
        Exception for invalid parameter values.

        Parameters:
        - message: Error message
        - ctx: Context where error occurred
        - param: Parameter that caused the error
        - param_hint: Hint about which parameter failed

        Usage:
        # Usually raised by parameter types
        if not os.path.exists(path):
            raise click.BadParameter(f'Path {path} does not exist')
        """

class MissingParameter(BadParameter):
    param_type: str

    def __init__(
        self,
        message: str | None = None,
        ctx: Context | None = None,
        param: Parameter | None = None,
        param_hint: str | None = None,
        param_type: str | None = None,
    ) -> None:
        """
        Exception for missing required parameters.

        Parameters:
        - message: Error message
        - ctx: Context where error occurred
        - param: Missing parameter
        - param_hint: Hint about which parameter is missing
        - param_type: Type of parameter ('parameter', 'option', 'argument')

        Usage:
        # Usually raised automatically by click
        if required_param is None:
            raise click.MissingParameter('Required parameter missing')
        """

Option and Argument Exceptions

Specific exceptions for option and argument processing errors.

class NoSuchOption(UsageError):
    option_name: str
    possibilities: list[str] | None

    def __init__(
        self,
        option_name: str,
        message: str | None = None,
        possibilities: list[str] | None = None,
        ctx: Context | None = None,
    ) -> None:
        """
        Exception for unknown options.

        Parameters:
        - option_name: Name of unknown option
        - message: Error message
        - possibilities: List of similar option names
        - ctx: Context where error occurred

        Usage:
        # Usually raised automatically by click
        if option not in valid_options:
            raise click.NoSuchOption(option, possibilities=['--help', '--version'])
        """

class BadOptionUsage(UsageError):
    option_name: str

    def __init__(self, option_name: str, message: str, ctx: Context | None = None) -> None:
        """
        Exception for incorrect option usage.

        Parameters:
        - option_name: Name of the option
        - message: Error message
        - ctx: Context where error occurred

        Usage:
        # When option is used incorrectly
        raise click.BadOptionUsage('--count', 'Option requires a value')
        """

class BadArgumentUsage(UsageError):
    def __init__(self, message: str, ctx: Context | None = None) -> None:
        """
        Exception for incorrect argument usage.

        Parameters:
        - message: Error message
        - ctx: Context where error occurred

        Usage:
        # When arguments are used incorrectly
        raise click.BadArgumentUsage('Too many arguments provided')
        """

File Operation Exceptions

Exceptions for file-related operations.

class FileError(ClickException):
    ui_filename: str
    filename: str

    def __init__(self, filename: str, hint: str | None = None) -> None:
        """
        Exception for file operation errors.

        Parameters:
        - filename: Name of the file that caused the error
        - hint: Additional hint about the error

        Usage:
        try:
            with open(filename, 'r') as f:
                content = f.read()
        except IOError:
            raise click.FileError(filename, 'Could not read file')
        """

Control Flow Exceptions

Exceptions used for controlling command execution flow.

class Abort(RuntimeError):
    """
    Exception for aborting command execution.

    Raised by Context.abort() and confirmation dialogs when user
    chooses to abort.

    Usage:
    if not click.confirm('Continue with dangerous operation?'):
        raise click.Abort()
    
    # Or use context method
    ctx.abort()
    """

class Exit(RuntimeError):
    exit_code: int

    def __init__(self, code: int = 0) -> None:
        """
        Exception for exiting with specific code.

        Parameters:
        - code: Exit code

        Usage:
        if success:
            raise click.Exit(0)
        else:
            raise click.Exit(1)
        
        # Or use context method
        ctx.exit(code)
        """

Exception Handling Patterns

Custom Validation with Exceptions:

@click.command()
@click.option('--port', type=int)
def start_server(port):
    if port and (port < 1 or port > 65535):
        raise click.BadParameter('Port must be between 1 and 65535', 
                               param_hint='--port')
    
    if port and port < 1024:
        if not click.confirm(f'Port {port} requires root privileges. Continue?'):
            raise click.Abort()

Custom Parameter Type with Exceptions:

class PortType(click.ParamType):
    name = 'port'
    
    def convert(self, value, param, ctx):
        if value is None:
            return None
            
        try:
            port = int(value)
        except ValueError:
            self.fail(f'{value} is not a valid port number', param, ctx)
        
        if not (1 <= port <= 65535):
            self.fail(f'Port {port} is not in valid range 1-65535', param, ctx)
            
        return port

@click.option('--port', type=PortType())
def connect(port):
    click.echo(f'Connecting to port {port}')

Error Handling with Context:

@click.command()
@click.argument('filename')
@click.pass_context
def process_file(ctx, filename):
    try:
        if not os.path.exists(filename):
            ctx.fail(f'File {filename} does not exist')
        
        with open(filename, 'r') as f:
            data = f.read()
            
        # Process data
        result = process_data(data)
        
    except PermissionError:
        ctx.fail(f'Permission denied accessing {filename}')
    except json.JSONDecodeError as e:
        ctx.fail(f'Invalid JSON in {filename}: {e}')
    except Exception as e:
        if ctx.obj and ctx.obj.get('debug'):
            raise  # Re-raise in debug mode
        else:
            ctx.fail(f'Error processing {filename}: {e}')

Graceful Error Messages:

@click.command()
@click.option('--config', type=click.Path(exists=True), required=True)
def deploy(config):
    try:
        with open(config, 'r') as f:
            config_data = json.load(f)
    except json.JSONDecodeError as e:
        # Convert generic exception to click exception
        raise click.BadParameter(
            f'Configuration file contains invalid JSON: {e}',
            param_hint='--config'
        )
    
    required_keys = ['host', 'port', 'database']
    missing_keys = [key for key in required_keys if key not in config_data]
    
    if missing_keys:
        raise click.BadParameter(
            f'Configuration missing required keys: {", ".join(missing_keys)}',
            param_hint='--config'
        )

Custom Exception Classes:

class DeploymentError(click.ClickException):
    def __init__(self, message, deployment_id=None):
        super().__init__(message)
        self.deployment_id = deployment_id
        self.exit_code = 2  # Custom exit code
    
    def format_message(self):
        msg = super().format_message()
        if self.deployment_id:
            msg += f' (Deployment ID: {self.deployment_id})'
        return msg

@click.command()
def deploy():
    try:
        deployment_id = start_deployment()
        monitor_deployment(deployment_id)
    except DeploymentFailure as e:
        raise DeploymentError(str(e), deployment_id) from e

Install with Tessl CLI

npx tessl i tessl/pypi-types-click

docs

commands-groups.md

context-management.md

exception-handling.md

formatting.md

index.md

parameter-types.md

parameters.md

terminal-ui.md

testing-support.md

tile.json