Skip to content

Fix pypi deployment - #173

Open
philrhc wants to merge 2 commits into
zeromq:masterfrom
philrhc:fix-pypi-deploy
Open

Fix pypi deployment#173
philrhc wants to merge 2 commits into
zeromq:masterfrom
philrhc:fix-pypi-deploy

Conversation

@philrhc

@philrhc philrhc commented Jul 27, 2026

Copy link
Copy Markdown

Fix PyPI deployment: trusted publishing + packaging metadata

Problem

Deployment has been broken since January 2025 (#171). PyPI is stuck at 0.3.4, while master is at 0.3.5 and tagged v0.3.5. The upload fails with:

ERROR HTTPError: 400 Bad Request from https://upload.pypi.org/legacy/
      User '6r4n' does not have a verified primary email address.

The PYPI_TOKEN repository secret (last updated June 2021) belongs to a single PyPI account that is no longer reachable. Issuing a fresh token would unblock today's release but leaves the same structural problem: the project's ability to publish depends on one individual's account remaining active and reachable.

Changes

1. Trusted publishing instead of a stored token (e34297a)

Trusted publishing is PyPI's recommended mechanism and removes the stored credential entirely. The workflow mints a short-lived OIDC token, which PyPI exchanges for a single-use upload token.

The practical difference: upload rights belong to this repository and workflow, not to any individual's PyPI account. Any maintainer who can trigger the workflow can cut a release, and there is no long-lived credential to rotate, leak, or lose when a maintainer moves on. That directly addresses the failure mode in #171 rather than deferring it.

The diff follows the canonical PyPA example:

  • adds permissions: id-token: write to the publish job
  • drops the user / password inputs — no secret is referenced anywhere in the workflow after this
  • drops actions/checkout from publish, which never used the source tree
  • pins pypa/gh-action-pypi-publish from @master to @release/v1@master is a mutable branch, so the previous form ran whatever was on that branch at the time

MAINTENANCE.md is updated to match, since it currently documents the token mechanism this removes.

2. Packaging metadata fixes (2809e3d)

  • extra_requiresextras_require. extra_requires is not a setuptools keyword, so it was silently ignored — the deploy and test extras documented in MAINTENANCE.md did not actually exist. Confirmed fixed: the built sdist now declares them.
  • Added long_description. Without it the PyPI project page renders empty. README.md is already shipped via MANIFEST.in, so it is read in and declared as markdown.

Required on the PyPI side

The workflow cannot upload until a matching publisher exists on the project (Manage → Publishing → GitHub):

Field Value
Owner zeromq
Repository pyre
Workflow deploy.yml
Environment (blank)

I have owner access on the PyPI project and will configure this. Adding a GitHub Environment (e.g. pypi) as an extra approval gate would be a good hardening follow-up, but it needs repository admin.

Note: merging this will not publish anything

bump_version.yml pushes its tag using secrets.GITHUB_TOKEN (lines 97, 105), and GitHub deliberately does not trigger workflows from GITHUB_TOKEN pushes. So merging bumps the version and pushes a tag, but deploy.yml will not fire on its own — the release has to be dispatched manually from the Actions tab. Flagging this so nobody expects a merge to ship a release.

Open question for reviewers

Whether to publish 0.3.5 (matching the existing v0.3.5 tag, which never made it to PyPI) or let the merge bump to 0.3.6. I have no strong preference; 0.3.6 has the mild advantage of including the metadata fixes above, so the first successful release renders a proper project page. Happy to go either way.

For context on why it is worth unblocking: the 15 commits since 0.3.4 are mostly CI and Python version upgrades, but they include set_interface being implemented (e782257), which is what #132 asks for. Users currently have no released version containing it.

Verification

Built and checked locally from this branch:

  • twine checkPASSED
  • Clean-venv install from the sdist — imports fine, __version__ == 0.3.5
  • requires.txt in the sdist now lists the [deploy] and [test] extras (confirming the typo fix)
  • PKG-INFO now embeds the README (247 lines, previously ~12)
  • deploy.yml parses; publish job has permissions: {id-token: write} and zero secrets. references

Nothing here changes library code — no behavioural change for users.

Follow-ups, not in this PR

  • MAINTENANCE.md "Note 1" still describes PERSONAL_ACCESS_TOKEN as required for the version bump, but bump_version.yml has since moved to GITHUB_TOKEN. The docs and the workflow disagree; worth reconciling separately.
  • Publishing pure-Python wheels alongside the sdist. MAINTENANCE.md justifies sdist-only by Python 2 support, which no longer applies.

Refs #171 — deliberately not using a closing keyword, since merging this does not itself publish anything. Better to close #171 once a release actually lands on PyPI.

Phil Cummins and others added 2 commits July 27, 2026 18:02
Releases have been blocked since Jan 2025 (zeromq#171): the PYPI_TOKEN secret
belongs to a single PyPI account that is no longer reachable, so uploads
fail with "does not have a verified primary email address". Rotating the
token only moves the problem to whoever holds the next one.

Trusted publishing removes the stored credential entirely. The workflow
mints a short-lived OIDC token which PyPI exchanges for a single-use
upload token, so upload rights belong to this repository and workflow
rather than to an individual's account. Any maintainer able to trigger
the workflow can cut a release, and there is nothing to rotate or lose
when a maintainer moves on.

Also pins pypa/gh-action-pypi-publish from @master to @release/v1, and
drops the checkout step from the publish job, which never used the
source tree.

Requires a matching publisher on the PyPI project (Manage -> Publishing):
owner zeromq, repository pyre, workflow deploy.yml.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gLbEtgftbkCLmbZwSCsSp
extra_requires is not a setuptools keyword, so it was silently ignored
and the 'deploy' and 'test' extras documented in MAINTENANCE.md did not
actually exist. Renaming to extras_require registers them.

Without long_description the PyPI project page renders empty. README.md
is already shipped via MANIFEST.in, so read it in and declare it as
markdown.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019gLbEtgftbkCLmbZwSCsSp
@philrhc philrhc mentioned this pull request Jul 27, 2026
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.

Deploy to PyPi fails

1 participant