Skip to main content

CAC Core

An API client library providing essential functionality for command-line applications.

This project uses UV for dependency management.

Overview

CAC Core (cac-core) is a Python library that provides common utilities for building robust command-line applications. It includes modules for commands, configuration management, standardized logging, data modeling, and formatted output display.

Features

  • CLI Runner: A shared entry point (cac_core.cli.run / make_main) that discovers a package's commands/ tree, builds the nested argparse parser, wires up shell completion, and dispatches — so a CLI tool is just its commands plus a one-line entry point
  • Command: Abstract base class with a run()/handle_exception() exit-code template; subclasses implement define_arguments() and execute()
  • Shell Completion: Tab-completion of commands, actions, and options via argcomplete, wired automatically by the runner
  • Configuration Management: Load/save configs from YAML files with environment variable support, plus ensure_keys() for interactive first-run setup
  • Standardized Logging: Consistent, configurable logging across applications
  • Data Modeling: Dynamic attribute creation and manipulation with dictionary-like access
  • Output Formatting: Display data as tables or JSON with customization options
  • Update Checking: Automatically check for package updates from PyPI or GitHub, with configurable intervals and notification options

Installation

pip install cac-core

Usage

Building a CLI application (recommended)

A cac-* tool is just a package with a commands/ tree and a one-line entry point. The shared runner handles discovery, argument parsing, shell completion, and dispatch.

Layout:

myapp/
  __init__.py        # defines `main`
  commands/
    __init__.py
    greet/
      __init__.py
      hello.py       # class GreetHello(Command)

myapp/__init__.py:

from cac_core.cli import make_main

# wire the console-script entry point to this callable:
#   [project.scripts]  myapp = "myapp:main"
main = make_main("myapp", "myapp", "My CLI tool")

myapp/commands/greet/hello.py — the class name must be {Command}{Action} (here GreetHello), and modules whose name starts with _ are treated as private and skipped by discovery:

import cac_core as cac

class GreetHello(cac.command.Command):
    def define_arguments(self, parser):
        self.define_common_arguments(parser)   # adds --output/--verbose
        parser.add_argument("--name", default="World")
        return parser

    def execute(self, args):
        # Return an int exit code (or None for success). Errors may propagate;
        # the base run()/handle_exception template logs them and returns 1.
        print(f"Hello, {args.name}!")
        return 0

That's it — myapp greet hello --name Ada, myapp --help, myapp --verbose greet hello, and tab-completion (see below) all work. Enable completion with eval "$(register-python-argcomplete myapp)" in your shell.

Command (low-level)

You can also drive a Command directly, without the runner:

import cac_core as cac

# Create a command class
class HelloCommand(cac.command.Command):
    def define_arguments(self, parser):
        """Define command arguments"""
        parser.add_argument('--name', default='World',
                          help='Name to greet')

    def execute(self, args):
        """Execute the command with parsed arguments"""
        logger = cac.logger.new(__name__)
        logger.info(f"Hello, {args.name}!")
        return f"Hello, {args.name}!"

# Use the command in your application
if __name__ == "__main__":
    # Create argument parser
    import argparse
    parser = argparse.ArgumentParser(description='Demo application')

    # Initialize command
    cmd = HelloCommand()

    # Add command arguments
    cmd.define_arguments(parser)

    # Parse arguments
    args = parser.parse_args()

    # Execute command
    result = cmd.execute(args)

    # Display result
    print(result)

Configuration

import cac_core as cac

# Load configuration
config = cac.config.Config("myapp")
server_url = config.get("server", "default-value")

# Update configuration
config.set("api_key", "my-secret-key")
config.save()

Logging

import cac_core as cac

# Create a logger
logger = cac.logger.new(__name__)
logger.info("Application started")
logger.debug("Debug information")

Data Models

import cac_core as cac

# Create data model
data = {
    "name": "Project X",
    "status": "active",
    "metadata": {
        "created": "2025-01-01",
        "version": "1.0"
    }
}

model = cac.model.Model(data)
print(model.name)  # "Project X"
print(model.metadata.version)  # "1.0"

Output Formatting

import cac_core as cac

# Create output handler
output = cac.output.Output({"output": "table"})

# Display data as table
models = [model1, model2, model3]
output.print_models(models)

# Display as JSON
output = cac.output.Output({"output": "json"})
output.print_models(models)

Update Checking

import cac_core as cac

# Check for updates to your package (using PyPI by default)
checker = cac.updatechecker.UpdateChecker("your-package-name")
status = checker.check_for_updates()

# Notify users if an update is available
if status["update_available"]:
    print(f"Update available: {status['current_version']} → {status['latest_version']}")

# Convenience function for quick checks
cac.updatechecker.check_package_for_updates("your-package-name", notify=True)

# Configure source options
# PyPI (default)
pypi_checker = cac.updatechecker.UpdateChecker(
    "your-package-name",
    source="pypi"  # This is the default, so it's optional
)

# GitHub
github_checker = cac.updatechecker.UpdateChecker(
    "your-package-name",
    source="github",
    repo="username/repo-name"
)

# Add update checking to your CLI application
def main():
    # Check for updates once per day
    from datetime import timedelta
    checker = cac.updatechecker.UpdateChecker(
        "your-package-name",
        check_interval=timedelta(days=1)
    )

    # Only notify if update is available, otherwise be quiet
    checker.check_for_updates()
    checker.notify_if_update_available(quiet=True)

    # Rest of your application...

Development

pip install uv

# Clone the repository
git clone https://github.com/rpunt/cac_core.git
cd cac_core
uv venv
uv pip install -e .

# Install dependencies
uv pip install -e ".[dev]"
uv pip install -e ".[test]"
uv pip install -e ".[lint]"

# Run tests
uv run pytest

Project Structure

  • cli.py - Shared CLI runner (run / make_main): discovery, argument parsing, completion, dispatch
  • command.py - Abstract Command base class and exit-code template
  • config.py - Configuration management
  • logger.py - Standardized logging
  • model.py - Data modeling utilities
  • output.py - Output formatting
  • credentialmanager.py - Cross-platform credential storage
  • updatechecker.py - PyPI/GitHub update checks

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Metadata

Release files for cac-core 2.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cac-core 2.0.1
File Size Uploaded
cac_core-2.0.1.tar.gz 120.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cac-core 2.0.1
File Interpreter ABI Platform
cac_core-2.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 151.0 kB

Release files / cac_core-2.0.1.tar.gz

Download URL cac_core-2.0.1.tar.gz
Size 120.4 kB
Tags Source
SHA-256 checksum
How to use checksums
79f9b1f5f78e917f6f17a6adcae3b3b9a27184329705345c370dd6bb3647f1af
BLAKE2b-256 checksum
How to use checksums
211336d47bb7e53d326b69560f759ac8b6c80ece197fce310a55482a967689b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.

Transparency log

Release files / cac_core-2.0.1-py3-none-any.whl

Download URL cac_core-2.0.1-py3-none-any.whl
Size 30.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
3bba854d3af8a1bd6dbbf01ed6f16137cae239979db937a6b23911c560e5d064
BLAKE2b-256 checksum
How to use checksums
7b306c520342a6803f9de9ea075d291704bd33984dd9b29ef9b4e6daf680c443
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jul 21, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

2.0.1 This release

2 release files

2.0.0

2 release files

1.0.0

2 release files

0.7.0

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page