Implement uv tree --no-dev (#8109)

## Summary

Allow pruning dev-dependencies in uv tree.
This is not inherently in conflict with --invert, but this pruning is
not yet implemented there.
This commit is contained in:
bluss 2024-10-12 15:10:56 +02:00 committed by GitHub
parent a3b11dacb8
commit e67d87301a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 43 additions and 3 deletions

View file

@ -3070,6 +3070,17 @@ pub struct TreeArgs {
#[command(flatten)] #[command(flatten)]
pub tree: DisplayTreeArgs, pub tree: DisplayTreeArgs,
/// Include development dependencies.
///
/// Development dependencies are defined via `tool.uv.dev-dependencies` in a
/// `pyproject.toml`.
#[arg(long, overrides_with("no_dev"), hide = true)]
pub dev: bool,
/// Omit development dependencies.
#[arg(long, overrides_with("dev"), conflicts_with = "invert")]
pub no_dev: bool,
/// Assert that the `uv.lock` will remain unchanged. /// Assert that the `uv.lock` will remain unchanged.
/// ///
/// Requires that the lockfile is up-to-date. If the lockfile is missing or /// Requires that the lockfile is up-to-date. If the lockfile is missing or

View file

@ -4,6 +4,7 @@ use std::collections::BTreeSet;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::{FxHashMap, FxHashSet}; use rustc_hash::{FxHashMap, FxHashSet};
use uv_configuration::DevMode;
use uv_normalize::{ExtraName, GroupName, PackageName}; use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pypi_types::ResolverMarkerEnvironment; use uv_pypi_types::ResolverMarkerEnvironment;
@ -22,8 +23,10 @@ pub struct TreeDisplay<'env> {
optional_dependencies: optional_dependencies:
FxHashMap<&'env PackageId, FxHashMap<ExtraName, Vec<Cow<'env, Dependency>>>>, FxHashMap<&'env PackageId, FxHashMap<ExtraName, Vec<Cow<'env, Dependency>>>>,
dev_dependencies: FxHashMap<&'env PackageId, FxHashMap<GroupName, Vec<Cow<'env, Dependency>>>>, dev_dependencies: FxHashMap<&'env PackageId, FxHashMap<GroupName, Vec<Cow<'env, Dependency>>>>,
/// Maximum display depth of the dependency tree /// Maximum display depth of the dependency tree.
depth: usize, depth: usize,
/// Whether to include development dependencies in the display.
dev: DevMode,
/// Prune the given packages from the display of the dependency tree. /// Prune the given packages from the display of the dependency tree.
prune: Vec<PackageName>, prune: Vec<PackageName>,
/// Display only the specified packages. /// Display only the specified packages.
@ -40,6 +43,7 @@ impl<'env> TreeDisplay<'env> {
depth: usize, depth: usize,
prune: Vec<PackageName>, prune: Vec<PackageName>,
packages: Vec<PackageName>, packages: Vec<PackageName>,
dev: DevMode,
no_dedupe: bool, no_dedupe: bool,
invert: bool, invert: bool,
) -> Self { ) -> Self {
@ -180,6 +184,7 @@ impl<'env> TreeDisplay<'env> {
optional_dependencies, optional_dependencies,
dev_dependencies, dev_dependencies,
depth, depth,
dev,
prune, prune,
packages, packages,
no_dedupe, no_dedupe,
@ -231,12 +236,14 @@ impl<'env> TreeDisplay<'env> {
let dependencies: Vec<Node<'env>> = self let dependencies: Vec<Node<'env>> = self
.dependencies .dependencies
.get(node.package_id()) .get(node.package_id())
.filter(|_| self.dev != DevMode::Only)
.into_iter() .into_iter()
.flatten() .flatten()
.map(|dep| Node::Dependency(dep.as_ref())) .map(|dep| Node::Dependency(dep.as_ref()))
.chain( .chain(
self.optional_dependencies self.optional_dependencies
.get(node.package_id()) .get(node.package_id())
.filter(|_| self.dev != DevMode::Only)
.into_iter() .into_iter()
.flatten() .flatten()
.flat_map(|(extra, deps)| { .flat_map(|(extra, deps)| {
@ -247,6 +254,7 @@ impl<'env> TreeDisplay<'env> {
.chain( .chain(
self.dev_dependencies self.dev_dependencies
.get(node.package_id()) .get(node.package_id())
.filter(|_| self.dev != DevMode::Exclude)
.into_iter() .into_iter()
.flatten() .flatten()
.flat_map(|(group, deps)| { .flat_map(|(group, deps)| {

View file

@ -4,7 +4,7 @@ use std::path::Path;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::Connectivity; use uv_client::Connectivity;
use uv_configuration::{Concurrency, TargetTriple}; use uv_configuration::{Concurrency, DevMode, TargetTriple};
use uv_pep508::PackageName; use uv_pep508::PackageName;
use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion}; use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion};
use uv_resolver::TreeDisplay; use uv_resolver::TreeDisplay;
@ -21,6 +21,7 @@ use crate::settings::ResolverSettings;
#[allow(clippy::fn_params_excessive_bools)] #[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn tree( pub(crate) async fn tree(
project_dir: &Path, project_dir: &Path,
dev: DevMode,
locked: bool, locked: bool,
frozen: bool, frozen: bool,
universal: bool, universal: bool,
@ -89,6 +90,7 @@ pub(crate) async fn tree(
depth.into(), depth.into(),
prune, prune,
package, package,
dev,
no_dedupe, no_dedupe,
invert, invert,
); );

View file

@ -1444,6 +1444,7 @@ async fn run_project(
commands::tree( commands::tree(
project_dir, project_dir,
args.dev,
args.locked, args.locked,
args.frozen, args.frozen,
args.universal, args.universal,

View file

@ -936,6 +936,7 @@ impl RemoveSettings {
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub(crate) struct TreeSettings { pub(crate) struct TreeSettings {
pub(crate) dev: DevMode,
pub(crate) locked: bool, pub(crate) locked: bool,
pub(crate) frozen: bool, pub(crate) frozen: bool,
pub(crate) universal: bool, pub(crate) universal: bool,
@ -956,6 +957,8 @@ impl TreeSettings {
let TreeArgs { let TreeArgs {
tree, tree,
universal, universal,
dev,
no_dev,
locked, locked,
frozen, frozen,
build, build,
@ -966,6 +969,7 @@ impl TreeSettings {
} = args; } = args;
Self { Self {
dev: DevMode::from_args(dev, no_dev, false),
locked, locked,
frozen, frozen,
universal, universal,

View file

@ -438,7 +438,7 @@ fn dev_dependencies() -> Result<()> {
"#, "#,
)?; )?;
uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###" uv_snapshot!(context.filters(), context.tree(), @r###"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
@ -453,6 +453,18 @@ fn dev_dependencies() -> Result<()> {
"### "###
); );
uv_snapshot!(context.filters(), context.tree().arg("--no-dev"), @r###"
success: true
exit_code: 0
----- stdout -----
project v0.1.0
iniconfig v2.0.0
----- stderr -----
Resolved 5 packages in [TIME]
"###
);
// `uv tree` should update the lockfile // `uv tree` should update the lockfile
let lock = context.read("uv.lock"); let lock = context.read("uv.lock");
assert!(!lock.is_empty()); assert!(!lock.is_empty());

View file

@ -2329,6 +2329,8 @@ uv tree [OPTIONS]
<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p> <p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p>
</dd><dt><code>--no-dedupe</code></dt><dd><p>Do not de-duplicate repeated dependencies. Usually, when a package has already displayed its dependencies, further occurrences will not re-display its dependencies, and will include a (*) to indicate it has already been shown. This flag will cause those duplicates to be repeated</p> </dd><dt><code>--no-dedupe</code></dt><dd><p>Do not de-duplicate repeated dependencies. Usually, when a package has already displayed its dependencies, further occurrences will not re-display its dependencies, and will include a (*) to indicate it has already been shown. This flag will cause those duplicates to be repeated</p>
</dd><dt><code>--no-dev</code></dt><dd><p>Omit development dependencies</p>
</dd><dt><code>--no-index</code></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p> </dd><dt><code>--no-index</code></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p>
</dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p> </dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p>