mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-08 04:48:02 +00:00
Reuse existing virtualenvs with --no-project
(#5846)
## Summary Closes https://github.com/astral-sh/uv/issues/5840.
This commit is contained in:
parent
345c167774
commit
e58c503f65
2 changed files with 113 additions and 21 deletions
|
@ -158,16 +158,14 @@ pub(crate) async fn run(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let temp_dir;
|
|
||||||
|
|
||||||
// Discover and sync the base environment.
|
// Discover and sync the base environment.
|
||||||
|
let temp_dir;
|
||||||
let base_interpreter = if let Some(script_interpreter) = script_interpreter {
|
let base_interpreter = if let Some(script_interpreter) = script_interpreter {
|
||||||
Some(script_interpreter)
|
Some(script_interpreter)
|
||||||
} else if no_project {
|
|
||||||
// package is `None` (`--no-project` and `--package` are marked as conflicting in Clap).
|
|
||||||
None
|
|
||||||
} else {
|
} else {
|
||||||
let project = if let Some(package) = package {
|
let project = if no_project {
|
||||||
|
None
|
||||||
|
} else if let Some(package) = package {
|
||||||
// We need a workspace, but we don't need to have a current package, we can be e.g. in
|
// We need a workspace, but we don't need to have a current package, we can be e.g. in
|
||||||
// the root of a virtual workspace and then switch into the selected package.
|
// the root of a virtual workspace and then switch into the selected package.
|
||||||
Some(VirtualProject::Project(
|
Some(VirtualProject::Project(
|
||||||
|
@ -199,6 +197,8 @@ pub(crate) async fn run(
|
||||||
}
|
}
|
||||||
|
|
||||||
let venv = if isolated {
|
let venv = if isolated {
|
||||||
|
debug!("Creating isolated virtual environment");
|
||||||
|
|
||||||
// If we're isolating the environment, use an ephemeral virtual environment as the
|
// If we're isolating the environment, use an ephemeral virtual environment as the
|
||||||
// base environment for the project.
|
// base environment for the project.
|
||||||
let interpreter = {
|
let interpreter = {
|
||||||
|
@ -301,23 +301,43 @@ pub(crate) async fn run(
|
||||||
} else {
|
} else {
|
||||||
debug!("No project found; searching for Python interpreter");
|
debug!("No project found; searching for Python interpreter");
|
||||||
|
|
||||||
let client_builder = BaseClientBuilder::new()
|
let interpreter = {
|
||||||
.connectivity(connectivity)
|
let client_builder = BaseClientBuilder::new()
|
||||||
.native_tls(native_tls);
|
.connectivity(connectivity)
|
||||||
|
.native_tls(native_tls);
|
||||||
|
|
||||||
let python = PythonInstallation::find_or_fetch(
|
let python = PythonInstallation::find_or_fetch(
|
||||||
python.as_deref().map(PythonRequest::parse),
|
python.as_deref().map(PythonRequest::parse),
|
||||||
// No opt-in is required for system environments, since we are not mutating it.
|
// No opt-in is required for system environments, since we are not mutating it.
|
||||||
EnvironmentPreference::Any,
|
EnvironmentPreference::Any,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_fetch,
|
python_fetch,
|
||||||
&client_builder,
|
&client_builder,
|
||||||
cache,
|
cache,
|
||||||
Some(&reporter),
|
Some(&reporter),
|
||||||
)
|
)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
python.into_interpreter()
|
python.into_interpreter()
|
||||||
|
};
|
||||||
|
|
||||||
|
if isolated {
|
||||||
|
debug!("Creating isolated virtual environment");
|
||||||
|
|
||||||
|
// If we're isolating the environment, use an ephemeral virtual environment.
|
||||||
|
temp_dir = cache.environment()?;
|
||||||
|
let venv = uv_virtualenv::create_venv(
|
||||||
|
temp_dir.path(),
|
||||||
|
interpreter,
|
||||||
|
uv_virtualenv::Prompt::None,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
)?;
|
||||||
|
venv.into_interpreter()
|
||||||
|
} else {
|
||||||
|
interpreter
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Some(interpreter)
|
Some(interpreter)
|
||||||
|
|
|
@ -1014,3 +1014,75 @@ fn run_isolated_python_version() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Ignore the existing project when executing with `--no-project`.
|
||||||
|
#[test]
|
||||||
|
fn run_no_project() -> Result<()> {
|
||||||
|
let context = TestContext::new("3.12")
|
||||||
|
.with_filtered_python_names()
|
||||||
|
.with_filtered_virtualenv_bin()
|
||||||
|
.with_filtered_exe_suffix();
|
||||||
|
|
||||||
|
let pyproject_toml = context.temp_dir.child("pyproject.toml");
|
||||||
|
pyproject_toml.write_str(indoc! { r#"
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "1.0.0"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = ["anyio"]
|
||||||
|
"#
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let src = context.temp_dir.child("src").child("foo");
|
||||||
|
src.create_dir_all()?;
|
||||||
|
|
||||||
|
let init = src.child("__init__.py");
|
||||||
|
init.touch()?;
|
||||||
|
|
||||||
|
// `run` should run in the context of the project.
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("python").arg("-c").arg("import sys; print(sys.executable)"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
[VENV]/[BIN]/python
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: `uv run` is experimental and may change without warning
|
||||||
|
Resolved 6 packages in [TIME]
|
||||||
|
Prepared 4 packages in [TIME]
|
||||||
|
Installed 4 packages in [TIME]
|
||||||
|
+ anyio==4.3.0
|
||||||
|
+ foo==1.0.0 (from file://[TEMP_DIR]/)
|
||||||
|
+ idna==3.6
|
||||||
|
+ sniffio==1.3.1
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// `run --no-project` should not (but it should still run in the same environment, as it would
|
||||||
|
// if there were no project at all).
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("--no-project").arg("python").arg("-c").arg("import sys; print(sys.executable)"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
[VENV]/[BIN]/python
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: `uv run` is experimental and may change without warning
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// `run --no-project --isolated` should run in an entirely isolated environment.
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("--no-project").arg("--isolated").arg("python").arg("-c").arg("import sys; print(sys.executable)"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
[CACHE_DIR]/builds-v0/[TMP]/python
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: `uv run` is experimental and may change without warning
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue