ci(py-315): withhold cp315 wheels from the PyPI upload - #19880
ci(py-315): withhold cp315 wheels from the PyPI upload#19880vlad-scherbich wants to merge 2 commits into
Conversation
The release_pypi job uploaded every artifact matching pywheels/ddtrace-*, which includes the cp315 wheels that "build linux" produces for internal S3 and the private prerelease index. Nothing prevented a Python 3.15 artifact from reaching PyPI other than the Requires-Python bound baked into the wheel metadata, which is a property of the artifact rather than a release guard. Filter cp315 out of the upload list and refuse to upload at all if the resulting list is empty, so a broken filter fails the job instead of silently uploading everything or nothing. twine check --strict still runs over the whole of pywheels/, so cp315 artifacts remain validated. The S3 and adms prerelease paths are unchanged: those are the intended consumers.
Circular import analysis
|
|
BenchmarksBenchmark execution time: 2026-08-27 11:39:00 Comparing candidate commit 42ff65d in PR branch Found 0 performance improvements and 5 performance regressions! Performance is the same for 581 metrics, 10 unstable metrics, 2 known flaky benchmarks, 16 flaky benchmarks without significant changes.
|
…is uploaded The comment used DEV(py-315), a marker form this repo has never used; main has three TODO(py-315) anchors and only a bare "# DEV:" convention. Build the upload list before "twine check" so both steps see the same distributions. --strict promotes warnings to errors, so checking the unfiltered directory let a malformed cp315 wheel from an allow_failure build fail a release whose supported wheels were all fine. release_pypi_prod depends on "ddtrace package", which carries no serverless artifacts, so the narrowed check loses no coverage beyond cp315.
Codeowners resolved asResolved from the full PR diff against |
Dependency direction analysis
|
There was a problem hiding this comment.
Pull request overview
Adjusts the GitLab release pipeline so release_pypi_prod no longer uploads cp315 wheels to PyPI, preventing publication of wheels for an unsupported (and potentially ABI-incompatible) Python 3.15 target while leaving internal distribution paths unchanged.
Changes:
- Builds an explicit upload list from
pywheels/ddtrace-*and filters out any*cp315*artifacts before bothtwine check --strictandtwine upload. - Fails the release job early with a clear error if filtering results in an empty upload set, and logs the exact distributions that will be published.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Description
release_pypi_produploads with the unfiltered globpywheels/ddtrace-*, so every cp315 wheel the pipeline builds is published to PyPI. This replaces the glob with a POSIX-shell loop that skips*cp315*, so cp315 wheels stop reaching PyPI. The sdist and every other wheel are unaffected.This is not hypothetical. cp315 wheels have been built since
cp315-cp315joined the matrix in.gitlab/package.yml(allow_failure, per the TODO citing #17849), and 122 of them are on PyPI today, across all 31 releases from 4.11.0rc1 through 4.14.0. They are ABI-broken rather than merely untested: CPython inserteduintptr_t last_profiled_frame_seqintoPyThreadStateimmediately abovec_profilefuncbetween thev3.15.0b1andv3.15.0b4tags, shifting every subsequent field, and these wheels were compiled against a pre-shift beta.requires-python = ">=3.9,<3.15"is not a sufficient guard on its own. pip honours it — pip 26.2.1 on a 3.15.0a6 environment refusesddtrace==4.14.0rc4outright — but uv 0.10.9 resolves and installs the cp315 wheel into that same environment with no error or warning, even though the wheel's ownMETADATAsaysRequires-Python: <3.15,>=3.9. Withholding the upload is the guard that holds for every installer.Deliberately unchanged: the S3 upload (
.upload_wheels_base) and the private prerelease index (.patch_wheel_versions_base,datadog/pypi-private-prereleases) still receive cp315, so internal distribution and custom customer builds keep working. Only PyPI is filtered.twine check --strictmoves frompywheels/*onto the same filtered list, so a malformed cp315 wheel from anallow_failurebuild cannot fail a release whose supported wheels are all fine. That loses no coverage:release_pypi_proddepends on"ddtrace package", which carries no serverless artifacts, so the two globs were already the same set. The filter is markedTODO(py-315)and comes out when 3.15 becomes a supported target.Testing
The loop is POSIX shell inside
release_pypi_prod, which runs only on release tags, so it was exercised by hand against a fixturepywheels/of cp313 and cp314 manylinux/musllinux wheels, cp315 manylinux/musllinux wheels, and an sdist. cp315 wheels are skipped and everything else retained. It fails closed: when filtering leaves nothing, the job exits 1 with[ERROR] no PyPI-eligible distributions found in pywheels/ -- refusing to upload, instead of lettingtwinefail with an argparse usage error that never says why the list was empty. The list is printed before uploading, so the job log records what was published.Risks
Low, and bounded to the release job. cp315 wheels stop appearing on PyPI for new releases; nothing changes for supported interpreters.
Out of scope: the 122 already-published files, where yank vs. delete is a release-engineering decision (PEP 592 yanking may be per-release rather than per-file, and deletion is irreversible); making
.gitlab/validate-ddtrace-package.pyfail on unrecognised interpreter tags rather than warn, which is why itsPYTHON_TAGSstopping atcp314let the gate pass; and #19861, which separately enables cp315 manylinux wheel builds.Additional Notes
changelog/no-changelog: CI-only, with no user-facing behaviour change on any supported interpreter. The title isci(rather thanfix/feat, soscripts/check-releasenoteshonours the label.