Skip to content

Build backend: Add direct builds to the resolver and installer #9621

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 4, 2024

Conversation

konstin
Copy link
Member

@konstin konstin commented Dec 3, 2024

This is like #9556, but at the level of all other builds, including the resolver and installer. Going through PEP 517 to build a package is slow, so when building a package with the uv build backend, we can call into the uv build backend directly instead: No temporary virtual env, no temp venv sync, no python subprocess calls, no uv subprocess calls.

This fast path is gated through preview. Since the uv wheel is not available at test time, I've manually confirmed the feature by comparing uv venv && cargo run pip install . -v --preview --reinstall . and uv venv && cargo run pip install . -v --reinstall .. When hacking the preview so that the python uv build backend works without the setting the direct build also (wheel built with maturin build --profile profiling), we can see the perfomance difference:

$ hyperfine --prepare "uv venv" --warmup 3 \
    "UV_PREVIEW=1 target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --preview" \
    "target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --find-links target/wheels/"
Benchmark 1: UV_PREVIEW=1 target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --preview
  Time (mean ± σ):      33.1 ms ±   2.5 ms    [User: 25.7 ms, System: 13.0 ms]
  Range (min … max):    29.8 ms …  47.3 ms    73 runs
 
Benchmark 2: target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --find-links target/wheels/
  Time (mean ± σ):     115.1 ms ±   4.3 ms    [User: 54.0 ms, System: 27.0 ms]
  Range (min … max):   109.2 ms … 123.8 ms    25 runs
 
Summary
  UV_PREVIEW=1 target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --preview ran
    3.48 ± 0.29 times faster than target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --find-links target/wheels/

Do we need a global option to disable the fast path? There is one for uv build because --force-pep517 moves uv build much closer to a pip install from source that a user of a library would experience (See discussion at #9610), but uv overall doesn't really make guarantees around the build env of dependencies, so I consider the direct build a valid option.

Best reviewed commit-by-commit, only the last commit is the actual implementation, while the preview mode introduction is just a refactoring touching too many files.

@konstin konstin added the preview Experimental behavior label Dec 3, 2024
@konstin konstin requested a review from BurntSushi December 3, 2024 21:44
@konstin konstin force-pushed the konsti/build-backend-frontend-error-handling branch from d006891 to 4d7f4fd Compare December 4, 2024 08:55
Base automatically changed from konsti/build-backend-frontend-error-handling to main December 4, 2024 09:04
We want to add direct builds that don't go through PEP 517 to the resolver and installer, too, after they now exist in `uv build`. These need to be hidden behind preview for now. For that, we need to thread the preview mode through to the build dispatch.
Move check_direct_build to uv-build-backend and add a parameter for logging. When using  this function as part of the resolver or installer, the log messages will otherwise be lacking context.
This is like #9556, but at the level of all other builds, including the resolver and installer. Going through PEP 517 to build a package is slow, so when building a package with the uv build backend, we can call into the uv build backend directly instead: No temporary virtual env, no temp venv sync, no python subprocess calls, no uv subprocess calls.

This fast path is gated through preview. Since the uv wheel is not available at test time, I've manually confirmed the feature by comparing `uv venv && cargo run pip install . -v --preview --reinstall .` and `uv venv && cargo run pip install . -v --reinstall .`.

Do we need a global option to disable the fast path? There is one for `uv build` because `--force-pep517` moves `uv build` much closer to a `pip install` from source that a user of a library would experience.See discussion at #9610 (comment)
@konstin konstin force-pushed the konsti/build-backend-resolver-direct-build2 branch from b927433 to 87823cf Compare December 4, 2024 09:05
Copy link
Member

@BurntSushi BurntSushi left a comment

Choose a reason for hiding this comment

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

Nice, looks great!

subdirectory: Option<&'data Path>,
output_dir: &'data Path,
build_kind: BuildKind,
version_id: Option<String>,
Copy link
Member

Choose a reason for hiding this comment

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

Should this be a Option<&str>?

Copy link
Member

Choose a reason for hiding this comment

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

I see. It would be kinda annoying, but doable. I don't feel strongly.

Copy link
Member Author

Choose a reason for hiding this comment

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

It's more converting back and forth now, but it's also move consistent with the rest of the codebase.

output_dir: &'data Path,
build_kind: BuildKind,
version_id: Option<String>,
) -> Result<Option<String>> {
Copy link
Member

Choose a reason for hiding this comment

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

What is being returned here? And should it be a PathBuf?

Copy link
Member

Choose a reason for hiding this comment

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

Oh okay, it's documented below on the trait.

Copy link
Member Author

Choose a reason for hiding this comment

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

This initially happened because PEP 517 says that the build backend returns the filename as last line, and we passed that around as a string.

Copy link
Member Author

Choose a reason for hiding this comment

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

More specifically, the location on disk may not be normalized the same as WheelFilename is, so for non-uv build backends we have to pass out a string and only parse later, i added comments.

/// Build by calling directly into the uv build backend without PEP 517, if possible.
///
/// Checks if the source tree uses uv as build backend. If not, it returns `Ok(None)`, otherwise
/// it builds and returns the name of the built file.
Copy link
Member

Choose a reason for hiding this comment

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

What does it return in the case of an editable?

Copy link
Member Author

Choose a reason for hiding this comment

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

At this stage, the editable is a wheel that is indistinguishable from a regular wheel, except it contains a .pth file instead of the actual sources (but we still unpack it the regular way) and we're not allowed to cache it.

@BurntSushi
Copy link
Member

Were you able to find any benchmarks showing an improvement? I guess they would be cold runs right?

@konstin
Copy link
Member Author

konstin commented Dec 4, 2024

With hacking the preview so that the python uv build backend works without the setting the direct build also (wheel built with maturin build --profile profiling):

$ hyperfine --prepare "uv venv" --warmup 3 \
    "UV_PREVIEW=1 target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --preview" \
    "target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --find-links target/wheels/"
Benchmark 1: UV_PREVIEW=1 target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --preview
  Time (mean ± σ):      33.1 ms ±   2.5 ms    [User: 25.7 ms, System: 13.0 ms]
  Range (min … max):    29.8 ms …  47.3 ms    73 runs
 
Benchmark 2: target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --find-links target/wheels/
  Time (mean ± σ):     115.1 ms ±   4.3 ms    [User: 54.0 ms, System: 27.0 ms]
  Range (min … max):   109.2 ms … 123.8 ms    25 runs
 
Summary
  UV_PREVIEW=1 target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --preview ran
    3.48 ± 0.29 times faster than target/profiling/uv pip install --no-deps --reinstall scripts/packages/built-by-uv --find-links target/wheels/

@konstin konstin enabled auto-merge (squash) December 4, 2024 15:24
@konstin konstin disabled auto-merge December 4, 2024 15:26
@konstin konstin enabled auto-merge (squash) December 4, 2024 15:47
@konstin konstin merged commit 6ed6fc1 into main Dec 4, 2024
64 checks passed
@konstin konstin deleted the konsti/build-backend-resolver-direct-build2 branch December 4, 2024 15:57
@konstin konstin mentioned this pull request Dec 4, 2024
31 tasks
tmeijn pushed a commit to tmeijn/dotfiles that referenced this pull request Dec 9, 2024
This MR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [astral-sh/uv](https://github.com/astral-sh/uv) | patch | `0.5.6` -> `0.5.7` |

MR created with the help of [el-capitano/tools/renovate-bot](https://gitlab.com/el-capitano/tools/renovate-bot).

**Proposed changes to behavior should be submitted there as MRs.**

---

### Release Notes

<details>
<summary>astral-sh/uv (astral-sh/uv)</summary>

### [`v0.5.7`](https://github.com/astral-sh/uv/blob/HEAD/CHANGELOG.md#057)

[Compare Source](astral-sh/uv@0.5.6...0.5.7)

##### Enhancements

-   Ignore dynamic version in source dist ([#&#8203;9549](astral-sh/uv#9549))
-   Improve build frontend error handling ([#&#8203;9611](astral-sh/uv#9611))
-   Un-hide `uv build --no-build-logs` option ([#&#8203;9642](astral-sh/uv#9642))
-   Flag version mismatch between sdist and wheel during `uv build` ([#&#8203;9633](astral-sh/uv#9633))
-   Improve message when updater receipt is for a different uv executable ([#&#8203;9487](astral-sh/uv#9487))
-   Add environment variable to disable writing installer metadata files ([#&#8203;8877](astral-sh/uv#8877))
-   Add managed downloads for the latest CPython releases: `3.9.21`, `3.10.16`, `3.11.11`, `3.12.8`, and `3.13.1` ([#&#8203;9696](astral-sh/uv#9696))

##### Preview features

-   Build backend: Add hint on import with preview disabled ([#&#8203;9691](astral-sh/uv#9691))
-   Build backend: Add direct builds to the resolver and installer ([#&#8203;9621](astral-sh/uv#9621))
-   Build backend: Add integration test for scripts ([#&#8203;9635](astral-sh/uv#9635))
-   Build backend: Add template to `uv init` ([#&#8203;9661](astral-sh/uv#9661))
-   Build backend: Add `--list` option ([#&#8203;9610](astral-sh/uv#9610))

##### Bug fixes

-   Create missing parent directories for output file of `uv export` / `uv pip compile` ([#&#8203;9648](astral-sh/uv#9648))
-   Fix missing display of non-freethreaded Python 3.13 in `python list` ([#&#8203;9669](astral-sh/uv#9669))
-   Implement `Ord` and `PartialOrd` without origin for `Requirement` ([#&#8203;9624](astral-sh/uv#9624))
-   Include more sources to avoid lowest bound warning ([#&#8203;9644](astral-sh/uv#9644))
-   Respect build tag priority in `uv.lock` ([#&#8203;9677](astral-sh/uv#9677))

##### Documentation

-   Add `build-essentials` note to build failures doc ([#&#8203;9641](astral-sh/uv#9641))
-   Add entry-point for distroless image in GitLab documentation ([#&#8203;9093](astral-sh/uv#9093))
-   Add documentation for `uv python pin` without a `REQUEST` argument ([#&#8203;9631](astral-sh/uv#9631))
-   Add a link to `uv python pin` reference docs ([#&#8203;9630](astral-sh/uv#9630))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever MR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this MR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNy40NDAuNyIsInVwZGF0ZWRJblZlciI6IjM3LjQ0MC43IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJSZW5vdmF0ZSBCb3QiXX0=-->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preview Experimental behavior
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants