Skip to content

chore(release): bump KCL to v0.13.2 - #410

Merged
Peefy merged 7 commits into
mainfrom
chore/kcl-0.13.2
Oct 19, 2026
Merged

Peefy merged 7 commits into
mainfrom
chore/kcl-0.13.2

Conversation

@Peefy

@Peefy Peefy commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Two commits: the 0.13.2 version bump, and CPython 3.15 wheel support (#404).

1. chore(release): bump KCL to v0.13.2

  • Bump KCL_VERSION in go/install/install.go and every binding's package version from 0.13.1 to 0.13.2, now that kcl-lang/kcl v0.13.2 is published. The runtime pin and the package version move together: the prebuilt binaries every binding vendors come from that release (see docs/lib-vendoring.md).
  • Move the kcl-* git dependencies with it. They are unpinned to the default branch, whose workspace version is already 0.13.2, so the 0.13.1 requirement no longer resolved — this part is a build fix, not cosmetics.
  • Rename lua/kcl_lib-0.13.1-3.rockspec to kcl_lib-0.13.2-3.rockspec; publish-luarocks.yaml globs for it by version and errors unless exactly one matches.

Comments recording what changed in v0.13.1 are left alone — historical, not stale.

2. feat(python): build wheels for CPython 3.15

  • pyo3 =0.20.2 → 0.30, the first line with final 3.15 support.
  • maturin floor >=1.5 → >=1.14; CI pins v1.15.0.
  • requires-python 3.7 → 3.10.

The pyo3 pin was dead weight. =0.20.2 existed because of PyO3/maturin#1960 — the action built against interpreters newer than pyo3's documented ceiling (3.12) and hard-failed. That closed in Feb 2024 once maturin 1.5 stopped detecting too-new interpreters, so the pin has been constraining nothing for two years. cp313/cp314 only worked because the workflow also set PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1, which is precisely the escape hatch that issue was about; that variable is now dropped.

Source change is one line: #[pymodule] takes &Bound<'_, PyModule> under the post-0.21 API. The crate is two #[pyfunction]s, so that migration is the entire surface.

requires-python was a lie in both directions. It said >=3.7, and protobuf 7.x — the wheel's only runtime dependency — requires >=3.10, so no build below 3.10 could ever install: pip resolves protobuf, finds no compatible version, and refuses. Declaring the floor that actually works means pip says no up front instead of failing halfway through. maturin skips interpreters below requires-python during --find-interpreter rather than erroring, so the Linux images' CPython 3.9 simply stops being probed and the cp39 wheels are no longer built.

How the cp315 wheel actually gets built

The wheel jobs pass --find-interpreter, which means "build for every interpreter maturin can find", not "build for one". The runner images already cover a wide range — but three of the four platforms needed something more:

Job Image Interpreters found
linux x86_64 quay.io/pypa/manylinux2014_x86_64 (native) 3.10–3.15, 3.14t, 3.15t, PyPy 3.11
linux aarch64 ghcr.io/rust-cross/manylinux2014-cross:aarch64 (cross) 3.10–3.14, 3.14t, PyPy 3.11 — 3.15 and 3.15t missing
macos host image 3.11–3.15
windows host image 3.10–3.14 — 3.15 missing
  • Windows stops at 3.14, so that job runs actions/setup-python for 3.15. setup-python adds to what maturin discovers rather than replacing it, so 3.10–3.14 are still built.
  • Linux aarch64 is a cross build, so maturin-action runs it in the rust-cross image rather than the native manylinux one. That image does carry 3.15 and 3.15t, but --find-interpreter never offers them — it reports 3.10 through 3.14, 3.14t and PyPy 3.11 and stops. Naming them explicitly (-i python3.15, -i python3.15t) resolves, so the aarch64 leg builds those two wheels in separate steps.
  • Linux x86_64 and macOS need nothing; their images already carry 3.15.

An earlier revision of this PR added a python: [default, "3.15"] matrix dimension to all the wheel jobs. That was redundant for x86_64 and macOS and actively harmful: macOS produced a byte-identical cp315 wheel under two artifact names, and those collide once the release job merges artifacts. The dimension is gone. The test job keeps its 3.x/3.15 matrix, where the version selects what is exercised rather than what is packaged — both legs are worth running there.

Wheel coverage, 0.13.1 → 0.13.2

Platform 0.13.1 0.13.2
linux x86_64 3.9–3.14, PyPy 3.11 3.10–3.15, 3.14t, 3.15t, PyPy 3.11
linux aarch64 3.7–3.14, PyPy 3.8–3.11 3.10–3.15, 3.14t, 3.15t, PyPy 3.11
macOS 3.11–3.14 3.11–3.15
Windows 3.10–3.14 3.10–3.15

Every platform gains 3.15. The dropped 3.7/3.8/3.9 and older PyPy builds are all unusable — protobuf 7.x needs Python >= 3.10 — and they are gone because requires-python now excludes them, not because anything was dropped by hand.

One thing worth a reviewer's eye

The release job's artifact download changed shape. It listed four artifacts by exact name, which would have needed hand-editing for every new Python version. It's now a single pattern: wheels-*-<run_id> download with merge-multiple. The wheels- prefix deliberately excludes the sdist artifact, which was never published either before or after. This is the one change on the PyPI publishing path that isn't exercised by a normal PR run (release is tag-gated), so it's the thing most worth a second look.

Test plan

  • cargo metadata resolves — the 0.13.2 git requirement builds the full graph
  • maturin develop on Python 3.14 with pyo3 0.30.1 / maturin 1.15.0; 176 tests pass, 2 skipped
  • Workflow YAML parses; the test job still resolves its 3.x/3.15 matrix
  • CI green on Linux/macOS/Windows; the four wheel artifacts contain 29 wheels with no duplicate filenames
  • Every platform ships a cp315 wheel — including linux aarch64, which needed an explicit build

🤖 Generated with Claude Code

Peefy and others added 2 commits October 16, 2026 22:24
Moves KCL_VERSION in go/install/install.go and every binding's package
version from 0.13.1 to 0.13.2, now that kcl-lang/kcl has cut v0.13.2.
The prebuilt binaries every binding vendors are downloaded from that
release, so the runtime pin and the package version have to move
together.

The kcl-* git dependencies move with it for a second reason: they are
unpinned to the default branch, whose workspace version is already
0.13.2, so the 0.13.1 requirement no longer resolves.

Renames the lua rockspec to match the new package_version, which
publish-luarocks.yaml globs for by name.

Comments recording what changed *in* v0.13.1 (the LoadPackageResult
fields, the ListDepFiles removal) are left alone; they are historical.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
Moves pyo3 from the pinned 0.20.2 to 0.30, the first line with final
Python 3.15 support, and gives the wheel jobs a Python dimension so a
cp315 leg actually gets built. Closes #404.

The pyo3 pin was `=0.20.2` because of PyO3/maturin#1960, where the
action built against interpreters newer than pyo3's documented ceiling
(3.12) and hard-failed. That issue closed in Feb 2024 once maturin 1.5
stopped detecting too-new interpreters, so the pin has been load-bearing
for nothing for two years. cp313/cp314 only worked because the workflow
also set PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1, which is exactly the
escape hatch that issue was about; with 0.30 that variable is dropped.

The only source change is the #[pymodule] signature, which takes
&Bound<'_, PyModule> under the post-0.21 API. The &PyModule-to-Bound
migration is otherwise the whole surface -- this crate uses two
#[pyfunction]s and nothing else.

requires-python moves 3.7 -> 3.9 to match pyo3 0.30's own floor. Note
protobuf >=7.36.2 already requires >=3.10, so the cp37/cp38 wheels that
were being published could not actually install; that pre-existing gap
is unchanged by this commit.

Verified locally on 3.14 with maturin 1.15.0: builds, 176 tests pass.
The 3.15 legs themselves can only be exercised in CI.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
Peefy and others added 5 commits October 16, 2026 23:11
maturin rejects the two together, so the Linux 3.15 leg died on
`--find-interpreter cannot be used with --interpreter`. The pinned leg
now passes `-i python3.15` alone and the default leg keeps
`--find-interpreter` alone; previously the expression appended `-i` on
top of an unconditional `--find-interpreter`.

Caught by CI, not locally: the Linux job builds inside the manylinux
container, while a local `maturin develop` is a host build that never
passes `-i`. Windows 3.15 and the 3.15 test legs passed, which is why
only the linux jobs failed.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Peefy <xpf6677@163.com>
maturin's --find-interpreter means "build for every interpreter it finds",
not "build for the default one". The runner images already carry a range:
the manylinux container ships 3.9-3.15 plus free-threaded and PyPy, the
macOS image carries 3.15. So the explicit 3.15 legs were rebuilding wheels
the default legs had already produced, and macOS produced a byte-identical
cp315 wheel under two artifact names, which collide once the release job
merges artifacts.

Windows is the exception: its image stops at 3.14, so that job now installs
3.15 explicitly. setup-python adds to what maturin discovers rather than
replacing it, so 3.10-3.14 from the image are still built.

The test job keeps its 3.x/3.15 matrix -- there the version selects what is
exercised rather than what is packaged, so both legs are worth running.

Signed-off-by: Peefy <xpf6677@163.com>
maturin-action cross-compiles aarch64 in
ghcr.io/rust-cross/manylinux2014-cross:aarch64, whose /opt/python stops at
CPython 3.14. --find-interpreter therefore reports 3.9-3.14, 3.14t and
PyPy 3.11 there and never offers 3.15, even though the interpreter itself
is present -- naming it explicitly resolves fine. The x86_64 leg is
unaffected: it builds in the native manylinux image, which does ship 3.15.

So after dropping the redundant 3.15 legs, aarch64 Linux shipped no 3.15
wheel at all -- the exact gap #404 asks to close. This restores it for
aarch64 only, where it is the difference between having the wheel and not.

The free-threaded 3.15t build is separate and non-fatal: the cross image
may not carry 3.15t, and that should not take the cp315 wheel down with
it. If it turns out to be present, the step can be made fatal.

Signed-off-by: Peefy <xpf6677@163.com>
The step was non-fatal while it was a probe. CI confirms the cross image
does carry 3.15t -- maturin just never offers it to --find-interpreter --
so the aarch64 artifact now matches x86_64 exactly: cp39, cp310-cp315,
cp314t, cp315t and PyPy 3.11.

Signed-off-by: Peefy <xpf6677@163.com>
protobuf 7.x -- the wheel's only runtime dependency -- requires Python
>=3.10, so a 3.9 build of this wheel can never install: pip resolves
protobuf, finds no compatible version, and refuses. Declaring >=3.9 let
pip believe a 3.9 install was possible and then fail on the dependency
rather than up front.

The declared floor is now the one that actually works, and it is not a
retreat -- the old floor of >=3.7 was already untrue, and the old >=3.9
was untrue for the same reason.

maturin skips interpreters below requires-python during
--find-interpreter rather than failing, so the Linux images' CPython 3.9
is simply not built any more. The published set goes from 31 wheels to 29:
the two cp39 wheels go, and nothing else changes.

Signed-off-by: Peefy <xpf6677@163.com>
@Peefy
Peefy merged commit d536bbf into main Oct 19, 2026
106 of 107 checks passed
@Peefy
Peefy deleted the chore/kcl-0.13.2 branch October 19, 2026 06:30
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