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
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
381eb57ca0d320baf90a5c54fd56e24485519cf2c737cfb25242f3a4796c71bc
|
|
| MD5 |
c541b0a3a5de5e3f875aca475175d8ae
|
|
| BLAKE2b-256 |
7fd675d3a70182c78cb7bb980db6ca4213d4ffeeaebcba3c62c6bb0a2d7255a5
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cli_standard_kit-1.0.2.tar.gz -
Subject digest:
381eb57ca0d320baf90a5c54fd56e24485519cf2c737cfb25242f3a4796c71bc - Sigstore transparency entry: 645581174
- Sigstore integration time:
-
Permalink:
c3nk/cli-standard-kit@64343e2355891fb96299ed41d1581bec267b5f49 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/c3nk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@64343e2355891fb96299ed41d1581bec267b5f49 -
Trigger Event:
push
-
Statement type:
File details
Details for the file cli_standard_kit-1.0.2-py3-none-any.whl.
File metadata
- Download URL: cli_standard_kit-1.0.2-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02bfcbca1745538351c9bd72deebba4a038489ab61e300be83945c13978d3762
|
|
| MD5 |
2c435d55f14bb8c6eddb463e907bbdef
|
|
| BLAKE2b-256 |
ca714b124a70c766b16a0284aa3f5c9bbac3246016eb1a03398e21e679ea61b1
|
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
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cli_standard_kit-1.0.2-py3-none-any.whl -
Subject digest:
02bfcbca1745538351c9bd72deebba4a038489ab61e300be83945c13978d3762 - Sigstore transparency entry: 645581195
- Sigstore integration time:
-
Permalink:
c3nk/cli-standard-kit@64343e2355891fb96299ed41d1581bec267b5f49 -
Branch / Tag:
refs/tags/v1.0.3 - Owner: https://github.com/c3nk
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@64343e2355891fb96299ed41d1581bec267b5f49 -
Trigger Event:
push
-
Statement type: