Skip to content

Commit dd467f9

Browse files
unamedkrclaude
andcommitted
pypi: ship quantcpp 0.8.0 — sdist + cibuildwheel + Trusted Publishing
End-user installs work via: pip install quantcpp Changes: - bindings/python/setup.py: bundle quant.h into quantcpp/_quant.h at sdist time so installs from a published tarball don't need ../../quant.h. Force platform-tagged wheel via _BinaryDistribution.has_ext_modules. - bindings/python/pyproject.toml: bump 0.5.0 → 0.8.0, drop deprecated license classifier (PEP 639), add cibuildwheel config for Linux x86_64/ aarch64, macOS Intel+arm64, Windows AMD64. requires-python >= 3.9. - bindings/python/quantcpp/__init__.py: read __version__ from importlib.metadata (single source of truth = pyproject.toml). - bindings/python/MANIFEST.in: include quantcpp/_quant.h in sdist. - bindings/python/.gitignore: never commit bundled header / built libs. - .github/workflows/publish.yml: cibuildwheel matrix + sdist + OIDC Trusted Publishing to PyPI on tag push (no API token needed). Manual workflow_dispatch supports TestPyPI as well. Local verification (clean venv, no source tree): pip install dist/quantcpp-0.8.0.tar.gz → libquant.dylib auto-builds pip install dist/quantcpp-...-arm64.whl → libquant.dylib pre-built python -c "import quantcpp; from quantcpp._binding import get_lib; print(get_lib().quant_version().decode())" → "0.1.0 (quant.h single-header)" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 04b08d3 commit dd467f9

7 files changed

Lines changed: 284 additions & 32 deletions

File tree

