Skip to content

Add Python 3.13 support and deploy a compiled wheel to PyPI#680

Merged
erikbern merged 16 commits intospotify:mainfrom
benglewis:add-python-3.13-support
Oct 29, 2025
Merged

Add Python 3.13 support and deploy a compiled wheel to PyPI#680
erikbern merged 16 commits intospotify:mainfrom
benglewis:add-python-3.13-support

Conversation

@benglewis
Copy link
Copy Markdown
Contributor

@benglewis benglewis commented May 4, 2025

Add support for Python 3.13 and configure deployment to PyPI.

  • CI Configuration: Update .github/workflows/ci.yml to include Python version 3.13 in the python-version matrix.
  • Setup.py: Update setup.py to list supported Python versions up to 3.13 in the classifiers list.
  • Tox Configuration: Update tox.ini to include Python 3.13 in the envlist.
  • Publish Workflow: Add a new GitHub Actions workflow in .github/workflows/publish.yml for publishing the package to PyPI.

For more details, open the Copilot Workspace session.

Add support for Python 3.13 and configure deployment to PyPI.

* **CI Configuration**: Update `.github/workflows/ci.yml` to include Python version 3.13 in the `python-version` matrix.
* **Setup.py**: Update `setup.py` to list supported Python versions up to 3.13 in the `classifiers` list.
* **Tox Configuration**: Update `tox.ini` to include Python 3.13 in the `envlist`.
* **Publish Workflow**: Add a new GitHub Actions workflow in `.github/workflows/publish.yml` for publishing the package to PyPI.

---

