mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-03 18:38:21 +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
|
||||
};
|
||||
|
||||
let temp_dir;
|
||||
|
||||
// Discover and sync the base environment.
|
||||
let temp_dir;
|
||||
let base_interpreter = if let Some(script_interpreter) = script_interpreter {
|
||||
Some(script_interpreter)
|
||||
} else if no_project {
|
||||
// package is `None` (`--no-project` and `--package` are marked as conflicting in Clap).
|
||||
None
|
||||
} 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
|
||||
// the root of a virtual workspace and then switch into the selected package.
|
||||
Some(VirtualProject::Project(
|
||||
|
@ -199,6 +197,8 @@ pub(crate) async fn run(
|
|||
}
|
||||
|
||||
let venv = if isolated {
|
||||
debug!("Creating isolated virtual environment");
|
||||
|
||||
// If we're isolating the environment, use an ephemeral virtual environment as the
|
||||
// base environment for the project.
|
||||
let interpreter = {
|
||||
|
@ -301,23 +301,43 @@ pub(crate) async fn run(
|
|||
} else {
|
||||
debug!("No project found; searching for Python interpreter");
|
||||
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
let interpreter = {
|
||||
let client_builder = BaseClientBuilder::new()
|
||||
.connectivity(connectivity)
|
||||
.native_tls(native_tls);
|
||||
|
||||
let python = PythonInstallation::find_or_fetch(
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
// No opt-in is required for system environments, since we are not mutating it.
|
||||
EnvironmentPreference::Any,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
)
|
||||
.await?;
|
||||
let python = PythonInstallation::find_or_fetch(
|
||||
python.as_deref().map(PythonRequest::parse),
|
||||
// No opt-in is required for system environments, since we are not mutating it.
|
||||
EnvironmentPreference::Any,
|
||||
python_preference,
|
||||
python_fetch,
|
||||
&client_builder,
|
||||
cache,
|
||||
Some(&reporter),
|
||||
)
|
||||
.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)
|
||||
|
|
|
@ -1014,3 +1014,75 @@ fn run_isolated_python_version() -> Result<()> {
|
|||
|
||||
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