Source code for cmdkit.cli
# SPDX-FileCopyrightText: 2022 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0
"""
Implements the `Interface` class.
This module provides a modification to the standard `argparse.ArgumentParser`.
Instead of allowing it to construct usage and help statements, the `Interface`
class takes a pre-constructed usage and help string and uses those instead.
Further, it suppresses the exit behavior and always raises an `ArgumentError`
instead of trying to exit the program immediately.
"""
# type annotations
from __future__ import annotations
from typing import Callable
# standard libs
import argparse as _argparse
# internal libs
from cmdkit.ansi import colorize_usage
# public interface
__all__ = ['Interface', 'ArgumentError', 'HelpOption', 'VersionOption']
# elevate to this module
Namespace = _argparse.Namespace
[docs]
class HelpOption(Exception):
"""Raised by :class:`~Interface` when the help option is passed."""
[docs]
class VersionOption(Exception):
"""Raised by :class:`~Interface` whenever ``action='version'``."""
[docs]
class ArgumentError(Exception):
"""Raised by :class:`~Interface` on bad arguments."""
# override version action to raise instead
def _version_action(self, parser, namespace, values, option_string=None) -> None: # noqa: unused args
raise VersionOption(self.version if self.version is not None else parser.version)
_argparse._VersionAction.__call__ = _version_action # noqa: (protected)
[docs]
class Interface(_argparse.ArgumentParser):
"""
Variant of :class:`argparse.ArgumentParser` that raises an :class:`ArgumentError`
instead of calling :meth:`sys.exit`. See the standard library documentation for
details on :meth:`~Interface.add_argument` and other common methods.
The `usage_text` and `help_text` are taken verbatim; however, these text values
can be colorized automatically using a generalized syntax highlighter
(:meth:`cmdkit.ansi.colorize_usage` by default).
To disable this behavior, use the `disable_colors` parameter.
"""
def __init__(self,
program: str,
usage_text: str,
help_text: str,
disable_colors: bool = False,
formatter: Callable[[str], str] = colorize_usage,
**kwargs) -> None:
"""Initialize with text and formatting arguments."""
self.program = program
if disable_colors:
self.usage_text = usage_text
self.help_text = help_text
else:
self.usage_text = formatter(usage_text)
self.help_text = formatter(help_text)
super().__init__(prog=program, usage=usage_text, **kwargs)
# prevents base class from trying to build up usage text
def format_help(self) -> str:
return self.help_text
# prevents base class from trying to build up help text
def format_usage(self) -> str:
return self.usage_text
# messages will be printed manually
def print_usage(self, *args, **kwargs) -> None:
return # don't allow parser to print usage
def print_help(self, *args, **kwargs) -> None:
raise HelpOption(self.help_text)
# don't allow base class attempt to exit
def exit(self, status: int = 0, message: str = None) -> None:
raise ArgumentError(message)
# simple raise, no printing
def error(self, message: str) -> None:
raise ArgumentError(message)