Skip to main content

update-kit

Self-update for Python CLIs that are released as git tags (vX.Y.Z or X.Y.Z) and installed with uv tool or pipx. Stdlib only, Python ≥ 3.10, macOS / Linux / Windows.

  • <cmd> update installs the newest release tag — no prompts, ever.
  • A cached background check prints a one-line hint on an interactive terminal only.
  • Every message exists in English and Traditional Chinese (zh-TW).

Install

# consumer pyproject.toml
dependencies = ["update-kit>=0.1,<0.2"]

Wiring a consumer CLI

import sys

import update_kit

from my_cli import __version__

APP, REPO, DIST = "my-cli", "owner/my-cli", "my-cli"


def main(argv=None):
    argv = sys.argv[1:] if argv is None else argv
    lang = "zh-TW"  # the app's own current language setting

    # `my-cli update` and `my-cli --update`
    if argv[:1] == ["update"] or "--update" in argv:
        sys.exit(update_kit.update(
            app=APP, repo=REPO, dist=DIST, lang=lang,
            after=[["my-cli", "migrate"]],  # optional: runs with the NEW binary
        ))

    # Background hint: stderr, TTY only (never under launchd/timers/--json/pipes).
    if update_kit.should_hint():
        latest = update_kit.check(repo=REPO, current=__version__)
        if latest:
            print(update_kit.hint("my-cli", latest, __version__, lang), file=sys.stderr)
    ...

API

Function Does
latest_tag(repo, *, timeout=5, url=None) -> str Newest strict v?X.Y.Z tag (ASCII digits) via git ls-remote --tags --refs. Prereleases and other names are ignored. Raises UpdateError (offline, no tags, git missing).
install_kind(dist) -> (kind, detail) "dev" (PEP 610 local/editable dir, detail = the dir), "uv" / "pipx" (from sys.prefix), else "unknown".
update(*, app, repo, dist, current=None, lang="en", after=(), out=sys.stderr, run=subprocess.run, url=None) -> int Exit code: 0 updated or already up to date · 1 couldn't check (offline/rate limit) or install/after-step failed · 2 dev install (use git pull) or unknown install (manual command printed).
check(*, repo, current, cache_path=None, ttl=86400, timeout=1.5, url=None) -> str | None Newer tag or None. Never raises. Results — failures too — are cached for ttl in $HOME/.update-kit/state.json, keyed by the resolved source URL.
hint(cmd, latest, current, lang="en") -> str my-cli v1.2.0 is available (you have 1.1.0) — run `my-cli update`
should_hint(stream=sys.stderr) -> bool True only when stream is a TTY.
normalize_lang(value) -> str zh_TW / zh-tw / zh-Hant / zh_HK → "zh-TW"; anything else → "en".

Install commands used by update:

  • uv: uv tool install --force --no-sources git+<url>@<tag>
  • pipx: pipx install --force git+<url>@<tag>

<url> is url=, else $UPDATE_KIT_REPO_URL, else https://github.com/<repo>.git (file:// works, which is how the tests run without a network). Only https://, ssh://, file:// and git@host:path are accepted (ssh://git@host/... is fine, ssh://user:pass@ is not; git@host:path is installed as ssh://git@host/path); a leading -, whitespace/control characters, ext:: or credentials in the URL (user:pass@) raise UpdateError (update returns 1, check returns None). When $UPDATE_KIT_REPO_URL is in effect, update prints one line naming it. git ls-remote runs as git -c protocol.ext.allow=never ls-remote --tags --refs -- <url> from the home directory, and so does the install; git's stderr is stripped of control characters.

Windows: the running .exe is locked, so update starts the install (and the after steps, chained with &&) in a detached cmd.exe that waits a few seconds for the app to exit, returns 0 and says the update continues in the background. Output goes to %USERPROFILE%\.update-kit\<app>-update.log. Unlike POSIX (where every after-step runs and any failure makes the result 1), the Windows chain stops at the first failing step and the outcome is only in the log. An install whose arguments or log path contain a cmd.exe metacharacter (& | < > ^ % " ( ) !) is refused with exit 1 instead of being spawned.

git ls-remote never prompts: GIT_TERMINAL_PROMPT=0, and GIT_SSH_COMMAND defaults to ssh -o BatchMode=yes when unset. The install step (uv / pipx) also runs with GIT_TERMINAL_PROMPT=0 and GCM_INTERACTIVE=never.

Development

uv sync
uv run pytest
uv run ruff check .
uv build

License

MIT

Metadata

Release files for update-kit 0.1.0

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

Source distribution (sdist)

Source distribution for update-kit 0.1.0
File Size Uploaded
update_kit-0.1.0.tar.gz 29.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for update-kit 0.1.0
File Interpreter ABI Platform
update_kit-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.3 kB

Release files / update_kit-0.1.0.tar.gz

Download URL update_kit-0.1.0.tar.gz
Size 29.4 kB
Tags Source
SHA-256 checksum
How to use checksums
cb01aa777359bddb92b64d685f5cf498c8dc3da66d86719e05dddd556232b452
BLAKE2b-256 checksum
How to use checksums
6b8e919696cf167397baa2a56c93302b745152734886c407261f92adc9bfde96
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / update_kit-0.1.0-py3-none-any.whl

Download URL update_kit-0.1.0-py3-none-any.whl
Size 9.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa337eef12e65792db8a4b09773b621fdf0ab7084c3998713e860cd0388c3d08
BLAKE2b-256 checksum
How to use checksums
0b7e72eb6ac00af7df4f8b304e74e61c9d9c16ee5f4647e3cf39734f63419ce4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

0.2.1

2 release files

This release

0.1.0 This release

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