mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-17 05:47:45 +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::vec;
|
||||
|
||||
use anstream::eprint;
|
||||
use anyhow::Result;
|
||||
use miette::{Diagnostic, IntoDiagnostic};
|
||||
use owo_colors::OwoColorize;
|
||||
use thiserror::Error;
|
||||
|
||||
|
@ -42,6 +40,21 @@ use crate::settings::NetworkSettings;
|
|||
|
||||
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.
|
||||
#[allow(clippy::unnecessary_wraps, clippy::fn_params_excessive_bools)]
|
||||
pub(crate) async fn venv(
|
||||
|
@ -70,89 +83,6 @@ pub(crate) async fn venv(
|
|||
relocatable: bool,
|
||||
preview: PreviewMode,
|
||||
) -> 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 project = if no_project {
|
||||
None
|
||||
|
@ -206,7 +136,7 @@ async fn venv_impl(
|
|||
// If the default dependency-groups demand a higher requires-python
|
||||
// we should bias an empty venv to that to avoid churn.
|
||||
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(),
|
||||
};
|
||||
let groups = DependencyGroups::default().with_defaults(default_groups);
|
||||
|
@ -221,8 +151,7 @@ async fn venv_impl(
|
|||
project_dir,
|
||||
no_config,
|
||||
)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
.await?;
|
||||
|
||||
// Locate the Python interpreter to use in the environment
|
||||
let interpreter = {
|
||||
|
@ -239,9 +168,8 @@ async fn venv_impl(
|
|||
install_mirrors.python_downloads_json_url.as_deref(),
|
||||
preview,
|
||||
)
|
||||
.await
|
||||
.into_diagnostic()?;
|
||||
report_interpreter(&python, false, printer).into_diagnostic()?;
|
||||
.await?;
|
||||
report_interpreter(&python, false, printer)?;
|
||||
python.into_interpreter()
|
||||
};
|
||||
|
||||
|
@ -268,8 +196,7 @@ async fn venv_impl(
|
|||
"Creating virtual environment {}at: {}",
|
||||
if seed { "with seed packages " } else { "" },
|
||||
path.user_display().cyan()
|
||||
)
|
||||
.into_diagnostic()?;
|
||||
)?;
|
||||
|
||||
let upgradeable = preview.is_enabled()
|
||||
&& python_request
|
||||
|
@ -307,8 +234,7 @@ async fn venv_impl(
|
|||
}
|
||||
|
||||
// Instantiate a client.
|
||||
let client = RegistryClientBuilder::try_from(client_builder)
|
||||
.into_diagnostic()?
|
||||
let client = RegistryClientBuilder::try_from(client_builder)?
|
||||
.cache(cache.clone())
|
||||
.index_locations(index_locations)
|
||||
.index_strategy(index_strategy)
|
||||
|
@ -400,9 +326,7 @@ async fn venv_impl(
|
|||
.map_err(|err| VenvError::Seed(err.into()))?;
|
||||
|
||||
let changelog = Changelog::from_installed(installed);
|
||||
DefaultInstallLogger
|
||||
.on_complete(&changelog, printer)
|
||||
.into_diagnostic()?;
|
||||
DefaultInstallLogger.on_complete(&changelog, printer)?;
|
||||
}
|
||||
|
||||
// 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)),
|
||||
};
|
||||
if let Some(act) = activation {
|
||||
writeln!(printer.stderr(), "Activate with: {}", act.green()).into_diagnostic()?;
|
||||
writeln!(printer.stderr(), "Activate with: {}", act.green())?;
|
||||
}
|
||||
|
||||
Ok(ExitStatus::Success)
|
||||
|
|
|
@ -17411,11 +17411,11 @@ fn compile_broken_active_venv() -> Result<()> {
|
|||
.arg(&broken_system_python)
|
||||
.arg("venv2"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× No interpreter found at path `python3.14159`
|
||||
error: No interpreter found at path `python3.14159`
|
||||
");
|
||||
|
||||
// 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"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× Found conflicting Python requirements:
|
||||
│ - foo: <3.12
|
||||
│ - foo:dev: >=3.12
|
||||
error: Found conflicting Python requirements:
|
||||
- foo: <3.12
|
||||
- foo:dev: >=3.12
|
||||
"
|
||||
);
|
||||
|
||||
|
@ -808,7 +808,7 @@ fn seed_older_python_version() {
|
|||
|
||||
#[test]
|
||||
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();
|
||||
command
|
||||
|
@ -819,34 +819,22 @@ fn create_venv_unknown_python_minor() {
|
|||
// Unset this variable to force what the user would see
|
||||
.env_remove(EnvVars::UV_TEST_PYTHON_PATH);
|
||||
|
||||
if cfg!(windows) {
|
||||
uv_snapshot!(&mut command, @r###"
|
||||
uv_snapshot!(context.filters(), &mut command, @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- 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());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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();
|
||||
command
|
||||
|
@ -857,27 +845,15 @@ fn create_venv_unknown_python_patch() {
|
|||
// Unset this variable to force what the user would see
|
||||
.env_remove(EnvVars::UV_TEST_PYTHON_PATH);
|
||||
|
||||
if cfg!(windows) {
|
||||
uv_snapshot!(&mut command, @r###"
|
||||
uv_snapshot!(context.filters(), &mut command, @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
× No interpreter found for Python 3.12.100 in managed installations, search path, or registry
|
||||
"###
|
||||
);
|
||||
} 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
|
||||
error: No interpreter found for Python 3.12.[X] in [PYTHON SOURCES]
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
context.venv.assert(predicates::path::missing());
|
||||
}
|
||||
|
@ -915,19 +891,17 @@ fn file_exists() -> Result<()> {
|
|||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
.arg("3.12"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtual environment at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
× Failed to create virtualenv
|
||||
╰─▶ File exists at `.venv`
|
||||
"###
|
||||
error: Failed to create virtual environment
|
||||
Caused by: File exists at `.venv`
|
||||
"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -970,19 +944,17 @@ fn non_empty_dir_exists() -> Result<()> {
|
|||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
.arg("3.12"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtual environment at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
× Failed to create virtualenv
|
||||
╰─▶ The directory `.venv` exists, but it's not a virtual environment
|
||||
"###
|
||||
error: Failed to create virtual environment
|
||||
Caused by: The directory `.venv` exists, but it's not a virtual environment
|
||||
"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
|
@ -1000,19 +972,17 @@ fn non_empty_dir_exists_allow_existing() -> Result<()> {
|
|||
uv_snapshot!(context.filters(), context.venv()
|
||||
.arg(context.venv.as_os_str())
|
||||
.arg("--python")
|
||||
.arg("3.12"), @r###"
|
||||
.arg("3.12"), @r"
|
||||
success: false
|
||||
exit_code: 1
|
||||
exit_code: 2
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||
Creating virtual environment at: .venv
|
||||
uv::venv::creation
|
||||
|
||||
× Failed to create virtualenv
|
||||
╰─▶ The directory `.venv` exists, but it's not a virtual environment
|
||||
"###
|
||||
error: Failed to create virtual environment
|
||||
Caused by: The directory `.venv` exists, but it's not a virtual environment
|
||||
"
|
||||
);
|
||||
|
||||
uv_snapshot!(context.filters(), context.venv()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue