Skip to content

fix(release): resolve an interpreter that has tomllib - #159

Merged
anoop-narang merged 2 commits into
mainfrom
fix/release-script-interpreter
Aug 11, 2026
Merged

fix(release): resolve an interpreter that has tomllib#159
anoop-narang merged 2 commits into
mainfrom
fix/release-script-interpreter

Conversation

@anoop-narang

Copy link
Copy Markdown
Contributor

./scripts/release.sh prepare minor fails before doing anything:

ModuleNotFoundError: No module named 'tomllib'

tomllib is stdlib only from 3.11, and this script hardcoded python3 in every
helper -- get_version, get_pkg_name, set_version, bump_version, the changelog
update, and the publish-time changelog check. python3 carries no version
guarantee, and this package's own requires-python is >=3.10, so the release
script could not run on the oldest Python the package claims to support.

No workflow runs this script; only a human cutting a release does, which is why
it went unnoticed. The symptom names a missing module, which reads as a broken
checkout rather than a too-old interpreter.

Resolved lazily inside cmd_prepare and cmd_publish -- not at load time, so the
commands that never touch Python (--help, no-args, unknown command) keep
working on a machine without a usable interpreter. Otherwise the message telling
you which interpreter you need is itself gated on having it.

The uv fallback is justified here because prepare already shells out to
uv lock when a uv.lock is present, so a machine able to cut a release already
has uv. Noted in the comment that CI installs with pip, so this concerns the
local release path only.

Verified as bash runs it:

PATH=/usr/bin:/bin  ./scripts/release.sh --help        -> prints usage
PATH=/usr/bin:/bin  ./scripts/release.sh prepare minor -> error: ... python3 is Python 3.9.6
with uv available                                      -> pkg=hotdata, minor bump 0.8.0 -> 0.9.0

No change to what a release does; only which interpreter runs it.

Ported from hotdata-dev/sdk-python-framework#58 and #60, where the script was
byte-identical. hotdata-marimo carries the same pattern and is untouched here.

`./scripts/release.sh prepare minor` fails before doing anything:

    ModuleNotFoundError: No module named 'tomllib'

tomllib is stdlib only from 3.11, and this script hardcoded `python3` in every
helper -- get_version, get_pkg_name, set_version, bump_version, the changelog
update, and the publish-time changelog check. `python3` carries no version
guarantee, and this package's own requires-python is >=3.10, so the release
script could not run on the oldest Python the package claims to support.

No workflow runs this script; only a human cutting a release does, which is why
it went unnoticed. The symptom names a missing module, which reads as a broken
checkout rather than a too-old interpreter.

Resolved lazily inside cmd_prepare and cmd_publish -- not at load time, so the
commands that never touch Python (`--help`, no-args, unknown command) keep
working on a machine without a usable interpreter. Otherwise the message telling
you which interpreter you need is itself gated on having it.

The `uv` fallback is justified here because `prepare` already shells out to
`uv lock` when a uv.lock is present, so a machine able to cut a release already
has uv. Noted in the comment that CI installs with pip, so this concerns the
local release path only.

Verified as bash runs it:

    PATH=/usr/bin:/bin  ./scripts/release.sh --help        -> prints usage
    PATH=/usr/bin:/bin  ./scripts/release.sh prepare minor -> error: ... python3 is Python 3.9.6
    with uv available                                      -> pkg=hotdata, minor bump 0.8.0 -> 0.9.0

No change to what a release does; only which interpreter runs it.

Ported from hotdata-dev/sdk-python-framework#58 and #60, where the script was
byte-identical. hotdata-marimo carries the same pattern and is untouched here.
@anoop-narang
anoop-narang requested a review from a team as a code owner August 11, 2026 08:44
@anoop-narang
anoop-narang requested review from rohan-hotdata and removed request for a team August 11, 2026 08:44
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh Outdated
Comment thread scripts/release.sh Outdated
claude[bot]
claude Bot previously approved these changes Aug 11, 2026

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness checks I walked through:

  • Every $PY_BIN consumer (get_version, get_pkg_name, set_version, bump_version, update_changelog, the publish-time changelog check) is only reachable from cmd_prepare/cmd_publish, so the deferred resolution covers all of them and the empty default is genuinely unreachable.
  • die inside $(resolve_python) exits the subshell, but the assignment inherits status 1 and set -e is in force at that call site (a case branch, not a condition), so the script aborts with the message rather than continuing with an empty PY_BIN.
  • --no-project matters on the uv path: set_version rewrites pyproject.toml, and uv must not try to resolve the project around it. uv's own progress output goes to stderr, so the $(get_version) captures stay clean.
  • scripts/update_changelog.py is pure stdlib and doesn't need 3.11, so routing it through $PY_BIN is consistency rather than necessity — no behavior change there.
  • scripts/publish-workflow.sh:41 runs the same import tomllib in CI but under setup-python pinned to 3.12, so the CI publish path is unaffected by this class of bug.