For more details, open the [Copilot Workspace session](https://copilot-workspace.githubnext.com/spotify/annoy?shareId=XXXX-XXXX-XXXX-XXXX).
@benglewis
Copy link
Copy Markdown
Contributor Author

Side note: I would be happy to implement Trusted Publishing for publishing to PyPI instead if you prefer

@erikbern
Copy link
Copy Markdown
Collaborator

erikbern commented May 4, 2025

Nice! But I don't think the publish step will work unless you have proper credentials set up?

@benglewis
Copy link
Copy Markdown
Contributor Author

@erikbern Correct. It either needs the secret to be configured in GitHub Actions or I can change the code to use the Trusted Publishing option if you configure that on the PyPI side (which is what I recommend and we use since it is more secure - it restricts only GitHub Actions from the GitHub repository to publish to PyPI via OIDC).
Which would you prefer? 🙏

@flying-sheep
Copy link
Copy Markdown

This workflow would make sense for a pure Python project, but not for a compiled one: I don’t think we should go for a single wheel built for x86_64 linux glibc if we can have all the platforms for no cost.

State-of-the-art for compiled wheels published from GitHub is cibuildwheel’s GitHub action, which is very easy to set up!

Please update the workflow for that one, it’ll make the package much more useful!

@benglewis
Copy link
Copy Markdown
Contributor Author

@flying-sheep That makes sense. I'll try to remember to update the next time that I am in front of computer

…g wheels

* Install cibuildwheel instead of setuptools, wheel, and twine
* Build wheels using cibuildwheel and save them to the `dist` folder
* Upload built wheels as artifacts
* Remove `sdist` build step
@benglewis
Copy link
Copy Markdown
Contributor Author

As per @flying-sheep 's suggestion, I have switched the workflow to use cibuildwheel

@flying-sheep
Copy link
Copy Markdown

Wonderful!

@erikbern could we get a release with this soon?
@benglewis did you test this? For my Rust-backed Python packages I usually have to disable 1–3 more exotic platforms, because they don’t build. But maybe that’s not the case for pure C++ code like here.

@benglewis
Copy link
Copy Markdown
Contributor Author

@flying-sheep I did a quick test now in a GitHub Codespace and found a little bug that with the help of ChatGPT I was able to resolve. It looks like builds for all platforms works now.

@erikbern How can I help you get this merged?

Copy link
Copy Markdown
Contributor

@mathematicalmichael mathematicalmichael left a comment

Choose a reason for hiding this comment

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

i've been meaning to get around to this exact contribution. thanks for taking it on! I just tested yours instead.

few things that I think need changing in publish.yml but otherwise the CI process worked for me to generate valid linux wheels.

benglewis and others added 2 commits June 19, 2025 14:28
…ish.yml`


Thank you `mathematicalmichael` for the PR suggestion

Co-authored-by: Michael Pilosov <40366263+mathematicalmichael@users.noreply.github.com>
Thank you to `mathematicalmichael` for the suggestion

Co-authored-by: Michael Pilosov <40366263+mathematicalmichael@users.noreply.github.com>
@mathematicalmichael
Copy link
Copy Markdown
Contributor

mathematicalmichael commented Jun 19, 2025

@benglewis I wanted to give this a proper test with (trusted) publishing, and noticed that while everything built for macos and windows, the final step of "publish package" fails because its only meant to run on linux.

Run >&2 echo This action is only able to run under GNU/Linux environments
  >&2 echo This action is only able to run under GNU/Linux environments
  exit 1
  shell: C:\Program Files\Git\bin\bash.EXE -eEuo pipefail {0}
  env:
    pythonLocation: C:\hostedtoolcache\windows\Python\3.13.3\x64
    PKG_CONFIG_PATH: C:\hostedtoolcache\windows\Python\3.13.3\x64/lib/pkgconfig
    Python_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.13.3\x64
    Python2_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.13.3\x64
    Python3_ROOT_DIR: C:\hostedtoolcache\windows\Python\3.13.3\x64

a fix: move publishing out to a separate step

  publish:
    needs: build
    runs-on: ubuntu-latest
    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: cibw-wheels-*
          path: dist
          merge-multiple: true

      - name: Publish package
        uses: pypa/gh-action-pypi-publish@release/v1
        if: startsWith(github.ref, 'refs/tags/v') && github.event_name == 'push'
        # with:
        #   password: ${{ secrets.PYPI_API_TOKEN }}

though now there's an error due to markup. oh the things testing reveals...
image

PR with fixes: benglewis#1 (including ensuring sdist is uploaded)
workflow file with end-to-end success (uploads all artifacts to pypi: https://github.com/mathematicalmichael/annoy/actions/runs/15769257949/workflow)

@mathematicalmichael
Copy link
Copy Markdown
Contributor

mathematicalmichael commented Jun 30, 2025

quick update:

  • windows build issues handled by removing an image that's currently not working the README.rst anyway
  • windows build issues handled by a bit of regex cleanup of README.rst in setup.py
  • windows build issues handled by switching from codecs to open which handles file encoding better
  • tested linux-aarch64 / arm64 wheels (as well as amd64), added them to linux build options in validated publishing benglewis/annoy#1

demonstration of publishing to pypi under my own namespace as a test:
https://pypi.org/project/annoy-mm/1.17.4rc2/#files
the github action that published it: https://github.com/mathematicalmichael/annoy/actions/runs/15985163036

  • 12 for windows (x86)
  • 12 for macOS (arm)
  • 48 manylinux (24 x86, 24 arm)
  • 24 musllinux (12 x86, 12 arm)

ive checked that I can pip install annoy-mm on python debian and alpine base images on both arm64 and amd64.
literally the only thing I can think of missing is Windows on ARM which... I mean... can we leave that for later?

@ngoldbaum
Copy link
Copy Markdown

Python 3.14 came out this month. Maybe it makes sense to update this to build wheels that are compatible with Python 3.14 as well?

@benglewis
Copy link
Copy Markdown
Contributor Author

@ngoldbaum Once I merge @mathematicalmichael 's changes, then I can update this PR with Python 3.14 and hopefully @erikbern can then merge this :)

@flying-sheep
Copy link
Copy Markdown

Merging this with benglewis#1 (and added 3.14 support) would be awesome, but I think ideally every binary package should instead build ABI3 / stable ABI wheels. Stable ABI wheels can be installed with any Python version ≥ the ABI version you targeted (e.g. <name>-<version>-cp311-abi3-<platform>.whl can be used by any Python version ≥3.11), which has several advantages:

  1. it’s future-compatible (no more updating your package on PyPI just to have wheels for the newest Python version)
  2. you only need to adjust CI when you need some new Python ABI feature, never to include new Python version
  3. you need fewer build jobs / need to build fewer wheels (only one per platform instead of one per platform per python version)

@ngoldbaum
Copy link
Copy Markdown

ngoldbaum commented Oct 23, 2025

I agree abi3 wheels are nice, but one note is that the free-threaded build does not (yet) support the stable ABI. So cp314-cp314t wheels are still needed. IMO supporting the free-threaded build shouldn't be blocked on setting up abi3 wheels, which free-threading suppory can't benefit from.

@benglewis
Copy link
Copy Markdown
Contributor Author

@erikbern Please take a look at this again 🙏 It would be great to put this in

Copy link
Copy Markdown
Collaborator

@erikbern erikbern left a comment

Choose a reason for hiding this comment

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

cool

@erikbern erikbern merged commit 379f744 into spotify:main Oct 29, 2025
21 checks passed
@benglewis benglewis deleted the add-python-3.13-support branch October 29, 2025 14:08
@erikbern
Copy link
Copy Markdown
Collaborator

Thanks!

@ngoldbaum
Copy link
Copy Markdown

I'll poke at opening a followup for 3.14 and 3.14t support.

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.

5 participants