.github/workflows/publish.yml

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
name: Publish quantcpp to PyPI
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
- 'pypi-v*'
8+
workflow_dispatch:
9+
inputs:
10+
target:
11+
description: 'Where to publish'
12+
required: true
13+
default: 'testpypi'
14+
type: choice
15+
options:
16+
- testpypi
17+
- pypi
18+
19+
jobs:
20+
# ---------------------------------------------------------------------
21+
# Build platform-specific wheels via cibuildwheel
22+
# ---------------------------------------------------------------------
23+
build_wheels:
24+
name: Wheels on ${{ matrix.os }} (${{ matrix.arch }})
25+
runs-on: ${{ matrix.os }}
26+
strategy:
27+
fail-fast: false
28+
matrix:
29+
include:
30+
- os: ubuntu-latest
31+
arch: x86_64
32+
- os: ubuntu-latest
33+
arch: aarch64
34+
- os: macos-13 # Intel runner
35+
arch: x86_64
36+
- os: macos-14 # Apple Silicon runner
37+
arch: arm64
38+
- os: windows-latest
39+
arch: AMD64
40+
41+
steps:
42+
- name: Checkout
43+
uses: actions/checkout@v4
44+
with:
45+
fetch-depth: 0
46+
47+
- name: Set up QEMU (linux aarch64 emulation)
48+
if: matrix.os == 'ubuntu-latest' && matrix.arch == 'aarch64'
49+
uses: docker/setup-qemu-action@v3
50+
with:
51+
platforms: arm64
52+
53+
- name: Build wheels
54+
uses: pypa/cibuildwheel@v2.21.3
55+
with:
56+
package-dir: bindings/python
57+
output-dir: wheelhouse
58+
env:
59+
CIBW_ARCHS: ${{ matrix.arch }}
60+
61+
- name: Upload wheels
62+
uses: actions/upload-artifact@v4
63+
with:
64+
name: wheels-${{ matrix.os }}-${{ matrix.arch }}
65+
path: ./wheelhouse/*.whl
66+
if-no-files-found: error
67+
68+
# ---------------------------------------------------------------------
69+
# Build the source distribution
70+
# ---------------------------------------------------------------------
71+
build_sdist:
72+
name: Source distribution
73+
runs-on: ubuntu-latest
74+
steps:
75+
- uses: actions/checkout@v4
76+
with:
77+
fetch-depth: 0
78+
79+
- uses: actions/setup-python@v5
80+
with:
81+
python-version: '3.11'
82+
83+
- name: Build sdist
84+
run: |
85+
cd bindings/python
86+
python -m pip install --upgrade pip build
87+
python -m build --sdist
88+
89+
- name: Smoke-test sdist install (clean venv)
90+
run: |
91+
python -m venv /tmp/sdist-test
92+
/tmp/sdist-test/bin/pip install bindings/python/dist/quantcpp-*.tar.gz
93+
cd /tmp
94+
/tmp/sdist-test/bin/python -c "import quantcpp; from quantcpp._binding import get_lib; print('sdist OK:', quantcpp.__version__, get_lib().quant_version().decode())"
95+
96+
- uses: actions/upload-artifact@v4
97+
with:
98+
name: sdist
99+
path: bindings/python/dist/*.tar.gz
100+
if-no-files-found: error
101+
102+
# ---------------------------------------------------------------------
103+
# Publish — Trusted Publishing (OIDC), no API token needed
104+
# ---------------------------------------------------------------------
105+
publish_testpypi:
106+
name: Publish to TestPyPI
107+
needs: [build_wheels, build_sdist]
108+
runs-on: ubuntu-latest
109+
if: github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'testpypi'
110+
environment:
111+
name: testpypi
112+
url: https://test.pypi.org/p/quantcpp
113+
permissions:
114+
id-token: write
115+
steps:
116+
- uses: actions/download-artifact@v4
117+
with:
118+
path: dist
119+
merge-multiple: true
120+
- name: List artifacts
121+
run: ls -la dist/
122+
- uses: pypa/gh-action-pypi-publish@release/v1
123+
with:
124+
repository-url: https://test.pypi.org/legacy/
125+
skip-existing: true
126+
127+
publish_pypi:
128+
name: Publish to PyPI
129+
needs: [build_wheels, build_sdist]
130+
runs-on: ubuntu-latest
131+
# Auto-publish on tag push, OR manual dispatch with target=pypi
132+
if: |
133+
startsWith(github.ref, 'refs/tags/') ||
134+
(github.event_name == 'workflow_dispatch' && github.event.inputs.target == 'pypi')
135+
environment:
136+
name: pypi
137+
url: https://pypi.org/p/quantcpp
138+
permissions:
139+
id-token: write
140+
steps:
141+
- uses: actions/download-artifact@v4
142+
with:
143+
path: dist
144+
merge-multiple: true
145+
- name: List artifacts
146+
run: ls -la dist/
147+
- uses: pypa/gh-action-pypi-publish@release/v1

bindings/python/.gitignore

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Build artifacts
2+
build/
3+
dist/
4+
wheelhouse/
5+
*.egg-info/
6+
__pycache__/
7+
*.pyc
8+
9+
# Bundled at build time from ../../quant.h — never commit
10+
quantcpp/_quant.h
11+
quantcpp/_quant_impl.c
12+
13+
# Compiled shared libraries — never commit
14+
quantcpp/libquant.so
15+
quantcpp/libquant.dylib
16+
quantcpp/quant.dll

bindings/python/MANIFEST.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
include README.md
2+
include pyproject.toml
3+
include setup.py
4+
include quantcpp/_quant.h
5+
recursive-include quantcpp *.py *.h

bindings/python/README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,17 @@ Python bindings for [quant.cpp](https://github.com/quantumaikr/quant.cpp) -- a m
55
## Installation
66

77
```bash
8-
cd quant.cpp/bindings/python
9-
pip install .
8+
pip install quantcpp
109
```
1110

12-
This compiles `quant.h` into a shared library automatically using your system C compiler (`cc`, `gcc`, or `clang`). No external dependencies required.
11+
Pre-built wheels are published for Linux (x86_64, aarch64), macOS (Intel + Apple Silicon), and Windows (x64). On other platforms pip falls back to the source distribution and compiles `quant.h` automatically using your system C compiler — no external dependencies.
1312

14-
For development (editable install):
13+
### From source (dev tree)
1514

1615
```bash
17-
pip install -e .
16+
cd quant.cpp/bindings/python
17+
pip install . # build + install
18+
pip install -e . # editable / development install
1819
```
1920

2021
To point at a pre-built library instead:

bindings/python/pyproject.toml

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
[build-system]
2-
requires = ["setuptools>=64"]
2+
requires = ["setuptools>=64", "wheel"]
33
build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "quantcpp"
7-
version = "0.5.0"
8-
description = "Python bindings for quant.cpp -- minimal LLM inference with KV compression"
7+
version = "0.8.0"
8+
description = "Single-header LLM inference engine with KV cache compression (7× compression at fp32 parity)"
99
readme = "README.md"
1010
license = "Apache-2.0"
11-
requires-python = ">=3.8"
11+
requires-python = ">=3.9"
1212
authors = [
13-
{ name = "quant.cpp contributors" },
13+
{ name = "quantumaikr", email = "noreply@quantumaikr.com" },
14+
]
15+
keywords = [
16+
"llm", "inference", "quantization", "kv-cache",
17+
"compression", "gguf", "embedded", "single-header",
1418
]
15-
keywords = ["llm", "inference", "quantization", "kv-cache", "compression", "gguf"]
1619
classifiers = [
1720
"Development Status :: 4 - Beta",
1821
"Intended Audience :: Developers",
1922
"Intended Audience :: Science/Research",
23+
"Programming Language :: C",
2024
"Programming Language :: Python :: 3",
21-
"Programming Language :: Python :: 3.8",
2225
"Programming Language :: Python :: 3.9",
2326
"Programming Language :: Python :: 3.10",
2427
"Programming Language :: Python :: 3.11",
@@ -27,15 +30,46 @@ classifiers = [
2730
"Topic :: Scientific/Engineering :: Artificial Intelligence",
2831
"Operating System :: POSIX :: Linux",
2932
"Operating System :: MacOS",
33+
"Operating System :: Microsoft :: Windows",
3034
]
3135

3236
[project.urls]
33-
Homepage = "https://github.com/quantumaikr/quant.cpp"
34-
Source = "https://github.com/quantumaikr/quant.cpp"
35-
Issues = "https://github.com/quantumaikr/quant.cpp/issues"
37+
Homepage = "https://github.com/quantumaikr/quant.cpp"
38+
Documentation = "https://github.com/quantumaikr/quant.cpp#readme"
39+
Source = "https://github.com/quantumaikr/quant.cpp"
40+
Issues = "https://github.com/quantumaikr/quant.cpp/issues"
41+
Changelog = "https://github.com/quantumaikr/quant.cpp/blob/main/CHANGELOG.md"
3642

3743
[project.optional-dependencies]
38-
dev = ["pytest>=7.0"]
44+
dev = ["pytest>=7.0", "build", "twine"]
3945

4046
[tool.setuptools.packages.find]
4147
include = ["quantcpp*"]
48+
49+
[tool.setuptools.package-data]
50+
quantcpp = ["_quant.h", "*.so", "*.dylib", "*.dll"]
51+
52+
# ---------------------------------------------------------------------------
53+
# cibuildwheel — pre-built binary wheels for PyPI
54+
# ---------------------------------------------------------------------------
55+
[tool.cibuildwheel]
56+
build = "cp39-* cp310-* cp311-* cp312-* cp313-*"
57+
skip = "*-musllinux_i686 *-manylinux_i686 pp*"
58+
59+
# Verify the bundled header is in place before building
60+
before-build = "python -c \"import shutil, os; src='../../quant.h'; dst='quantcpp/_quant.h'; (os.path.exists(src) and shutil.copyfile(src, dst)) or (os.path.exists(dst) or (_ for _ in ()).throw(FileNotFoundError(dst)))\""
61+
62+
# Smoke-test the built wheel before publishing
63+
test-command = "python -c \"import quantcpp; print('quantcpp', quantcpp.__version__)\""
64+
65+
[tool.cibuildwheel.linux]
66+
archs = ["x86_64", "aarch64"]
67+
manylinux-x86_64-image = "manylinux2014"
68+
manylinux-aarch64-image = "manylinux2014"
69+
70+
[tool.cibuildwheel.macos]
71+
archs = ["x86_64", "arm64"]
72+
environment = { MACOSX_DEPLOYMENT_TARGET = "11.0" }
73+
74+
[tool.cibuildwheel.windows]
75+
archs = ["AMD64"]

bindings/python/quantcpp/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
print(m.ask("Explain gravity"))
1818
"""
1919

20-
__version__ = "0.5.0"
20+
try:
21+
from importlib.metadata import version as _pkg_version
22+
__version__ = _pkg_version("quantcpp")
23+
except Exception:
24+
__version__ = "0.8.0" # fallback for editable / source-tree imports
2125

2226
import os
2327
import threading

0 commit comments

Comments
 (0)