Skip to main content

CLI exit handling helpers: clean signals, exit codes, and error printing

Project description

lib_cli_exit_tools

CI CodeQL License: MIT Jupyter PyPI PyPI - Downloads Code Style: Ruff codecov Maintainability Known Vulnerabilities

Small helpers for robust CLI exit handling:

  • Portable signal handling (SIGINT, SIGTERM/SIGBREAK)
  • Consistent exception → exit code mapping
  • Concise error printing with optional traceback and subprocess stdout/stderr capture

Install

Pick one of the options below. All methods register the lib_cli_exit_tools and cli-exit-tools commands on your PATH.

1) Standard virtualenv (pip)

python -m venv .venv
source .venv/bin/activate  # Windows: .venv\\Scripts\\activate
pip install -e .[dev]       # dev install
# or for runtime only:
pip install .

2) Per-user (no venv)

pip install --user .

Note: respects PEP 668; avoid on system Python if “externally managed”. Ensure ~/.local/bin (POSIX) is on PATH.

3) pipx (isolated, recommended for end users)

pipx install .
pipx upgrade lib_cli_exit_tools
# From Git tag/commit:
pipx install "git+https://github.com/bitranox/lib_cli_exit_tools@v0.1.0"

4) uv (fast installer/runner)

uv pip install -e .[dev]
uv tool install .
uvx lib_cli_exit_tools --help

5) From artifacts

python -m build
pip install dist/lib_cli_exit_tools-*.whl
pip install dist/lib_cli_exit_tools-*.tar.gz   # sdist

6) Poetry / PDM (project-managed envs)

# Poetry
poetry add lib_cli_exit_tools     # as dependency
poetry install                    # for local dev

# PDM
pdm add lib_cli_exit_tools
pdm install

7) From Git via pip (CI-friendly)

pip install "git+https://github.com/bitranox/lib_cli_exit_tools@v0.1.0#egg=lib_cli_exit_tools"

8) Conda/mamba (optional)

mamba create -n cli-exit python=3.12 pip
mamba activate cli-exit
pip install .

9) System package managers (optional distribution)

  • Homebrew formula (macOS): brew install lib_cli_exit_tools (if published)
  • Nix: flake/package for reproducible installs
  • Deb/RPM via fpm for OS-native packages

Make Targets

Target Description
help Show help
install Install package editable
dev Install package with dev extras
test Lint, type-check, run tests with coverage, upload to Codecov
run Run module CLI (requires dev install or src on PYTHONPATH)
version-current Print current version from pyproject.toml
bump Bump version: VERSION=X.Y.Z or PART=major
bump-patch Bump patch version (X.Y.Z -> X.Y.(Z+1))
bump-minor Bump minor version (X.Y.Z -> X.(Y+1).0)
bump-major Bump major version ((X+1).0.0)
clean Remove caches, build artifacts, and coverage
push Commit all changes once and push to GitHub (no CI monitoring)
build Build wheel/sdist and attempt conda, brew, and nix builds (auto-installs tools if missing)

Target Details

  • test: single entry point for local CI — runs ruff lint + format check, pyright, pytest (including doctests) with coverage (enabled by default), and uploads coverage to Codecov if configured (reads .env).
  • Auto‑bootstrap: make test will try to install dev tools (pip install -e .[dev]) if ruff/pyright/pytest are missing. Set SKIP_BOOTSTRAP=1 to skip this behavior.
  • build: convenient builder — creates Python wheel/sdist, then attempts Conda, Homebrew, and Nix builds. It auto‑installs missing tools (Miniforge, Homebrew, Nix) when needed.
  • install/dev/user-install: common install flows for editable or per‑user installs.
  • version-current: prints current version from pyproject.toml.
  • bump: updates pyproject.toml version and inserts a new section in CHANGELOG.md. Use VERSION=X.Y.Z make bump or make bump-minor/bump-major/bump-patch.
  • pipx-* and uv-*: isolated CLI installations for end users and fast developer tooling.
  • which-cmd/verify-install: quick diagnostics to ensure the command is on PATH.

Usage

Console script:

# After install (pip/pipx/uv tool)
lib_cli_exit_tools --help
cli-exit-tools --help  # alias
lib_cli_exit_tools info

Library:

import lib_cli_exit_tools

lib_cli_exit_tools.config.traceback = False  # show short messages
try:
    raise FileNotFoundError("missing.txt")
except Exception as e:
    code = lib_cli_exit_tools.get_system_exit_code(e)   # 2 on POSIX
    lib_cli_exit_tools.print_exception_message()        # prints: FileNotFoundError: missing.txt
    raise SystemExit(code)

Command names registered on install

  • lib_cli_exit_tools (default)
  • cli-exit-tools (alias)
  • python -m lib_cli_exit_tools (module entry)

If you installed with --user or in a venv, make sure the corresponding bin directory is on PATH:

  • Linux/macOS venv: .venv/bin
  • Linux/macOS user: ~/.local/bin
  • Windows venv: .venv\Scripts
  • Windows user: %APPDATA%\Python\PythonXY\Scripts

