Skip to content

PyPI publishing

The release.yml workflow publishes to PyPI automatically when a v* tag is pushed. Authentication uses OIDC trusted publishing — no API token stored in GitHub secrets.

One-time setup on PyPI

  1. Register at pypi.org and enable 2FA (required since 2024)
  2. Go to Account → Publishing → Add a new pending publisher
  3. Fill in:
  4. PyPI project name: your package name
  5. GitHub owner: your GitHub username or org
  6. Repository name: your repo name
  7. Workflow filename: release.yml
  8. Environment name: (leave blank)
  9. Click Add

That's it. The workflow handles authentication automatically — no token, no secret.

Trigger a release

Releases are triggered automatically by bump.yml on every merge to main. To trigger manually:

cz bump
git push --follow-tags

The release.yml workflow will:

  1. Build wheel + sdist with uv build
  2. Create a GitHub release with the dist files attached
  3. Publish to PyPI with uv publish --trusted-publishing auto

Test PyPI

To publish to test.pypi.org first, add a pending publisher there (same steps). Then temporarily edit release.yml:

- name: Publish to Test PyPI
  run: uv publish --trusted-publishing auto --publish-url https://test.pypi.org/legacy/

Manual publish (local)

Requires a PyPI API token:

uv build
UV_PUBLISH_TOKEN=pypi-... uv publish

Zenodo archiving

If the Zenodo webhook is enabled, every GitHub release automatically creates a Zenodo record. See CITATION.cff for the metadata format. After the first release, copy the concept DOI from Zenodo and add it to CITATION.cff.