I did not execute the script; the verification runs in the description are the author's. Two non-blocking notes inline.

Resolution ran before the bump-kind check, so `prepare` with no argument died
with the interpreter error instead of printing usage -- contradicting the
comment above it, which is specifically about keeping the paths that need no
interpreter working. Moved below the usage and `need gh` checks; nothing between
them uses $PY_BIN. Same reordering in cmd_publish, so a missing `gh` reports
itself rather than being pre-empted.

And `--python 3.12` was an exact request: on a machine whose uv-visible
interpreter is 3.11 or 3.13 it downloads a managed 3.12 mid-release, and fails
altogether under UV_PYTHON_DOWNLOADS=never. Now `>=3.11`, which is the real
requirement. Verified the unquoted expansion is not a redirect -- it reaches uv
as a literal argument and no `=3.11` file appears -- and that uv then reuses the
interpreter already present.

  prepare (no args)        -> usage + "missing bump kind or explicit version"
  resolves to             -> uv run --no-project --python >=3.11 python
  pkg=hotdata, minor bump -> 0.9.0

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prior nits addressed. Interpreter resolution now sits after the usage/need gh checks in both commands, and the >=3.11 request avoids pinning a download mid-release. update_changelog.py is stdlib-only, so --no-project is fine for the one non-heredoc call site.

anoop-narang added a commit to hotdata-dev/sdk-python-framework that referenced this pull request Aug 11, 2026
Both found in review of the same change ported to sdk-python
(hotdata-dev/sdk-python#159), and both apply here because the script is the
same.

Resolution ran before the bump-kind check, so `prepare` with no argument died
with the interpreter error instead of printing usage -- contradicting the
comment right above it, which exists to keep the no-interpreter paths working.
Moved below the usage and `need gh` checks; nothing between them uses $PY_BIN.
Same in cmd_publish, so a missing `gh` reports itself.

And `--python 3.12` was an exact request: on a machine whose uv-visible
interpreter is 3.11 or 3.13 it downloads a managed 3.12 mid-release, and fails
altogether under UV_PYTHON_DOWNLOADS=never. Now `>=3.11`. Verified the unquoted
expansion is not a redirect -- uv receives it literally and no `=3.11` file
appears -- and that uv reuses the interpreter already present.
@anoop-narang
anoop-narang merged commit 0e11e3c into main Aug 11, 2026
4 checks passed
@anoop-narang
anoop-narang deleted the fix/release-script-interpreter branch August 11, 2026 10:05
anoop-narang added a commit to hotdata-dev/sdk-python-framework that referenced this pull request Aug 11, 2026
…#60)

* docs(release): justify the interpreter check from the repo, not an OS

The comment rested on `python3` being 3.9 on macOS, which is where the failure
showed up rather than why the code was wrong -- and a reader on another
platform would take it as not applying to them.

The repo-intrinsic version: this package declares requires-python >=3.10 and
tomllib is stdlib only from 3.11, so the release script could not run on the
oldest Python the package itself claims to support, on any OS. Also records why
it stayed hidden -- CI installs 3.12 through uv, so only a human cutting a
release ever ran into it.

Comment only; no behaviour change.

* docs(release): CI does not run this script at all

"CI never sees this because it installs 3.12" was true but named the wrong
shield: no workflow invokes release.sh, so the pinned interpreter is not what
protects CI from this. Confirmed -- grep for release.sh across .github/workflows
returns nothing.

Since the point of the previous rewrite was to ground the comment in facts that
stay true, this is the more durable sentence.

Comment only.

* fix(release): resolve after the argument checks, and ask uv for a range

Both found in review of the same change ported to sdk-python
(hotdata-dev/sdk-python#159), and both apply here because the script is the
same.

Resolution ran before the bump-kind check, so `prepare` with no argument died
with the interpreter error instead of printing usage -- contradicting the
comment right above it, which exists to keep the no-interpreter paths working.
Moved below the usage and `need gh` checks; nothing between them uses $PY_BIN.
Same in cmd_publish, so a missing `gh` reports itself.

And `--python 3.12` was an exact request: on a machine whose uv-visible
interpreter is 3.11 or 3.13 it downloads a managed 3.12 mid-release, and fails
altogether under UV_PYTHON_DOWNLOADS=never. Now `>=3.11`. Verified the unquoted
expansion is not a redirect -- uv receives it literally and no `=3.11` file
appears -- and that uv reuses the interpreter already present.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant