mirror of https://github.com/astral-sh/uv
Add support for `--prefix` and `--with` installations in `find_uv_bin` (#14184)
Follows #14182 Adds support for the case described at https://github.com/astral-sh/uv/issues/10194#issuecomment-2993544346 This also happens to fix both `--with` requirement test cases, which should close https://github.com/tox-dev/pre-commit-uv/issues/70
This commit is contained in:
parent
554f06c595
commit
8968d783de
|
|
@ -141,22 +141,14 @@ fn find_uv_bin_prefix() {
|
|||
.env(
|
||||
EnvVars::PYTHONPATH,
|
||||
site_packages_path(&context.temp_dir.join("prefix"), "python3.12"),
|
||||
), @r#"
|
||||
success: false
|
||||
exit_code: 1
|
||||
), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[TEMP_DIR]/prefix/[BIN]/uv
|
||||
|
||||
----- stderr -----
|
||||
Traceback (most recent call last):
|
||||
File "<string>", line 1, in <module>
|
||||
File "[TEMP_DIR]/prefix/[PYTHON-LIB]/site-packages/uv/_find_uv.py", line 36, in find_uv_bin
|
||||
raise UvNotFound(
|
||||
uv._find_uv.UvNotFound: Could not find the uv binary in any of the following locations:
|
||||
- [VENV]/[BIN]
|
||||
- [PYTHON-BIN-3.12]
|
||||
- [USER_SCHEME]/[BIN]
|
||||
- [TEMP_DIR]/prefix/[PYTHON-LIB]/site-packages/[BIN]
|
||||
"#
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -239,10 +231,11 @@ fn find_uv_bin_in_ephemeral_environment() -> anyhow::Result<()> {
|
|||
.arg(context.workspace_root.join("scripts/packages/fake-uv"))
|
||||
.arg("python")
|
||||
.arg("-c")
|
||||
.arg("import uv; print(uv.find_uv_bin())"), @r#"
|
||||
success: false
|
||||
exit_code: 1
|
||||
.arg("import uv; print(uv.find_uv_bin())"), @r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[CACHE_DIR]/archive-v0/[HASH]/[BIN]/uv
|
||||
|
||||
----- stderr -----
|
||||
Resolved 1 package in [TIME]
|
||||
|
|
@ -251,16 +244,7 @@ fn find_uv_bin_in_ephemeral_environment() -> anyhow::Result<()> {
|
|||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
||||
Traceback (most recent call last):
|
||||
File "<string>", line 1, in <module>
|
||||
File "[CACHE_DIR]/archive-v0/[HASH]/[PYTHON-LIB]/site-packages/uv/_find_uv.py", line 36, in find_uv_bin
|
||||
raise UvNotFound(
|
||||
uv._find_uv.UvNotFound: Could not find the uv binary in any of the following locations:
|
||||
- [CACHE_DIR]/builds-v0/[TMP]/[BIN]
|
||||
- [PYTHON-BIN-3.12]
|
||||
- [USER_SCHEME]/[BIN]
|
||||
- [CACHE_DIR]/archive-v0/[HASH]/[PYTHON-LIB]/site-packages/[BIN]
|
||||
"#
|
||||
"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
@ -300,10 +284,11 @@ fn find_uv_bin_in_parent_of_ephemeral_environment() -> anyhow::Result<()> {
|
|||
.arg("python")
|
||||
.arg("-c")
|
||||
.arg("import uv; print(uv.find_uv_bin())"),
|
||||
@r#"
|
||||
success: false
|
||||
exit_code: 1
|
||||
@r"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
[VENV]/[BIN]/uv
|
||||
|
||||
----- stderr -----
|
||||
Resolved 2 packages in [TIME]
|
||||
|
|
@ -316,16 +301,7 @@ fn find_uv_bin_in_parent_of_ephemeral_environment() -> anyhow::Result<()> {
|
|||
+ anyio==4.3.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.1
|
||||
Traceback (most recent call last):
|
||||
File "<string>", line 1, in <module>
|
||||
File "[SITE_PACKAGES]/uv/_find_uv.py", line 36, in find_uv_bin
|
||||
raise UvNotFound(
|
||||
uv._find_uv.UvNotFound: Could not find the uv binary in any of the following locations:
|
||||
- [CACHE_DIR]/builds-v0/[TMP]/[BIN]
|
||||
- [PYTHON-BIN-3.12]
|
||||
- [USER_SCHEME]/[BIN]
|
||||
- [SITE_PACKAGES]/[BIN]
|
||||
"#
|
||||
"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -16,16 +16,29 @@ def find_uv_bin() -> str:
|
|||
targets = [
|
||||
# The scripts directory for the current Python
|
||||
sysconfig.get_path("scripts"),
|
||||
# The scripts directory for the base prefix (if different)
|
||||
# The scripts directory for the base prefix
|
||||
sysconfig.get_path("scripts", vars={"base": sys.base_prefix}),
|
||||
# The user scheme scripts directory, e.g., `~/.local/bin`
|
||||
sysconfig.get_path("scripts", scheme=_user_scheme()),
|
||||
# Adjacent to the package root, e.g. from, `pip install --target`
|
||||
os.path.join(os.path.dirname(os.path.dirname(__file__)), "bin"),
|
||||
# Above the package root, e.g., from `pip install --prefix` or `uv run --with`
|
||||
(
|
||||
# On Windows, with module path `<prefix>/Lib/site-packages/uv`
|
||||
_join(_matching_parents(_module_path(), "Lib/site-packages/uv"), "Scripts")
|
||||
if sys.platform == "win32"
|
||||
# On Unix, with module path `<prefix>/lib/python3.13/site-packages/uv`
|
||||
else _join(
|
||||
_matching_parents(_module_path(), "lib/python*/site-packages/uv"), "bin"
|
||||
)
|
||||
),
|
||||
# Adjacent to the package root, e.g., from `pip install --target`
|
||||
# with module path `<target>/uv`
|
||||
_join(_matching_parents(_module_path(), "uv"), "bin"),
|
||||
]
|
||||
|
||||
seen = []
|
||||
for target in targets:
|
||||
if not target:
|
||||
continue
|
||||
if target in seen:
|
||||
continue
|
||||
seen.append(target)
|
||||
|
|
@ -39,6 +52,45 @@ def find_uv_bin() -> str:
|
|||
)
|
||||
|
||||
|
||||
def _module_path() -> str | None:
|
||||
path = os.path.dirname(__file__)
|
||||
return path
|
||||
|
||||
|
||||
def _matching_parents(path: str | None, match: str) -> str | None:
|
||||
"""
|
||||
Return the parent directory of `path` after trimming a `match` from the end.
|
||||
The match is expected to contain `/` as a path separator, while the `path`
|
||||
is expected to use the platform's path separator (e.g., `os.sep`). The path
|
||||
components are compared case-insensitively and a `*` wildcard can be used
|
||||
in the `match`.
|
||||
"""
|
||||
from fnmatch import fnmatch
|
||||
|
||||
if not path:
|
||||
return None
|
||||
parts = path.split(os.sep)
|
||||
match_parts = match.split("/")
|
||||
if len(parts) < len(match_parts):
|
||||
return None
|
||||
|
||||
if not all(
|
||||
fnmatch(part, match_part)
|
||||
for part, match_part in zip(
|
||||
reversed(parts), reversed(match_parts), strict=False
|
||||
)
|
||||
):
|
||||
return None
|
||||
|
||||
return os.sep.join(parts[: -len(match_parts)])
|
||||
|
||||
|
||||
def _join(path: str | None, *parts: str) -> str | None:
|
||||
if not path:
|
||||
return None
|
||||
return os.path.join(path, *parts)
|
||||
|
||||
|
||||
def _user_scheme() -> str:
|
||||
if sys.version_info >= (3, 10):
|
||||
user_scheme = sysconfig.get_preferred_scheme("user")
|
||||
|
|
|
|||
Loading…
Reference in New Issue