Repository navigation
✨ feat(cli): accept sdist tarball as srcdir argument - #1057
Merged
Merged
Conversation
gaborbernat
force-pushed
the
311
branch
2 times, most recently
from
May 5, 2026 23:46
700e8c1 to
904db90
Compare
Users testing release artifacts had to either extract the sdist by hand or run a separate `pip wheel`/`pyproject-build` against the tarball. The positional `srcdir` now accepts a `.tar.gz` directly, matching the "build a wheel from an sdist" recipe discussed in the issue. Validation rejects archives whose filename does not parse per PEP 625, that fail to open as tar, that contain multiple top-level directories, or that lack a `PKG-INFO`. Validated archives are extracted into a temporary directory and a wheel is built from the extracted source; the wheel lands next to the input archive by default, matching `pip wheel`. The default for archive input is wheel-only rather than sdist+wheel: regenerating an sdist from another sdist is not a defined operation across backends, so `--sdist` against an sdist input is an error. The public Python API stays directory-only; this is a CLI-only affordance.
henryiii
reviewed
May 7, 2026
There was a problem hiding this comment.
Pull request overview
Adds a CLI-only enhancement so python -m build can take a .tar.gz sdist directly as the positional srcdir, enabling “build a wheel from an sdist artifact” workflows without manual extraction or an intermediate pip wheel.
Changes:
- Extend CLI
srcdirparsing to detect.tar.gzinputs, validate the archive as an sdist, extract to a temp dir, and build from the extracted source. - Adjust default behavior for archive inputs (wheel-only; default
--outdirbecomes the archive’s parent directory; reject--sdistwith an actionable error). - Add unit/integration tests and update documentation + changelog to describe the new CLI behavior.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_main.py |
Adds fixtures and coverage for sdist-archive validation/extraction, CLI dispatch behavior, error paths, and an end-to-end wheel build from a generated sdist. |
src/build/__main__.py |
Implements .tar.gz detection, archive validation + extraction helpers, updates CLI defaults/erroring, and reuses extraction logic for build_package_via_sdist. |
docs/tutorial/getting-started.rst |
Documents building a wheel directly from a previously-built sdist. |
docs/reference/cli.rst |
Updates CLI reference prose to note .tar.gz archive input behavior and --outdir/--sdist semantics. |
docs/how-to/basic-usage.rst |
Adds a “Building from a source distribution” section and updates examples to use the new default invocation. |
docs/explanation/how-it-works.rst |
Explains the wheel-only default behavior when the positional argument is an sdist archive. |
docs/changelog/311.feature.rst |
Adds a changelog fragment announcing the new CLI capability. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
henryiii
reviewed
May 7, 2026
Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
henryiii
approved these changes
May 7, 2026
Use the PEP 706 stdlib data filter when present and validate members manually on 3.10.0-3.10.12 / 3.11.0-3.11.4, where the filter was not backported. Rejects device files, paths that escape the destination, and symlinks/hardlinks whose targets resolve outside it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #311.
Anyone testing a release artifact has had to extract the sdist by hand or run a separate
pip wheelagainst the tarball before they could exercise the wheel build path. The positionalsrcdirargument now accepts a.tar.gzsource distribution directly, matching the "build a wheel from an sdist" recipe that came out of the discussion on #311. 📦When
srcdirpoints at a.tar.gz, build first validates it: the filename must parse per PEP 625, the archive must open as tar, contain a single top-level directory, and include aPKG-INFO. The validated archive is extracted into a temporary directory and a wheel is built from the extracted source. The default--outdirfor archive input is the directory containing the archive, matching the conventionpip wheelalready uses, so the wheel lands next to the sdist that produced it. ✨The default for archive input is wheel-only rather than sdist+wheel: regenerating an sdist from another sdist is not a defined operation across backends, and the issue thread converged on rejecting it for now. Passing
--sdistagainst an sdist input is therefore an error with a message pointing back at #311.--metadataand--wheelwork as expected;--config-setting,--no-isolation,--installer, and friends are passed through unchanged. The public Python API (build_package,build_package_via_sdist,ProjectBuilder) keeps its directory-only contract — this is a CLI-only affordance, since broadening the API surface was outside the scope FFY00 had approved on the issue.--wheel--sdist--metadata.tar.gzValidation against real PyPI sdists
Built five sdists pulled from PyPI:
attrs-26.1.0click-8.3.3idna-3.13wheel-0.47.0markupsafe-3.0.3Error paths exercised manually:
--sdist <archive>: parser rejects with the [FR] Implement building wheels from sdist/tarball artifacts #311-pointed error.tar.gz:BuildException: "failed to read source distribution" with tarfile diagnosticsnotavalid.tar.gz): "does not look like a source distribution"--metadata <archive>: PKG-INFO surfaced as JSONSource-built vs sdist-built wheel equivalence
Built the same package both ways and compared:
build(this repo)87361bc1…(byte-identical)attrs-26.1.094d456bc…(byte-identical)For pure-Python wheels with deterministic backends, the sdist path produces a bit-for-bit identical wheel.