Exit Codes

  • SIGINT → 130, SIGTERM → 143 (POSIX), SIGBREAK → 149 (Windows)
  • SystemExit(n) → n
  • Common exceptions map to POSIX/Windows codes (FileNotFoundError, PermissionError, ValueError, etc.)

Broken pipe behavior

  • Default: exit 141 quietly (128+SIGPIPE), no noisy error output.
  • Configure: config.broken_pipe_exit_code = 0 to treat as benign truncation, or 32 (EPIPE).

Sysexits mode (optional)

  • Set config.exit_code_style = "sysexits" to map ValueError/TypeError → EX_USAGE(64), FileNotFoundError → EX_NOINPUT(66), PermissionError → EX_NOPERM(77), generic OSError → EX_IOERR(74).

Development

make test                 # ruff + pyright + pytest + coverage (default ON)
SKIP_BOOTSTRAP=1 make test  # skip auto-install of dev deps
COVERAGE=off make test       # disable coverage locally
COVERAGE=on make test        # force coverage and generate coverage.xml/codecov.xml

Packaging sync (Conda/Brew/Nix)

  • make test and make push automatically align the packaging skeletons in packaging/ with the current pyproject.toml:

    • Conda: updates {% set version = "X.Y.Z" %} and both python >=X.Y constraints to match requires-python.
    • Homebrew: updates the source URL tag to vX.Y.Z and sets depends_on "python@X.Y" to match requires-python.
    • Nix: updates the package version, example rev = "vX.Y.Z", and switches pkgs.pythonXYZPackages / pkgs.pythonXYZ to match the minimum Python version from requires-python.
  • To run just the sync without bumping versions: python tools/bump_version.py --sync-packaging.

  • On release tags (v*.*.*), CI validates that packaging files are consistent with pyproject.toml and will fail if they drift.

Versioning & Metadata

  • Single source of truth for package metadata is pyproject.toml ([project]).
  • The library reads its own installed metadata at runtime via importlib.metadata (see src/lib_cli_exit_tools/__init__conf__.py).
  • Do not duplicate the version in code; bump only pyproject.toml and update CHANGELOG.md.
  • Console script name is discovered from entry points; defaults to lib_cli_exit_tools.

Packaging Skeletons

Starter files for package managers live under packaging/:

  • Conda: packaging/conda/recipe/meta.yaml (update version + sha256)
  • Homebrew: packaging/brew/Formula/lib-cli-exit-tools.rb (fill sha256 and vendored resources)
  • Nix: packaging/nix/flake.nix (use working tree or pin to GitHub rev with sha256)

These are templates; fill placeholders (e.g., sha256) before publishing. Version and Python constraints are auto-synced from pyproject.toml by make test/make push and during version bumps.

CI & Publishing

GitHub Actions workflows are included:

  • .github/workflows/ci.yml — lint/type/test, build wheel/sdist, verify pipx and uv installs, Nix and Conda builds (CI-only; no local install required).
  • .github/workflows/release.yml — on tags v*.*.*, builds artifacts and publishes to PyPI when PYPI_API_TOKEN secret is set.

To publish a release:

  1. Bump pyproject.toml version and update CHANGELOG.md.
  2. Tag the commit (git tag v0.1.1 && git push --tags).
  3. Ensure PYPI_API_TOKEN secret is configured in the repo.
  4. Release workflow uploads wheel/sdist to PyPI.

Conda/Homebrew/Nix: use files in packaging/ to submit to their ecosystems. CI also attempts builds to validate recipes, but does not publish automatically.

Local Codecov uploads

  • make test (with coverage enabled) generates coverage.xml and codecov.xml, then attempts to upload via the Codecov CLI or the bash uploader.
  • For private repos, set CODECOV_TOKEN (see .env.example) or export it in your shell.
  • For public repos, a token is typically not required.

License

MIT

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

lib_cli_exit_tools-1.0.0.tar.gz (33.6 kB view details)

Uploaded Source

Built Distribution

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

lib_cli_exit_tools-1.0.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file lib_cli_exit_tools-1.0.0.tar.gz.

File metadata

  • Download URL: lib_cli_exit_tools-1.0.0.tar.gz
  • Upload date:
  • Size: 33.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for lib_cli_exit_tools-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3e517915b21c2742d350a577ee1e8207f2269525d1d7e69e738da5941b6ad874
MD5 f4f9e95add38b02e6ca9c626ff643278
BLAKE2b-256 5f98c7bd4ce4b6d20127d0cacda29a47238a2be8187946f423bf03442fb236dc

See more details on using hashes here.

File details

Details for the file lib_cli_exit_tools-1.0.0-py3-none-any.whl.

File metadata

File hashes

Hashes for lib_cli_exit_tools-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eadfd037a6cd6502101caf57d63a8a918f7fe19c3a8863a8378db1c1e994d12a
MD5 7a77395fd956a6bccc10697bb7bdc89c
BLAKE2b-256 2c676b3c2628832feb87386a9cdab68f9c2deba9b092d84e56ed12bbc62534a0

See more details on using hashes here.

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