Skip to main content

Reusable CLI utilities for consistent command-line interfaces

Project description

cli-standard-kit

Reusable CLI utilities for consistent command-line interfaces in Python.

This package provides common building blocks for standardized, professional Python CLI tools:

  • Standardized logging (file + console) with verbose/quiet modes
  • ANSI color utilities and message formatting templates
  • Conventional directory layout helpers
  • File operations for batch processing with progress tracking
  • Argument parser with a consistent set of flags
  • Pure Python (stdlib only)

Installation

From PyPI

pip install cli-standard-kit

Development (editable)

git clone https://github.com/c3nk/cli-standard-kit.git
cd cli-standard-kit
pip install -e .

Quick Start

Below is a minimal CLI using cli-standard-kit components.

import sys
from pathlib import Path
from cli_commons.parser import create_standard_parser, validate_arguments
from cli_commons.logger import setup_logging
from cli_commons.directories import setup_directories
from cli_commons.colors import MessageFormatter
from cli_commons.file_ops import get_files_recursive, process_batch_files


def process_file(file_path: Path) -> tuple[bool, str]:
    try:
        with open(file_path, "r", encoding="utf-8") as f:
            _ = f.read()
        return True, "Processed successfully"
    except Exception as e:
        return False, str(e)


def main() -> int:
    parser = create_standard_parser(
        prog="my-tool",
        description="My awesome CLI tool",
        version="1.0.0",
        epilog="Examples:\n  my-tool ./inputs --output ./outputs",
    )
    args = parser.parse_args()

    errors = validate_arguments(args)
    if errors:
        for error in errors:
            print(MessageFormatter.error(error), file=sys.stderr)
        return 1

    logger = setup_logging(args.log_file, args.verbose, args.quiet)
    dirs = setup_directories(Path.cwd())

    logger.info("Starting my-tool")

    try:
        input_files: list[Path] = []
        for p in args.paths:
            input_files.extend(get_files_recursive(p))

        if not input_files:
            print(MessageFormatter.warning("No files found to process"))
            return 0

        print(MessageFormatter.process(f"Found {len(input_files)} files"))

        stats = process_batch_files(
            input_files,
            process_file,
            dirs,
            logger,
            dry_run=args.dry_run,
        )

        print("\n" + "=" * 70)
        if args.dry_run:
            print(MessageFormatter.dry_run(f"Would process: {stats['processed']} files"))
        else:
            if stats["failed"] > 0:
                print(
                    MessageFormatter.warning(
                        f"Processed: {stats['processed']}, Failed: {stats['failed']}"
                    )
                )
            else:
                print(
                    MessageFormatter.success(
                        f"All {stats['processed']} files processed successfully"
                    )
                )

        print("=" * 70 + "\n")
        if args.log_file:
            print(f"Log file: {args.log_file}")
        return 0

    except KeyboardInterrupt:
        print(MessageFormatter.warning("Interrupted by user"), file=sys.stderr)
        logger.warning("Interrupted by user")
        return 130
    except Exception as e:
        print(MessageFormatter.error(str(e)), file=sys.stderr)
        logger.exception("Fatal error")
        return 1


if __name__ == "__main__":
    sys.exit(main())

Modules

colors.py

from cli_commons.colors import Colors, MessageFormatter

print(f"{Colors.GREEN}Success{Colors.END}")
print(MessageFormatter.success("Operation completed"))
print(MessageFormatter.error("Something failed"))
print(MessageFormatter.warning("Be careful"))

logger.py

from pathlib import Path
from cli_commons.logger import setup_logging

logger = setup_logging()  # creates ./logs/process_<timestamp>.log
logger = setup_logging(verbose=True)
logger = setup_logging(quiet=True)
logger = setup_logging(log_file=Path("./my.log"))

logger.info("Information message")
logger.debug("Debug message")
logger.warning("Warning message")
logger.error("Error message")

directories.py

from pathlib import Path
from cli_commons.directories import setup_directories, get_timestamped_dir

dirs = setup_directories()  # inputs/, outputs/, inputs/processed/, inputs/failed/, logs/
timestamped = get_timestamped_dir(Path("./outputs"), prefix="run")

file_ops.py

from pathlib import Path
from cli_commons.file_ops import (
    process_batch_files,
    get_files_recursive,
    get_output_filename,
    safe_rename,
)

def process_file(file_path: Path) -> tuple[bool, str]:
    return True, "Success"

files = get_files_recursive(Path("./inputs"), pattern="*.txt")
stats = process_batch_files(files, process_file, dirs, logger, dry_run=False)
output = get_output_filename(Path("file.txt"), suffix="processed")  # file_processed.txt
safe_rename(Path("old.txt"), Path("new.txt"), logger)

parser.py

from cli_commons.parser import (
    create_standard_parser,
    validate_arguments,
    validate_paths,
    validate_output_dir,
)

parser = create_standard_parser(
    prog="my-tool",
    description="What this tool does",
    version="1.0.0",
    epilog="Examples:\n  my-tool ./input",
)
args = parser.parse_args()

errors = validate_arguments(args)
if errors:
    for error in errors:
        print(error)
    sys.exit(1)

Standard Flags

Flag Short Description
--help -h Show help message
--version Show version
--verbose -v Enable verbose output (DEBUG)
--quiet -q Suppress output (ERROR only)
--dry-run -n Show what would be done
--log-file Save logs to file
--output -o Output directory (default: ./outputs)
--json JSON format output

Directory Structure

Created by setup_directories():

project/
├── inputs/
├── outputs/
├── inputs/processed/
├── inputs/failed/
└── logs/

Requirements

  • Python 3.9 or higher
  • No external dependencies (stdlib only)

License

MIT

Version History

  • 1.0.0 (2025-10-27): Initial release

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

cli_standard_kit-1.0.2.tar.gz (10.0 kB view details)

Uploaded Source

Built Distribution

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

cli_standard_kit-1.0.2-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

File details

Details for the file cli_standard_kit-1.0.2.tar.gz.

File metadata

  • Download URL: cli_standard_kit-1.0.2.tar.gz
  • Upload date:
  • Size: 10.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for cli_standard_kit-1.0.2.tar.gz
Algorithm Hash digest
SHA256 381eb57ca0d320baf90a5c54fd56e24485519cf2c737cfb25242f3a4796c71bc
MD5 c541b0a3a5de5e3f875aca475175d8ae
BLAKE2b-256 7fd675d3a70182c78cb7bb980db6ca4213d4ffeeaebcba3c62c6bb0a2d7255a5

See more details on using hashes here.

Provenance

The following attestation bundles were made for cli_standard_kit-1.0.2.tar.gz:

Publisher: python-publish.yml on c3nk/cli-standard-kit

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

File details

Details for the file cli_standard_kit-1.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for cli_standard_kit-1.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 02bfcbca1745538351c9bd72deebba4a038489ab61e300be83945c13978d3762
MD5 2c435d55f14bb8c6eddb463e907bbdef
BLAKE2b-256 ca714b124a70c766b16a0284aa3f5c9bbac3246016eb1a03398e21e679ea61b1

See more details on using hashes here.

Provenance

The following attestation bundles were made for cli_standard_kit-1.0.2-py3-none-any.whl:

Publisher: python-publish.yml on c3nk/cli-standard-kit

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