Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions crates/uv/src/commands/project/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion}
use uv_resolver::{PackageMap, TreeDisplay};
use uv_scripts::Pep723Script;
use uv_settings::PythonInstallMirrors;
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache};

use crate::commands::pip::latest::LatestClient;
use crate::commands::pip::loggers::DefaultResolveLogger;
Expand Down Expand Up @@ -65,18 +65,18 @@ pub(crate) async fn tree(
) -> Result<ExitStatus> {
// Find the project requirements.
let workspace_cache = WorkspaceCache::default();
let workspace;
let virtual_project;
let target = if let Some(script) = script.as_ref() {
LockTarget::Script(script)
} else {
workspace = Workspace::discover(
virtual_project = VirtualProject::discover(
project_dir,
&DiscoveryOptions::default(),
cache,
&workspace_cache,
)
.await?;
LockTarget::Workspace(&workspace)
LockTarget::Workspace(virtual_project.workspace())
};

// Determine the groups to include.
Expand Down
35 changes: 35 additions & 0 deletions crates/uv/tests/project/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2226,6 +2226,41 @@ fn non_project() -> Result<()> {
Ok(())
}

/// A pyproject.toml with only `[dependency-groups]` (no `[project]`, no `[tool.uv.workspace]`)
/// is valid per PEP 735, and `uv tree` must handle it.
#[test]
fn dependency_groups_only() -> Result<()> {
let context = uv_test::test_context!("3.12");

let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[dependency-groups]
async = ["anyio"]
"#,
)?;

uv_snapshot!(context.filters(), context.tree().arg("--universal").arg("--group").arg("async"), @"
success: true
exit_code: 0
----- stdout -----
anyio v4.3.0 (group: async)
├── idna v3.6
└── sniffio v1.3.1

----- stderr -----
warning: No `requires-python` value found in the workspace. Defaulting to `>=3.12`.
Resolved 3 packages in [TIME]
"
);

// `uv tree` should update the lockfile
let lock = context.read("uv.lock");
assert!(!lock.is_empty());

Ok(())
}

#[test]
fn non_project_group_selection_with_extras() -> Result<()> {
let context = uv_test::test_context!("3.12");
Expand Down
Loading