mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-17 13:58:29 +00:00
Tear miette out of the uv venv
command (#14546)
This has some changes to the user-facing output, but makes it more consistent with the rest of uv.
This commit is contained in:
parent
dff9ced40a
commit
dbaec0537a
3 changed files with 62 additions and 168 deletions
|
@ -4,9 +4,7 @@ use std::str::FromStr;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::vec;
|
use std::vec;
|
||||||
|
|
||||||
use anstream::eprint;
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use miette::{Diagnostic, IntoDiagnostic};
|
|
||||||
use owo_colors::OwoColorize;
|
use owo_colors::OwoColorize;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
@ -42,6 +40,21 @@ use crate::settings::NetworkSettings;
|
||||||
|
|
||||||
use super::project::default_dependency_groups;
|
use super::project::default_dependency_groups;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
enum VenvError {
|
||||||
|
#[error("Failed to create virtual environment")]
|
||||||
|
Creation(#[source] uv_virtualenv::Error),
|
||||||
|
|
||||||
|
#[error("Failed to install seed packages into virtual environment")]
|
||||||
|
Seed(#[source] AnyErrorBuild),
|
||||||
|
|
||||||
|
#[error("Failed to extract interpreter tags for installing seed packages")]
|
||||||
|
Tags(#[source] uv_platform_tags::TagsError),
|
||||||
|
|
||||||
|
#[error("Failed to resolve `--find-links` entry")]
|
||||||
|
FlatIndex(#[source] uv_client::FlatIndexError),
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a virtual environment.
|
/// Create a virtual environment.
|
||||||
#[allow(clippy::unnecessary_wraps, clippy::fn_params_excessive_bools)]
|
#[allow(clippy::unnecessary_wraps, clippy::fn_params_excessive_bools)]
|
||||||
pub(crate) async fn venv(
|
pub(crate) async fn venv(
|
||||||
|
@ -70,89 +83,6 @@ pub(crate) async fn venv(
|
||||||
relocatable: bool,
|
relocatable: bool,
|
||||||
preview: PreviewMode,
|
preview: PreviewMode,
|
||||||
) -> Result<ExitStatus> {
|
) -> Result<ExitStatus> {
|
||||||
match venv_impl(
|
|
||||||
project_dir,
|
|
||||||
path,
|
|
||||||
python_request,
|
|
||||||
install_mirrors,
|
|
||||||
link_mode,
|
|
||||||
index_locations,
|
|
||||||
index_strategy,
|
|
||||||
dependency_metadata,
|
|
||||||
keyring_provider,
|
|
||||||
network_settings,
|
|
||||||
prompt,
|
|
||||||
system_site_packages,
|
|
||||||
seed,
|
|
||||||
python_preference,
|
|
||||||
python_downloads,
|
|
||||||
allow_existing,
|
|
||||||
exclude_newer,
|
|
||||||
concurrency,
|
|
||||||
no_config,
|
|
||||||
no_project,
|
|
||||||
cache,
|
|
||||||
printer,
|
|
||||||
relocatable,
|
|
||||||
preview,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
Ok(status) => Ok(status),
|
|
||||||
Err(err) => {
|
|
||||||
eprint!("{err:?}");
|
|
||||||
Ok(ExitStatus::Failure)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Error, Debug, Diagnostic)]
|
|
||||||
enum VenvError {
|
|
||||||
#[error("Failed to create virtualenv")]
|
|
||||||
#[diagnostic(code(uv::venv::creation))]
|
|
||||||
Creation(#[source] uv_virtualenv::Error),
|
|
||||||
|
|
||||||
#[error("Failed to install seed packages")]
|
|
||||||
#[diagnostic(code(uv::venv::seed))]
|
|
||||||
Seed(#[source] AnyErrorBuild),
|
|
||||||
|
|
||||||
#[error("Failed to extract interpreter tags")]
|
|
||||||
#[diagnostic(code(uv::venv::tags))]
|
|
||||||
Tags(#[source] uv_platform_tags::TagsError),
|
|
||||||
|
|
||||||
#[error("Failed to resolve `--find-links` entry")]
|
|
||||||
#[diagnostic(code(uv::venv::flat_index))]
|
|
||||||
FlatIndex(#[source] uv_client::FlatIndexError),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a virtual environment.
|
|
||||||
#[allow(clippy::fn_params_excessive_bools)]
|
|
||||||
async fn venv_impl(
|
|
||||||
project_dir: &Path,
|
|
||||||
path: Option<PathBuf>,
|
|
||||||
python_request: Option<PythonRequest>,
|
|
||||||
install_mirrors: PythonInstallMirrors,
|
|
||||||
link_mode: LinkMode,
|
|
||||||
index_locations: &IndexLocations,
|
|
||||||
index_strategy: IndexStrategy,
|
|
||||||
dependency_metadata: DependencyMetadata,
|
|
||||||
keyring_provider: KeyringProviderType,
|
|
||||||
network_settings: &NetworkSettings,
|
|
||||||
prompt: uv_virtualenv::Prompt,
|
|
||||||
system_site_packages: bool,
|
|
||||||
seed: bool,
|
|
||||||
python_preference: PythonPreference,
|
|
||||||
python_downloads: PythonDownloads,
|
|
||||||
allow_existing: bool,
|
|
||||||
exclude_newer: Option<ExcludeNewer>,
|
|
||||||
concurrency: Concurrency,
|
|
||||||
no_config: bool,
|
|
||||||
no_project: bool,
|
|
||||||
cache: &Cache,
|
|
||||||
printer: Printer,
|
|
||||||
relocatable: bool,
|
|
||||||
preview: PreviewMode,
|
|
||||||
) -> miette::Result<ExitStatus> {
|
|
||||||
let workspace_cache = WorkspaceCache::default();
|
let workspace_cache = WorkspaceCache::default();
|
||||||
let project = if no_project {
|
let project = if no_project {
|
||||||
None
|
None
|
||||||
|
@ -206,7 +136,7 @@ async fn venv_impl(
|
||||||
// If the default dependency-groups demand a higher requires-python
|
// If the default dependency-groups demand a higher requires-python
|
||||||
// we should bias an empty venv to that to avoid churn.
|
// we should bias an empty venv to that to avoid churn.
|
||||||
let default_groups = match &project {
|
let default_groups = match &project {
|
||||||
Some(project) => default_dependency_groups(project.pyproject_toml()).into_diagnostic()?,
|
Some(project) => default_dependency_groups(project.pyproject_toml())?,
|
||||||
None => DefaultGroups::default(),
|
None => DefaultGroups::default(),
|
||||||
};
|
};
|
||||||
let groups = DependencyGroups::default().with_defaults(default_groups);
|
let groups = DependencyGroups::default().with_defaults(default_groups);
|
||||||
|
@ -221,8 +151,7 @@ async fn venv_impl(
|
||||||
project_dir,
|
project_dir,
|
||||||
no_config,
|
no_config,
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
.into_diagnostic()?;
|
|
||||||
|
|
||||||
// Locate the Python interpreter to use in the environment
|
// Locate the Python interpreter to use in the environment
|
||||||
let interpreter = {
|
let interpreter = {
|
||||||
|
@ -239,9 +168,8 @@ async fn venv_impl(
|
||||||
install_mirrors.python_downloads_json_url.as_deref(),
|
install_mirrors.python_downloads_json_url.as_deref(),
|
||||||
preview,
|
preview,
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
.into_diagnostic()?;
|
report_interpreter(&python, false, printer)?;
|
||||||
report_interpreter(&python, false, printer).into_diagnostic()?;
|
|
||||||
python.into_interpreter()
|
python.into_interpreter()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -268,8 +196,7 @@ async fn venv_impl(
|
||||||
"Creating virtual environment {}at: {}",
|
"Creating virtual environment {}at: {}",
|
||||||
if seed { "with seed packages " } else { "" },
|
if seed { "with seed packages " } else { "" },
|
||||||
path.user_display().cyan()
|
path.user_display().cyan()
|
||||||
)
|
)?;
|
||||||
.into_diagnostic()?;
|
|
||||||
|
|
||||||
let upgradeable = preview.is_enabled()
|
let upgradeable = preview.is_enabled()
|
||||||
&& python_request
|
&& python_request
|
||||||
|
@ -307,8 +234,7 @@ async fn venv_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Instantiate a client.
|
// Instantiate a client.
|
||||||
let client = RegistryClientBuilder::try_from(client_builder)
|
let client = RegistryClientBuilder::try_from(client_builder)?
|
||||||
.into_diagnostic()?
|
|
||||||
.cache(cache.clone())
|
.cache(cache.clone())
|
||||||
.index_locations(index_locations)
|
.index_locations(index_locations)
|
||||||
.index_strategy(index_strategy)
|
.index_strategy(index_strategy)
|
||||||
|
@ -400,9 +326,7 @@ async fn venv_impl(
|
||||||
.map_err(|err| VenvError::Seed(err.into()))?;
|
.map_err(|err| VenvError::Seed(err.into()))?;
|
||||||
|
|
||||||
let changelog = Changelog::from_installed(installed);
|
let changelog = Changelog::from_installed(installed);
|
||||||
DefaultInstallLogger
|
DefaultInstallLogger.on_complete(&changelog, printer)?;
|
||||||
.on_complete(&changelog, printer)
|
|
||||||
.into_diagnostic()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the appropriate activation command.
|
// Determine the appropriate activation command.
|
||||||
|
@ -431,7 +355,7 @@ async fn venv_impl(
|
||||||
Some(Shell::Cmd) => Some(shlex_windows(venv.scripts().join("activate"), Shell::Cmd)),
|
Some(Shell::Cmd) => Some(shlex_windows(venv.scripts().join("activate"), Shell::Cmd)),
|
||||||
};
|
};
|
||||||
if let Some(act) = activation {
|
if let Some(act) = activation {
|
||||||
writeln!(printer.stderr(), "Activate with: {}", act.green()).into_diagnostic()?;
|
writeln!(printer.stderr(), "Activate with: {}", act.green())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(ExitStatus::Success)
|
Ok(ExitStatus::Success)
|
||||||
|
|
|
@ -17411,11 +17411,11 @@ fn compile_broken_active_venv() -> Result<()> {
|
||||||
.arg(&broken_system_python)
|
.arg(&broken_system_python)
|
||||||
.arg("venv2"), @r"
|
.arg("venv2"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 1
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
× No interpreter found at path `python3.14159`
|
error: No interpreter found at path `python3.14159`
|
||||||
");
|
");
|
||||||
|
|
||||||
// Simulate a removed Python interpreter
|
// Simulate a removed Python interpreter
|
||||||
|
|
|
@ -656,13 +656,13 @@ fn create_venv_respects_group_requires_python() -> Result<()> {
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("3.11"), @r"
|
uv_snapshot!(context.filters(), context.venv().arg("--python").arg("3.11"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 1
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
× Found conflicting Python requirements:
|
error: Found conflicting Python requirements:
|
||||||
│ - foo: <3.12
|
- foo: <3.12
|
||||||
│ - foo:dev: >=3.12
|
- foo:dev: >=3.12
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -808,7 +808,7 @@ fn seed_older_python_version() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_venv_unknown_python_minor() {
|
fn create_venv_unknown_python_minor() {
|
||||||
let context = TestContext::new_with_versions(&["3.12"]);
|
let context = TestContext::new_with_versions(&["3.12"]).with_filtered_python_sources();
|
||||||
|
|
||||||
let mut command = context.venv();
|
let mut command = context.venv();
|
||||||
command
|
command
|
||||||
|
@ -819,34 +819,22 @@ fn create_venv_unknown_python_minor() {
|
||||||
// Unset this variable to force what the user would see
|
// Unset this variable to force what the user would see
|
||||||
.env_remove(EnvVars::UV_TEST_PYTHON_PATH);
|
.env_remove(EnvVars::UV_TEST_PYTHON_PATH);
|
||||||
|
|
||||||
if cfg!(windows) {
|
uv_snapshot!(context.filters(), &mut command, @r"
|
||||||
uv_snapshot!(&mut command, @r###"
|
success: false
|
||||||
success: false
|
exit_code: 2
|
||||||
exit_code: 1
|
----- stdout -----
|
||||||
----- stdout -----
|
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
× No interpreter found for Python 3.100 in managed installations, search path, or registry
|
error: No interpreter found for Python 3.100 in [PYTHON SOURCES]
|
||||||
"###
|
"
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
uv_snapshot!(&mut command, @r###"
|
|
||||||
success: false
|
|
||||||
exit_code: 1
|
|
||||||
----- stdout -----
|
|
||||||
|
|
||||||
----- stderr -----
|
|
||||||
× No interpreter found for Python 3.100 in managed installations or search path
|
|
||||||
"###
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.venv.assert(predicates::path::missing());
|
context.venv.assert(predicates::path::missing());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn create_venv_unknown_python_patch() {
|
fn create_venv_unknown_python_patch() {
|
||||||
let context = TestContext::new_with_versions(&["3.12"]);
|
let context = TestContext::new_with_versions(&["3.12"]).with_filtered_python_sources();
|
||||||
|
|
||||||
let mut command = context.venv();
|
let mut command = context.venv();
|
||||||
command
|
command
|
||||||
|
@ -857,27 +845,15 @@ fn create_venv_unknown_python_patch() {
|
||||||
// Unset this variable to force what the user would see
|
// Unset this variable to force what the user would see
|
||||||
.env_remove(EnvVars::UV_TEST_PYTHON_PATH);
|
.env_remove(EnvVars::UV_TEST_PYTHON_PATH);
|
||||||
|
|
||||||
if cfg!(windows) {
|
uv_snapshot!(context.filters(), &mut command, @r"
|
||||||
uv_snapshot!(&mut command, @r###"
|
success: false
|
||||||
success: false
|
exit_code: 2
|
||||||
exit_code: 1
|
----- stdout -----
|
||||||
----- stdout -----
|
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
× No interpreter found for Python 3.12.100 in managed installations, search path, or registry
|
error: No interpreter found for Python 3.12.[X] in [PYTHON SOURCES]
|
||||||
"###
|
"
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
uv_snapshot!(&mut command, @r"
|
|
||||||
success: false
|
|
||||||
exit_code: 1
|
|
||||||
----- stdout -----
|
|
||||||
|
|
||||||
----- stderr -----
|
|
||||||
× No interpreter found for Python 3.12.100 in managed installations or search path
|
|
||||||
"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
context.venv.assert(predicates::path::missing());
|
context.venv.assert(predicates::path::missing());
|
||||||
}
|
}
|
||||||
|
@ -915,19 +891,17 @@ fn file_exists() -> Result<()> {
|
||||||
uv_snapshot!(context.filters(), context.venv()
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
.arg(context.venv.as_os_str())
|
.arg(context.venv.as_os_str())
|
||||||
.arg("--python")
|
.arg("--python")
|
||||||
.arg("3.12"), @r###"
|
.arg("3.12"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 1
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
Creating virtual environment at: .venv
|
Creating virtual environment at: .venv
|
||||||
uv::venv::creation
|
error: Failed to create virtual environment
|
||||||
|
Caused by: File exists at `.venv`
|
||||||
× Failed to create virtualenv
|
"
|
||||||
╰─▶ File exists at `.venv`
|
|
||||||
"###
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -970,19 +944,17 @@ fn non_empty_dir_exists() -> Result<()> {
|
||||||
uv_snapshot!(context.filters(), context.venv()
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
.arg(context.venv.as_os_str())
|
.arg(context.venv.as_os_str())
|
||||||
.arg("--python")
|
.arg("--python")
|
||||||
.arg("3.12"), @r###"
|
.arg("3.12"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 1
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
Creating virtual environment at: .venv
|
Creating virtual environment at: .venv
|
||||||
uv::venv::creation
|
error: Failed to create virtual environment
|
||||||
|
Caused by: The directory `.venv` exists, but it's not a virtual environment
|
||||||
× Failed to create virtualenv
|
"
|
||||||
╰─▶ The directory `.venv` exists, but it's not a virtual environment
|
|
||||||
"###
|
|
||||||
);
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1000,19 +972,17 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
||||||
uv_snapshot!(context.filters(), context.venv()
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
.arg(context.venv.as_os_str())
|
.arg(context.venv.as_os_str())
|
||||||
.arg("--python")
|
.arg("--python")
|
||||||
.arg("3.12"), @r###"
|
.arg("3.12"), @r"
|
||||||
success: false
|
success: false
|
||||||
exit_code: 1
|
exit_code: 2
|
||||||
----- stdout -----
|
----- stdout -----
|
||||||
|
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
Creating virtual environment at: .venv
|
Creating virtual environment at: .venv
|
||||||
uv::venv::creation
|
error: Failed to create virtual environment
|
||||||
|
Caused by: The directory `.venv` exists, but it's not a virtual environment
|
||||||
× Failed to create virtualenv
|
"
|
||||||
╰─▶ The directory `.venv` exists, but it's not a virtual environment
|
|
||||||
"###
|
|
||||||
);
|
);
|
||||||
|
|
||||||
uv_snapshot!(context.filters(), context.venv()
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue