From 6b45baf7be1b2fb11bd3757e5d2642a5a039057f Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Mon, 5 Aug 2024 15:02:35 -0400 Subject: [PATCH] Support `--python-platform` in `uv tree` (#5764) ## Summary This allows you to set (e.g.) `--python-platform windows` to view the resolved dependencies on Windows. Closes https://github.com/astral-sh/uv/issues/5760. --- crates/uv-cli/src/lib.rs | 15 ++++++++++ crates/uv/src/commands/pip/mod.rs | 2 +- crates/uv/src/commands/project/tree.rs | 19 ++++++++++-- crates/uv/src/lib.rs | 2 ++ crates/uv/src/settings.rs | 6 ++++ crates/uv/tests/tree.rs | 22 +++++++++++++- docs/reference/cli.md | 41 ++++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 5 deletions(-) diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs index 595e8e0ce..4b848490c 100644 --- a/crates/uv-cli/src/lib.rs +++ b/crates/uv-cli/src/lib.rs @@ -2370,6 +2370,21 @@ pub struct TreeArgs { #[command(flatten)] pub resolver: ResolverArgs, + /// The Python version to use when filtering the tree (via `--filter`). For example, pass + /// `--python-version 3.10` to display the dependencies that would be included when installing + /// on Python 3.10. + #[arg(long, conflicts_with = "universal")] + pub python_version: Option, + + /// The platform to use when filtering the tree (via `--filter`). For example, pass `--platform + /// windows` to display the dependencies that would be included when installing on Windows. + /// + /// Represented as a "target triple", a string that describes the target platform in terms of + /// its CPU, vendor, and operating system name, like `x86_64-unknown-linux-gnu` or + /// `aaarch64-apple-darwin`. + #[arg(long, conflicts_with = "universal")] + pub python_platform: Option, + /// The Python interpreter for which packages should be listed. /// /// By default, uv installs into the virtual environment in the current working directory or diff --git a/crates/uv/src/commands/pip/mod.rs b/crates/uv/src/commands/pip/mod.rs index 5730efb72..01a360973 100644 --- a/crates/uv/src/commands/pip/mod.rs +++ b/crates/uv/src/commands/pip/mod.rs @@ -16,7 +16,7 @@ pub(crate) mod sync; pub(crate) mod tree; pub(crate) mod uninstall; -// Determine the tags, markers, and interpreter to use for resolution. +/// Determine the tags, markers, and interpreter to use for resolution. pub(crate) fn resolution_environment( python_version: Option, python_platform: Option, diff --git a/crates/uv/src/commands/project/tree.rs b/crates/uv/src/commands/project/tree.rs index 1e39385a4..d0ad56555 100644 --- a/crates/uv/src/commands/project/tree.rs +++ b/crates/uv/src/commands/project/tree.rs @@ -1,3 +1,4 @@ +use std::borrow::Cow; use std::fmt::Write; use anyhow::Result; @@ -5,9 +6,9 @@ use anyhow::Result; use pep508_rs::PackageName; use uv_cache::Cache; use uv_client::Connectivity; -use uv_configuration::{Concurrency, PreviewMode}; +use uv_configuration::{Concurrency, PreviewMode, TargetTriple}; use uv_fs::CWD; -use uv_python::{PythonFetch, PythonPreference, PythonRequest}; +use uv_python::{PythonFetch, PythonPreference, PythonRequest, PythonVersion}; use uv_resolver::TreeDisplay; use uv_warnings::warn_user_once; use uv_workspace::{DiscoveryOptions, Workspace}; @@ -30,6 +31,8 @@ pub(crate) async fn tree( package: Vec, no_dedupe: bool, invert: bool, + python_version: Option, + python_platform: Option, python: Option, settings: ResolverSettings, python_preference: PythonPreference, @@ -79,10 +82,20 @@ pub(crate) async fn tree( ) .await?; + // Apply the platform tags to the markers. + let markers = match (python_platform, python_version) { + (Some(python_platform), Some(python_version)) => { + Cow::Owned(python_version.markers(&python_platform.markers(interpreter.markers()))) + } + (Some(python_platform), None) => Cow::Owned(python_platform.markers(interpreter.markers())), + (None, Some(python_version)) => Cow::Owned(python_version.markers(interpreter.markers())), + (None, None) => Cow::Borrowed(interpreter.markers()), + }; + // Render the tree. let tree = TreeDisplay::new( &lock.lock, - (!universal).then(|| interpreter.markers()), + (!universal).then(|| markers.as_ref()), depth.into(), prune, package, diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs index 3137ae4e7..e760e6f82 100644 --- a/crates/uv/src/lib.rs +++ b/crates/uv/src/lib.rs @@ -1127,6 +1127,8 @@ async fn run_project( args.package, args.no_dedupe, args.invert, + args.python_version, + args.python_platform, args.python, args.resolver, globals.python_preference, diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs index 521a3bc78..9a7ae621d 100644 --- a/crates/uv/src/settings.rs +++ b/crates/uv/src/settings.rs @@ -775,6 +775,8 @@ pub(crate) struct TreeSettings { pub(crate) package: Vec, pub(crate) no_dedupe: bool, pub(crate) invert: bool, + pub(crate) python_version: Option, + pub(crate) python_platform: Option, pub(crate) python: Option, pub(crate) resolver: ResolverSettings, } @@ -789,6 +791,8 @@ impl TreeSettings { frozen, build, resolver, + python_version, + python_platform, python, } = args; @@ -801,6 +805,8 @@ impl TreeSettings { package: tree.package, no_dedupe: tree.no_dedupe, invert: tree.invert, + python_version, + python_platform, python, resolver: ResolverSettings::combine(resolver_options(resolver, build), filesystem), } diff --git a/crates/uv/tests/tree.rs b/crates/uv/tests/tree.rs index e2bf4c9f3..258894594 100644 --- a/crates/uv/tests/tree.rs +++ b/crates/uv/tests/tree.rs @@ -219,7 +219,27 @@ fn platform_dependencies() -> Result<()> { Resolved 8 packages in [TIME] "###); - // Should include `colorama`, even though it's only included on Windows. + // Unless `--python-platform` is set to `windows`, in which case it should be included. + uv_snapshot!(context.filters(), context.tree().arg("--python-platform").arg("windows"), @r###" + success: true + exit_code: 0 + ----- stdout ----- + project v0.1.0 + └── black v24.3.0 + ├── click v8.1.7 + │ └── colorama v0.4.6 + ├── mypy-extensions v1.0.0 + ├── packaging v24.0 + ├── pathspec v0.12.1 + └── platformdirs v4.2.0 + + ----- stderr ----- + warning: `uv tree` is experimental and may change without warning + Resolved 8 packages in [TIME] + "###); + + // When `--universal` is _not_ provided, should include `colorama`, even though it's only + // included on Windows. uv_snapshot!(context.filters(), context.tree().arg("--universal"), @r###" success: true exit_code: 0 diff --git a/docs/reference/cli.md b/docs/reference/cli.md index f7051bcfe..c2b5f4db8 100644 --- a/docs/reference/cli.md +++ b/docs/reference/cli.md @@ -3392,6 +3392,47 @@ uv tree [OPTIONS]
  • symlink: Symbolically link packages from the wheel into the site-packages directory
  • +
    --python-version python-version

    The Python version to use when filtering the tree (via --filter). For example, pass --python-version 3.10 to display the dependencies that would be included when installing on Python 3.10

    + +
    --python-platform python-platform

    The platform to use when filtering the tree (via --filter). For example, pass --platform windows to display the dependencies that would be included when installing on Windows.

    + +

    Represented as a "target triple", a string that describes the target platform in terms of its CPU, vendor, and operating system name, like x86_64-unknown-linux-gnu or aaarch64-apple-darwin.

    + +

    Possible values:

    + +
      +
    • windows: An alias for x86_64-pc-windows-msvc, the default target for Windows
    • + +
    • linux: An alias for x86_64-unknown-linux-gnu, the default target for Linux
    • + +
    • macos: An alias for aarch64-apple-darwin, the default target for macOS
    • + +
    • x86_64-pc-windows-msvc: An x86 Windows target
    • + +
    • x86_64-unknown-linux-gnu: An x86 Linux target. Equivalent to x86_64-manylinux_2_17
    • + +
    • aarch64-apple-darwin: An ARM-based macOS target, as seen on Apple Silicon devices
    • + +
    • x86_64-apple-darwin: An x86 macOS target
    • + +
    • aarch64-unknown-linux-gnu: An ARM64 Linux target. Equivalent to aarch64-manylinux_2_17
    • + +
    • aarch64-unknown-linux-musl: An ARM64 Linux target
    • + +
    • x86_64-unknown-linux-musl: An x86_64 Linux target
    • + +
    • x86_64-manylinux_2_17: An x86_64 target for the manylinux_2_17 platform
    • + +
    • x86_64-manylinux_2_28: An x86_64 target for the manylinux_2_28 platform
    • + +
    • x86_64-manylinux_2_31: An x86_64 target for the manylinux_2_31 platform
    • + +
    • aarch64-manylinux_2_17: An ARM64 target for the manylinux_2_17 platform
    • + +
    • aarch64-manylinux_2_28: An ARM64 target for the manylinux_2_28 platform
    • + +
    • aarch64-manylinux_2_31: An ARM64 target for the manylinux_2_31 platform
    • +
    --python, -p python

    The Python interpreter for which packages should be listed.

    By default, uv installs into the virtual environment in the current working directory or any parent directory. The --python option allows you to specify a different interpreter, which is intended for use in continuous integration (CI) environments or other automated workflows.