diff --git a/crates/uv/src/commands/venv.rs b/crates/uv/src/commands/venv.rs index 8d3e71ebfa09..d94cbc40fe57 100644 --- a/crates/uv/src/commands/venv.rs +++ b/crates/uv/src/commands/venv.rs @@ -159,9 +159,13 @@ async fn venv_impl( if preview.is_enabled() && interpreter_request.is_none() { let project = match VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await { Ok(project) => Some(project), + Err(WorkspaceError::MissingProject(_)) => None, Err(WorkspaceError::MissingPyprojectToml) => None, Err(WorkspaceError::NonWorkspace(_)) => None, - Err(err) => return Err(err).into_diagnostic(), + Err(err) => { + warn_user_once!("{err}"); + None + } }; if let Some(project) = project { diff --git a/crates/uv/tests/common/mod.rs b/crates/uv/tests/common/mod.rs index cbc4a94391c8..7a156584237a 100644 --- a/crates/uv/tests/common/mod.rs +++ b/crates/uv/tests/common/mod.rs @@ -307,11 +307,15 @@ impl TestContext { .map(|pattern| (pattern, "[WORKSPACE]/".to_string())), ); - // Make virtual environment activation cross-platform + // Make virtual environment activation cross-platform and shell-agnostic filters.push(( r"Activate with: (?:.*)\\Scripts\\activate".to_string(), "Activate with: source .venv/bin/activate".to_string(), )); + filters.push(( + r"Activate with: source .venv/bin/activate(?:\.\w+)".to_string(), + "Activate with: source .venv/bin/activate".to_string(), + )); // Account for [`Simplified::user_display`] which is relative to the command working directory if let Some(site_packages) = site_packages { diff --git a/crates/uv/tests/venv.rs b/crates/uv/tests/venv.rs index 762af358bfbb..46d4f9033ca6 100644 --- a/crates/uv/tests/venv.rs +++ b/crates/uv/tests/venv.rs @@ -350,6 +350,64 @@ fn create_venv_respects_pyproject_requires_python() -> Result<()> { Ok(()) } +#[test] +fn create_venv_ignores_missing_pyproject_metadata() -> Result<()> { + let context = TestContext::new_with_versions(&["3.12"]); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! { r"[tool.no.project.here]" })?; + + uv_snapshot!(context.filters(), context.venv() + .arg("--preview"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + Using Python 3.12.[X] interpreter at: [PYTHON-3.12] + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate + "### + ); + + context.venv.assert(predicates::path::is_dir()); + + Ok(()) +} + +#[test] +fn create_venv_warns_user_on_requires_python_discovery_error() -> Result<()> { + let context = TestContext::new_with_versions(&["3.12"]); + + let pyproject_toml = context.temp_dir.child("pyproject.toml"); + pyproject_toml.write_str(indoc! { r"invalid toml" })?; + + uv_snapshot!(context.filters(), context.venv() + .arg("--preview"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + + ----- stderr ----- + warning: Failed to parse `pyproject.toml` during settings discovery: + TOML parse error at line 1, column 9 + | + 1 | invalid toml + | ^ + expected `.`, `=` + + warning: Failed to parse: `pyproject.toml` + Using Python 3.12.[X] interpreter at: [PYTHON-3.12] + Creating virtualenv at: .venv + Activate with: source .venv/bin/activate + "### + ); + + context.venv.assert(predicates::path::is_dir()); + + Ok(()) +} + #[test] fn create_venv_explicit_request_takes_priority_over_python_version_file() { let context = TestContext::new_with_versions(&["3.11", "3.12"]);