Make uv optional#2325
Open
youdie006 wants to merge 1 commit into
Open
Conversation
cjames23
requested changes
Jun 24, 2026
| # `uv` is an optional dependency, so the internal environments only default to it when it is | ||
| # actually available and otherwise fall back to `pip`. This mirrors the detection used by the | ||
| # virtual environment type (see `hatch.env.virtual.VirtualEnvironment.uv_path`). | ||
| return "uv" if shutil.which("uv") is not None else "pip" |
Member
There was a problem hiding this comment.
This does not mirror what is in VirtualEnvironment.uv_path https://github.com/pypa/hatch/blob/master/src/hatch/env/virtual.py#L110 . The uv_path does augmentation with the scripts dir. That augmentation exists precisely because uv (installed as a Python package) lands in the install environment's scripts dir, which is not necessarily on the running process's PATH.
Another concern here is that this runs a full PATH scan on every config build.
d99b6be to
f89c660
Compare
Hatch required uv as a hard dependency and several internal environments hardcoded "installer": "uv", so a clean install with uv removed broke. Add a default_installer() helper that returns "uv" when uv is on PATH else "pip", use it across the internal envs (build, static-analysis, test, type-check, and the hatch-uv bootstrap), and move uv to a [uv] optional extra. uv stays the default when present; pip is used when absent.
Author
|
Thanks @cjames23 — both fixed:
|
f89c660 to
10f31b0
Compare
cjames23
requested changes
Jun 26, 2026
| which.assert_called_once_with("uv", path=f"{scripts_dir}{os.pathsep}/usr/bin") | ||
|
|
||
| def test_detects_uv_in_scripts_dir_not_on_bare_path(self, mocker, tmp_path): | ||
| # The exact scenario from the review: ``uv`` is installed as a package and lives in the |
Member
There was a problem hiding this comment.
Do not reference PR reviews in comments
Comment on lines
+14
to
+22
| # `uv` is an optional dependency, so detect whether it is actually installed before defaulting | ||
| # the internal environments to it. This mirrors the standalone detection used by the virtual | ||
| # environment type (see `hatch.env.virtual.VirtualEnvironment.uv_path`): when `uv` is installed | ||
| # as a Python package it lands in the install environment's scripts directory, which is not | ||
| # necessarily on the running process's `PATH`, so that directory is prepended before searching. | ||
| # | ||
| # The result is cached because `default_installer` is called by every internal environment config | ||
| # producer, and a fresh `PATH` scan on every config build is wasteful. Tests that toggle `uv` | ||
| # availability must clear this cache (`uv_available.cache_clear()`). |
Member
There was a problem hiding this comment.
This level of verbosity of a comment is not needed here.
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.
Summary
Hatch required
uvas a hard dependency, and several internal environments hardcoded"installer": "uv", so a clean Hatch install withuvremoved broke (#2141).This makes
uvoptional:default_installer()(src/hatch/env/internal/__init__.py): returns"uv"whenuvis on PATH (shutil.which, matching the existingVirtualEnvironment.uv_pathdetection), else"pip". The internal envs (build, static-analysis, test, type-check, and thehatch-uvbootstrap env) use it instead of hardcoding"uv".pyproject.toml: moveduv>=0.5.23from requireddependenciesinto a[uv]optional extra, sopip install hatch[uv]opts back in.Verified end-to-end: with
uvon PATH all internal envs resolveuv; withuvabsent all resolvepip. No regression to the uv-present experience.Tests
tests/env/internal/test_default_installer.py— 18 parametrized tests over the internal envs for both uv-present and uv-absent.ruff+mypyclean; history entry added.A note for maintainers
The code-side fallback is the core fix and stands on its own. Moving
uvto an optional extra is a packaging-default change — happy to adjust if you'd prefer keepinguvas a default-but-removable dependency, or a different extra name.AI usage disclosure
Per the contributing guide: this PR was developed with AI assistance (Claude Code); the implementation and tests were substantially AI-assisted and reviewed before submission.
Closes #2141