mirror of https://github.com/astral-sh/uv
385 lines
12 KiB
Rust
385 lines
12 KiB
Rust
use assert_cmd::assert::OutputAssertExt;
|
|
use assert_fs::prelude::{FileTouch, FileWriteStr, PathChild, PathCreateDir};
|
|
use indoc::{formatdoc, indoc};
|
|
|
|
use uv_fs::Simplified;
|
|
use uv_static::EnvVars;
|
|
|
|
use crate::common::{TestContext, site_packages_path, uv_snapshot};
|
|
|
|
/// Filter the user scheme, which differs between Windows and Unix.
|
|
fn user_scheme_bin_filter() -> (String, String) {
|
|
if cfg!(windows) {
|
|
(
|
|
r"\[USER_CONFIG_DIR\][\\/]Python[\\/]Python\d+".to_string(),
|
|
"[USER_SCHEME]".to_string(),
|
|
)
|
|
} else {
|
|
(r"\[HOME\]/\.local".to_string(), "[USER_SCHEME]".to_string())
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_venv() {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Install in a virtual environment
|
|
uv_snapshot!(context.filters(), context.pip_install()
|
|
.arg(context.workspace_root.join("scripts/packages/fake-uv")), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 1 package in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
"
|
|
);
|
|
|
|
// We should find the binary in the virtual environment
|
|
uv_snapshot!(context.filters(), context.python_command()
|
|
.arg("-c")
|
|
.arg("import uv; print(uv.find_uv_bin())"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[VENV]/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_target() {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Install in a target directory
|
|
uv_snapshot!(context.filters(), context.pip_install()
|
|
.arg(context.workspace_root.join("scripts/packages/fake-uv"))
|
|
.arg("--target")
|
|
.arg("target"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Using CPython 3.12.[X] interpreter at: .venv/[BIN]/[PYTHON]
|
|
Resolved 1 package in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
"
|
|
);
|
|
|
|
// We should find the binary in the target directory
|
|
uv_snapshot!(context.filters(), context.python_command()
|
|
.arg("-c")
|
|
.arg("import uv; print(uv.find_uv_bin())")
|
|
.env(EnvVars::PYTHONPATH, context.temp_dir.child("target").path()), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[TEMP_DIR]/target/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_prefix() {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Install in a prefix directory
|
|
let prefix = context.temp_dir.child("prefix");
|
|
|
|
uv_snapshot!(context.filters(), context.pip_install()
|
|
.arg(context.workspace_root.join("scripts/packages/fake-uv"))
|
|
.arg("--prefix")
|
|
.arg(prefix.path()), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Using CPython 3.12.[X] interpreter at: .venv/[BIN]/[PYTHON]
|
|
Resolved 1 package in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
"
|
|
);
|
|
|
|
// We should find the binary in the prefix directory
|
|
uv_snapshot!(context.filters(), context.python_command()
|
|
.arg("-c")
|
|
.arg("import uv; print(uv.find_uv_bin())")
|
|
.env(
|
|
EnvVars::PYTHONPATH,
|
|
site_packages_path(&context.temp_dir.join("prefix"), "python3.12"),
|
|
), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[TEMP_DIR]/prefix/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_base_prefix() {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Test base prefix fallback by mutating sys.base_prefix
|
|
// First, create a "base" environment with fake-uv installed
|
|
let base_venv = context.temp_dir.child("base-venv");
|
|
context.venv().arg(base_venv.path()).assert().success();
|
|
|
|
// Install fake-uv in the "base" venv
|
|
uv_snapshot!(context.filters(), context.pip_install()
|
|
.arg("--python")
|
|
.arg(base_venv.path())
|
|
.arg(context.workspace_root.join("scripts/packages/fake-uv")), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Using Python 3.12.[X] environment at: base-venv
|
|
Resolved 1 package in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
"
|
|
);
|
|
|
|
context.venv().assert().success();
|
|
|
|
// Mutate `base_prefix` to simulate lookup in a system Python installation
|
|
uv_snapshot!(context.filters(), context.python_command()
|
|
.arg("-c")
|
|
.arg(format!(r#"import sys, uv; sys.base_prefix = "{}"; print(uv.find_uv_bin())"#, base_venv.path().portable_display()))
|
|
.env(EnvVars::PYTHONPATH, site_packages_path(base_venv.path(), "python3.12")), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[TEMP_DIR]/base-venv/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_in_ephemeral_environment() -> anyhow::Result<()> {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Create a minimal pyproject.toml
|
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
|
pyproject_toml.write_str(indoc! { r#"
|
|
[project]
|
|
name = "test-project"
|
|
version = "1.0.0"
|
|
requires-python = ">=3.8"
|
|
dependencies = []
|
|
"#
|
|
})?;
|
|
|
|
// We should find the binary in an ephemeral `--with` environment
|
|
uv_snapshot!(context.filters(), context.run()
|
|
.arg("--with")
|
|
.arg(context.workspace_root.join("scripts/packages/fake-uv"))
|
|
.arg("python")
|
|
.arg("-c")
|
|
.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]
|
|
Audited in [TIME]
|
|
Resolved 1 package in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
"
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_in_parent_of_ephemeral_environment() -> anyhow::Result<()> {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Add the fake-uv package as a dependency
|
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
|
pyproject_toml.write_str(&formatdoc! { r#"
|
|
[project]
|
|
name = "test-project"
|
|
version = "1.0.0"
|
|
requires-python = ">=3.8"
|
|
dependencies = ["uv"]
|
|
|
|
[tool.uv.sources]
|
|
uv = {{ path = "{}" }}
|
|
"#,
|
|
context.workspace_root.join("scripts/packages/fake-uv").portable_display()
|
|
})?;
|
|
|
|
// When running in an ephemeral environment, we should find the binary in the project
|
|
// environment
|
|
uv_snapshot!(context.filters(), context.run()
|
|
.arg("--with")
|
|
.arg("anyio")
|
|
.arg("python")
|
|
.arg("-c")
|
|
.arg("import uv; print(uv.find_uv_bin())"),
|
|
@r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[VENV]/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
Resolved 2 packages in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
Resolved 3 packages in [TIME]
|
|
Prepared 3 packages in [TIME]
|
|
Installed 3 packages in [TIME]
|
|
+ anyio==4.3.0
|
|
+ idna==3.6
|
|
+ sniffio==1.3.1
|
|
"
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn find_uv_bin_user_bin() {
|
|
let context = TestContext::new("3.12")
|
|
.with_filtered_python_names()
|
|
.with_filtered_virtualenv_bin()
|
|
.with_filtered_exe_suffix()
|
|
.with_filter(user_scheme_bin_filter())
|
|
// Target installs always use "bin" on all platforms. On Windows,
|
|
// `with_filtered_virtualenv_bin` only filters "Scripts", not "bin"
|
|
.with_filter((r"[\\/]bin".to_string(), "/[BIN]".to_string()));
|
|
|
|
// Add uv to `~/.local/bin`
|
|
let bin = if cfg!(unix) {
|
|
context.home_dir.child(".local").child("bin")
|
|
} else {
|
|
context
|
|
.user_config_dir
|
|
.child("Python")
|
|
.child("Python312")
|
|
.child("Scripts")
|
|
};
|
|
bin.create_dir_all().unwrap();
|
|
bin.child(format!("uv{}", std::env::consts::EXE_SUFFIX))
|
|
.touch()
|
|
.unwrap();
|
|
|
|
// Install in a virtual environment
|
|
uv_snapshot!(context.filters(), context.pip_install()
|
|
.arg(context.workspace_root.join("scripts/packages/fake-uv")), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
|
|
----- stderr -----
|
|
Resolved 1 package in [TIME]
|
|
Prepared 1 package in [TIME]
|
|
Installed 1 package in [TIME]
|
|
+ uv==0.1.0 (from file://[WORKSPACE]/scripts/packages/fake-uv)
|
|
"
|
|
);
|
|
|
|
// We should find the binary in the virtual environment first
|
|
uv_snapshot!(context.filters(), context.python_command()
|
|
.arg("-c")
|
|
.arg("import uv; print(uv.find_uv_bin())"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[VENV]/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
"
|
|
);
|
|
|
|
// Remove the virtual environment one for some reason
|
|
fs_err::remove_file(if cfg!(unix) {
|
|
context.venv.child("bin").child("uv")
|
|
} else {
|
|
context.venv.child("Scripts").child("uv.exe")
|
|
})
|
|
.unwrap();
|
|
|
|
// We should find the binary in the bin now
|
|
uv_snapshot!(context.filters(), context.python_command()
|
|
.arg("-c")
|
|
.arg("import uv; print(uv.find_uv_bin())"), @r"
|
|
success: true
|
|
exit_code: 0
|
|
----- stdout -----
|
|
[USER_SCHEME]/[BIN]/uv
|
|
|
|
----- stderr -----
|
|
"
|
|
);
|
|
}
|