Skip to content

sqlalchemy: add build-sqlalchemy.yml for riscv64 wheels - #310

Open
luhenry wants to merge 2 commits into
mainfrom
sqlalchemy
Open

sqlalchemy: add build-sqlalchemy.yml for riscv64 wheels#310
luhenry wants to merge 2 commits into
mainfrom
sqlalchemy

Conversation

@luhenry

@luhenry luhenry commented Aug 24, 2026

Copy link
Copy Markdown
Member

What

Adds .github/workflows/build-sqlalchemy.yml to build riscv64 wheels for SQLAlchemy 2.0.52 and publish them to pypi.riseproject.dev.

SQLAlchemy is pure-Python with optional Cython speedups (5 .pyx modules under lib/sqlalchemy/cyextension/). PyPI already ships the py3-none-any wheel plus a per-interpreter compiled wheel for every arch except riscv64 — so the value we add is exactly those compiled riscv64 wheels.

How

Build shape: sdist → bdist, modelled on upstream's create-wheels.yaml.

  • build_sdist (ubuntu-latest): builds the sdist from the upstream rel_2_0_52 checkout. The sdist bundles the .pyx sources, the whole test/ tree, and upstream's [tool.cibuildwheel] config — so we inherit upstream's exact test-requires + test-command (the "easy inverse" of CLAUDE.md gotcha 6).
  • build_wheels (ubuntu-24.04-riscv): one cibuildwheel run per interpreter over the matrix [cp312, cp313, cp314, cp314t]. The cyextension is a plain per-interpreter C extension (not abi3), so each CPython needs its own wheel — same matrix as cffi/numpy/zstandard. cibuildwheel consumes the sdist tarball directly.
  • publish: shared publish-wheels action (dry-runs off main).

Two package-specific subtleties (both phase-scoped env vars)

  1. .dev0 version trap — SQLAlchemy keeps tag_build = dev in setup.cfg on release branches, so a plain python -m build yields sqlalchemy-2.0.52.dev0. Upstream strips that line before building (the released PyPI sdist has it blank); we do the same via sed -i '/tag_build = dev/d' setup.cfg, or the wheel version stops matching PyPI and the docs YAML / patches path (gotcha 18).

  2. REQUIRE_SQLALCHEMY_CEXT=1 (build) + PYTHONNOUSERSITE=1 (test) — the extensions are optional=not REQUIRE_SQLALCHEMY_CEXT, so a Cython failure would silently ship a pure-Python wheel mislabeled manylinux_riscv64; REQUIRE makes that a hard failure. Separately, upstream's python -s (no-user-site) keeps test/conftest.py from injecting the source tree ahead of the installed wheel — but the -s flag doesn't propagate to pytest-xdist (-n4) workers, which respawn with no_user_site=0 and import the source tree anyway (crashing under REQUIRE via SQLAlchemy's __ensure_cext plugin). Setting no-user-site as the PYTHONNOUSERSITE env var — which xdist inherits into workers — makes each worker test the installed compiled wheel. Test-phase-scoped so it can't affect the build (gotcha 12).

Validation

  • YAML parses; actionlint clean (only the expected ubuntu-24.04-riscv unknown-label warning).
  • Built the cp312 riscv64 wheel end-to-end under QEMU on an aarch64 host: all 5 compiled .so cyextension modules present, clean 2.0.52 version, tag cp312-cp312-manylinux_2_39_riscv64.
  • Ran the inherited test-command under QEMU with the fix: 4 xdist workers boot and the suite passes (no failures, expected DB-backend skips only) against the compiled wheel.

CI on the native riscv64 runner is the final gate for all four interpreters.

SQLAlchemy is pure-Python with *optional* Cython speedups (5 .pyx modules
under lib/sqlalchemy/cyextension/). PyPI ships the py3-none-any wheel plus a
per-interpreter compiled wheel for every arch except riscv64 - so the value
we add here is exactly those compiled riscv64 wheels.

Build shape (sdist -> bdist):
- build_sdist (ubuntu-latest): build the sdist ourselves from the upstream
  rel_2_0_52 checkout. SQLAlchemy keeps `tag_build = dev` in setup.cfg on
  release branches, so a plain `python -m build` yields sqlalchemy-2.0.52.dev0
  and every wheel built from it inherits the .dev0 suffix. Upstream's release
  job strips that line before building (the released PyPI sdist has it blank);
  we do the same, or the wheel version stops matching PyPI and the docs
  YAML / patches path. The sdist bundles the .pyx sources, the whole test/
  tree, and upstream's [tool.cibuildwheel] config.
- build_wheels (ubuntu-24.04-riscv): one cibuildwheel run per interpreter
  (cp312/cp313/cp314/cp314t - the cyextension is a plain per-interpreter C
  extension, not abi3). cibuildwheel consumes the sdist tarball directly, so
  {project} in the inherited test-command resolves to the extracted tree that
  bundles both pyproject.toml and test/. We inherit upstream's exact
  test-requires + test-command and add only the riscv overrides.

Two package-specific subtleties, both phase-scoped env vars:
- REQUIRE_SQLALCHEMY_CEXT=1 (build phase): the extensions are declared
  optional=not REQUIRE_SQLALCHEMY_CEXT, so a Cython/compile failure would be
  swallowed and setuptools would ship a *pure-Python* wheel still tagged
  manylinux_riscv64 - a broken artifact that looks fine. REQUIRE turns any
  extension-build failure into a hard failure.
- PYTHONNOUSERSITE=1 (test phase only): upstream's test-command uses
  `python -s` so test/conftest.py doesn't inject {project}/lib ahead of the
  installed wheel (which would import the pure-Python source, not the compiled
  extension). But the -s *flag* does not propagate to pytest-xdist (-n4)
  workers - they respawn with no_user_site=0 and import the source tree anyway,
  and SQLAlchemy's own __ensure_cext plugin (active under REQUIRE) then
  hard-fails every worker. Setting no-user-site as the PYTHONNOUSERSITE env
  var, which xdist inherits into workers, makes each worker test the installed
  compiled wheel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@luhenry
luhenry requested review from justeph and threexc August 24, 2026 13:28
Per repo guidance (PR #308 review): workflows are read as reference, so
reserve comments for the non-obvious and cut per-step narration. The full
rationale lives in the commit message and CLAUDE.md gotchas 20-22.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@luhenry luhenry linked an issue Aug 24, 2026 that may be closed by this pull request
@luhenry luhenry removed a link to an issue Aug 24, 2026
@luhenry luhenry linked an issue Aug 24, 2026 that may be closed by this pull request
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.

sqlalchemy riscv64 support

2 participants