diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs
index 34797ae14..c975313c0 100644
--- a/crates/uv-cli/src/lib.rs
+++ b/crates/uv-cli/src/lib.rs
@@ -2482,6 +2482,14 @@ pub struct PipFreezeArgs {
#[arg(long, overrides_with("system"), hide = true)]
pub no_system: bool,
+ /// List packages from the specified `--target` directory.
+ #[arg(long, conflicts_with_all = ["prefix", "paths"])]
+ pub target: Option,
+
+ /// List packages from the specified `--prefix` directory.
+ #[arg(long, conflicts_with_all = ["target", "paths"])]
+ pub prefix: Option,
+
#[command(flatten)]
pub compat_args: compat::PipGlobalCompatArgs,
}
@@ -2557,6 +2565,14 @@ pub struct PipListArgs {
#[arg(long, overrides_with("system"), hide = true)]
pub no_system: bool,
+ /// List packages from the specified `--target` directory.
+ #[arg(long, conflicts_with = "prefix")]
+ pub target: Option,
+
+ /// List packages from the specified `--prefix` directory.
+ #[arg(long, conflicts_with = "target")]
+ pub prefix: Option,
+
#[command(flatten)]
pub compat_args: compat::PipListCompatArgs,
}
@@ -2672,6 +2688,14 @@ pub struct PipShowArgs {
#[arg(long, overrides_with("system"), hide = true)]
pub no_system: bool,
+ /// Show a package from the specified `--target` directory.
+ #[arg(long, conflicts_with = "prefix")]
+ pub target: Option,
+
+ /// Show a package from the specified `--prefix` directory.
+ #[arg(long, conflicts_with = "target")]
+ pub prefix: Option,
+
#[command(flatten)]
pub compat_args: compat::PipGlobalCompatArgs,
}
diff --git a/crates/uv/src/commands/pip/freeze.rs b/crates/uv/src/commands/pip/freeze.rs
index 7a6844427..fd8f3cb17 100644
--- a/crates/uv/src/commands/pip/freeze.rs
+++ b/crates/uv/src/commands/pip/freeze.rs
@@ -4,13 +4,15 @@ use std::path::PathBuf;
use anyhow::Result;
use itertools::Itertools;
use owo_colors::OwoColorize;
+use tracing::debug;
use uv_cache::Cache;
use uv_distribution_types::{Diagnostic, InstalledDistKind, Name};
+use uv_fs::Simplified;
use uv_installer::SitePackages;
use uv_preview::Preview;
use uv_python::PythonPreference;
-use uv_python::{EnvironmentPreference, PythonEnvironment, PythonRequest};
+use uv_python::{EnvironmentPreference, Prefix, PythonEnvironment, PythonRequest, Target};
use crate::commands::ExitStatus;
use crate::commands::pip::operations::report_target_environment;
@@ -22,6 +24,8 @@ pub(crate) fn pip_freeze(
strict: bool,
python: Option<&str>,
system: bool,
+ target: Option,
+ prefix: Option,
paths: Option>,
cache: &Cache,
printer: Printer,
@@ -36,6 +40,23 @@ pub(crate) fn pip_freeze(
preview,
)?;
+ // Apply any `--target` or `--prefix` directories.
+ let environment = if let Some(target) = target {
+ debug!(
+ "Using `--target` directory at {}",
+ target.root().user_display()
+ );
+ environment.with_target(target)?
+ } else if let Some(prefix) = prefix {
+ debug!(
+ "Using `--prefix` directory at {}",
+ prefix.root().user_display()
+ );
+ environment.with_prefix(prefix)?
+ } else {
+ environment
+ };
+
report_target_environment(&environment, cache, printer)?;
// Collect all the `site-packages` directories.
diff --git a/crates/uv/src/commands/pip/list.rs b/crates/uv/src/commands/pip/list.rs
index 908cacbf0..0c7879d18 100644
--- a/crates/uv/src/commands/pip/list.rs
+++ b/crates/uv/src/commands/pip/list.rs
@@ -8,6 +8,7 @@ use owo_colors::OwoColorize;
use rustc_hash::FxHashMap;
use serde::Serialize;
use tokio::sync::Semaphore;
+use tracing::debug;
use unicode_width::UnicodeWidthStr;
use uv_cache::{Cache, Refresh};
@@ -25,7 +26,7 @@ use uv_normalize::PackageName;
use uv_pep440::Version;
use uv_preview::Preview;
use uv_python::PythonRequest;
-use uv_python::{EnvironmentPreference, PythonEnvironment, PythonPreference};
+use uv_python::{EnvironmentPreference, Prefix, PythonEnvironment, PythonPreference, Target};
use uv_resolver::{ExcludeNewer, PrereleaseMode};
use crate::commands::ExitStatus;
@@ -51,6 +52,8 @@ pub(crate) async fn pip_list(
exclude_newer: ExcludeNewer,
python: Option<&str>,
system: bool,
+ target: Option,
+ prefix: Option,
cache: &Cache,
printer: Printer,
preview: Preview,
@@ -69,6 +72,23 @@ pub(crate) async fn pip_list(
preview,
)?;
+ // Apply any `--target` or `--prefix` directories.
+ let environment = if let Some(target) = target {
+ debug!(
+ "Using `--target` directory at {}",
+ target.root().user_display()
+ );
+ environment.with_target(target)?
+ } else if let Some(prefix) = prefix {
+ debug!(
+ "Using `--prefix` directory at {}",
+ prefix.root().user_display()
+ );
+ environment.with_prefix(prefix)?
+ } else {
+ environment
+ };
+
report_target_environment(&environment, cache, printer)?;
// Build the installed index.
diff --git a/crates/uv/src/commands/pip/show.rs b/crates/uv/src/commands/pip/show.rs
index 5a906547f..15a4b30ee 100644
--- a/crates/uv/src/commands/pip/show.rs
+++ b/crates/uv/src/commands/pip/show.rs
@@ -5,6 +5,7 @@ use fs_err::File;
use itertools::{Either, Itertools};
use owo_colors::OwoColorize;
use rustc_hash::FxHashMap;
+use tracing::debug;
use uv_cache::Cache;
use uv_distribution_types::{Diagnostic, Name};
@@ -13,7 +14,9 @@ use uv_install_wheel::read_record_file;
use uv_installer::SitePackages;
use uv_normalize::PackageName;
use uv_preview::Preview;
-use uv_python::{EnvironmentPreference, PythonEnvironment, PythonPreference, PythonRequest};
+use uv_python::{
+ EnvironmentPreference, Prefix, PythonEnvironment, PythonPreference, PythonRequest, Target,
+};
use crate::commands::ExitStatus;
use crate::commands::pip::operations::report_target_environment;
@@ -25,6 +28,8 @@ pub(crate) fn pip_show(
strict: bool,
python: Option<&str>,
system: bool,
+ target: Option,
+ prefix: Option,
files: bool,
cache: &Cache,
printer: Printer,
@@ -52,6 +57,23 @@ pub(crate) fn pip_show(
preview,
)?;
+ // Apply any `--target` or `--prefix` directories.
+ let environment = if let Some(target) = target {
+ debug!(
+ "Using `--target` directory at {}",
+ target.root().user_display()
+ );
+ environment.with_target(target)?
+ } else if let Some(prefix) = prefix {
+ debug!(
+ "Using `--prefix` directory at {}",
+ prefix.root().user_display()
+ );
+ environment.with_prefix(prefix)?
+ } else {
+ environment
+ };
+
report_target_environment(&environment, cache, printer)?;
// Build the installed index.
diff --git a/crates/uv/src/lib.rs b/crates/uv/src/lib.rs
index 9a2d4d42b..7ab3d1279 100644
--- a/crates/uv/src/lib.rs
+++ b/crates/uv/src/lib.rs
@@ -941,6 +941,8 @@ async fn run(mut cli: Cli) -> Result {
args.settings.strict,
args.settings.python.as_deref(),
args.settings.system,
+ args.settings.target,
+ args.settings.prefix,
args.paths,
&cache,
printer,
@@ -974,6 +976,8 @@ async fn run(mut cli: Cli) -> Result {
args.settings.exclude_newer,
args.settings.python.as_deref(),
args.settings.system,
+ args.settings.target,
+ args.settings.prefix,
&cache,
printer,
globals.preview,
@@ -995,6 +999,8 @@ async fn run(mut cli: Cli) -> Result {
args.settings.strict,
args.settings.python.as_deref(),
args.settings.system,
+ args.settings.target,
+ args.settings.prefix,
args.files,
&cache,
printer,
diff --git a/crates/uv/src/settings.rs b/crates/uv/src/settings.rs
index 9e623f712..7f80ddb86 100644
--- a/crates/uv/src/settings.rs
+++ b/crates/uv/src/settings.rs
@@ -2771,6 +2771,8 @@ impl PipFreezeSettings {
paths,
system,
no_system,
+ target,
+ prefix,
compat_args: _,
} = args;
@@ -2782,6 +2784,8 @@ impl PipFreezeSettings {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
+ target,
+ prefix,
..PipOptions::default()
},
filesystem,
@@ -2821,6 +2825,8 @@ impl PipListSettings {
python,
system,
no_system,
+ target,
+ prefix,
compat_args: _,
} = args;
@@ -2834,6 +2840,8 @@ impl PipListSettings {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
+ target,
+ prefix,
..PipOptions::from(fetch)
},
filesystem,
@@ -2866,6 +2874,8 @@ impl PipShowSettings {
python,
system,
no_system,
+ target,
+ prefix,
compat_args: _,
} = args;
@@ -2877,6 +2887,8 @@ impl PipShowSettings {
python: python.and_then(Maybe::into_option),
system: flag(system, no_system, "system"),
strict: flag(strict, no_strict, "strict"),
+ target,
+ prefix,
..PipOptions::default()
},
filesystem,
diff --git a/crates/uv/tests/it/pip_freeze.rs b/crates/uv/tests/it/pip_freeze.rs
index e1bb5e59f..eb7f90e97 100644
--- a/crates/uv/tests/it/pip_freeze.rs
+++ b/crates/uv/tests/it/pip_freeze.rs
@@ -482,3 +482,95 @@ fn freeze_with_quiet_flag() -> Result<()> {
Ok(())
}
+
+#[test]
+fn freeze_target() -> Result<()> {
+ let context = TestContext::new("3.12");
+
+ let requirements_txt = context.temp_dir.child("requirements.txt");
+ requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
+
+ let target = context.temp_dir.child("target");
+
+ // Install packages to a target directory.
+ context
+ .pip_install()
+ .arg("-r")
+ .arg("requirements.txt")
+ .arg("--target")
+ .arg(target.path())
+ .assert()
+ .success();
+
+ // Freeze packages in the target directory.
+ uv_snapshot!(context.filters(), context.pip_freeze()
+ .arg("--target")
+ .arg(target.path()), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ markupsafe==2.1.3
+ tomli==2.0.1
+
+ ----- stderr -----
+ "###
+ );
+
+ // Without --target, the packages should not be visible.
+ uv_snapshot!(context.pip_freeze(), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+
+ ----- stderr -----
+ "###
+ );
+
+ Ok(())
+}
+
+#[test]
+fn freeze_prefix() -> Result<()> {
+ let context = TestContext::new("3.12");
+
+ let requirements_txt = context.temp_dir.child("requirements.txt");
+ requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
+
+ let prefix = context.temp_dir.child("prefix");
+
+ // Install packages to a prefix directory.
+ context
+ .pip_install()
+ .arg("-r")
+ .arg("requirements.txt")
+ .arg("--prefix")
+ .arg(prefix.path())
+ .assert()
+ .success();
+
+ // Freeze packages in the prefix directory.
+ uv_snapshot!(context.filters(), context.pip_freeze()
+ .arg("--prefix")
+ .arg(prefix.path()), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ markupsafe==2.1.3
+ tomli==2.0.1
+
+ ----- stderr -----
+ "###
+ );
+
+ // Without --prefix, the packages should not be visible.
+ uv_snapshot!(context.pip_freeze(), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+
+ ----- stderr -----
+ "###
+ );
+
+ Ok(())
+}
diff --git a/crates/uv/tests/it/pip_list.rs b/crates/uv/tests/it/pip_list.rs
index ec1f288e6..73b3461aa 100644
--- a/crates/uv/tests/it/pip_list.rs
+++ b/crates/uv/tests/it/pip_list.rs
@@ -1,4 +1,5 @@
use anyhow::Result;
+use assert_cmd::prelude::*;
use assert_fs::fixture::ChildPath;
use assert_fs::fixture::FileWriteStr;
use assert_fs::fixture::PathChild;
@@ -788,3 +789,99 @@ fn list_ignores_quiet_flag_format_freeze() {
"###
);
}
+
+#[test]
+fn list_target() -> Result<()> {
+ let context = TestContext::new("3.12");
+
+ let requirements_txt = context.temp_dir.child("requirements.txt");
+ requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
+
+ let target = context.temp_dir.child("target");
+
+ // Install packages to a target directory.
+ context
+ .pip_install()
+ .arg("-r")
+ .arg("requirements.txt")
+ .arg("--target")
+ .arg(target.path())
+ .assert()
+ .success();
+
+ // List packages in the target directory.
+ uv_snapshot!(context.filters(), context.pip_list()
+ .arg("--target")
+ .arg(target.path()), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ Package Version
+ ---------- -------
+ markupsafe 2.1.3
+ tomli 2.0.1
+
+ ----- stderr -----
+ "###
+ );
+
+ // Without --target, the packages should not be visible.
+ uv_snapshot!(context.pip_list(), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+
+ ----- stderr -----
+ "###
+ );
+
+ Ok(())
+}
+
+#[test]
+fn list_prefix() -> Result<()> {
+ let context = TestContext::new("3.12");
+
+ let requirements_txt = context.temp_dir.child("requirements.txt");
+ requirements_txt.write_str("MarkupSafe==2.1.3\ntomli==2.0.1")?;
+
+ let prefix = context.temp_dir.child("prefix");
+
+ // Install packages to a prefix directory.
+ context
+ .pip_install()
+ .arg("-r")
+ .arg("requirements.txt")
+ .arg("--prefix")
+ .arg(prefix.path())
+ .assert()
+ .success();
+
+ // List packages in the prefix directory.
+ uv_snapshot!(context.filters(), context.pip_list()
+ .arg("--prefix")
+ .arg(prefix.path()), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ Package Version
+ ---------- -------
+ markupsafe 2.1.3
+ tomli 2.0.1
+
+ ----- stderr -----
+ "###
+ );
+
+ // Without --prefix, the packages should not be visible.
+ uv_snapshot!(context.pip_list(), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+
+ ----- stderr -----
+ "###
+ );
+
+ Ok(())
+}
diff --git a/crates/uv/tests/it/pip_show.rs b/crates/uv/tests/it/pip_show.rs
index a097e128b..7ed3919a0 100644
--- a/crates/uv/tests/it/pip_show.rs
+++ b/crates/uv/tests/it/pip_show.rs
@@ -534,3 +534,105 @@ fn show_files() {
----- stderr -----
"#);
}
+
+#[test]
+fn show_target() -> Result<()> {
+ let context = TestContext::new("3.12");
+
+ let requirements_txt = context.temp_dir.child("requirements.txt");
+ requirements_txt.write_str("MarkupSafe==2.1.3")?;
+
+ let target = context.temp_dir.child("target");
+
+ // Install packages to a target directory.
+ context
+ .pip_install()
+ .arg("-r")
+ .arg("requirements.txt")
+ .arg("--target")
+ .arg(target.path())
+ .assert()
+ .success();
+
+ // Show package in the target directory.
+ uv_snapshot!(context.filters(), context.pip_show()
+ .arg("markupsafe")
+ .arg("--target")
+ .arg(target.path()), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ Name: markupsafe
+ Version: 2.1.3
+ Location: [TEMP_DIR]/target
+ Requires:
+ Required-by:
+
+ ----- stderr -----
+ "###
+ );
+
+ // Without --target, the package should not be found.
+ uv_snapshot!(context.pip_show().arg("markupsafe"), @r###"
+ success: false
+ exit_code: 1
+ ----- stdout -----
+
+ ----- stderr -----
+ warning: Package(s) not found for: markupsafe
+ "###
+ );
+
+ Ok(())
+}
+
+#[test]
+fn show_prefix() -> Result<()> {
+ let context = TestContext::new("3.12");
+
+ let requirements_txt = context.temp_dir.child("requirements.txt");
+ requirements_txt.write_str("MarkupSafe==2.1.3")?;
+
+ let prefix = context.temp_dir.child("prefix");
+
+ // Install packages to a prefix directory.
+ context
+ .pip_install()
+ .arg("-r")
+ .arg("requirements.txt")
+ .arg("--prefix")
+ .arg(prefix.path())
+ .assert()
+ .success();
+
+ // Show package in the prefix directory.
+ uv_snapshot!(context.filters(), context.pip_show()
+ .arg("markupsafe")
+ .arg("--prefix")
+ .arg(prefix.path()), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ Name: markupsafe
+ Version: 2.1.3
+ Location: [TEMP_DIR]/prefix/[PYTHON-LIB]/site-packages
+ Requires:
+ Required-by:
+
+ ----- stderr -----
+ "###
+ );
+
+ // Without --prefix, the package should not be found.
+ uv_snapshot!(context.pip_show().arg("markupsafe"), @r###"
+ success: false
+ exit_code: 1
+ ----- stdout -----
+
+ ----- stderr -----
+ warning: Package(s) not found for: markupsafe
+ "###
+ );
+
+ Ok(())
+}
diff --git a/docs/reference/cli.md b/docs/reference/cli.md
index de2bdc312..d5a1b0fe0 100644
--- a/docs/reference/cli.md
+++ b/docs/reference/cli.md
@@ -5062,6 +5062,7 @@ uv pip freeze [OPTIONS]
--offlineDisable network access.
When disabled, uv will only use locally cached data and locally available files.
May also be set with the UV_OFFLINE environment variable.
--path pathsRestrict to the specified installation path for listing packages (can be used multiple times)
+--prefix prefixList packages from the specified --prefix directory
--project projectRun the command within the given project directory.
All pyproject.toml, uv.toml, and .python-version files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (.venv).
Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.
@@ -5077,7 +5078,8 @@ Python environment if no virtual environment is found.
--systemList packages in the system Python environment.
Disables discovery of virtual environments.
See uv python for details on Python discovery.
-May also be set with the UV_SYSTEM_PYTHON environment variable.
--verbose, -vUse verbose output.
+May also be set with the UV_SYSTEM_PYTHON environment variable.
--target targetList packages from the specified --target directory
+--verbose, -vUse verbose output.
You can configure fine-grained logging using the RUST_LOG environment variable. (https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives)
@@ -5172,6 +5174,7 @@ uv pip list [OPTIONS]
When disabled, uv will only use locally cached data and locally available files.
May also be set with the UV_OFFLINE environment variable.
--outdatedList outdated packages.
The latest version of each package will be shown alongside the installed version. Up-to-date packages will be omitted from the output.
+--prefix prefixList packages from the specified --prefix directory
--project projectRun the command within the given project directory.
All pyproject.toml, uv.toml, and .python-version files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (.venv).
Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.
@@ -5187,7 +5190,8 @@ Python environment if no virtual environment is found.
--systemList packages in the system Python environment.
Disables discovery of virtual environments.
See uv python for details on Python discovery.
-May also be set with the UV_SYSTEM_PYTHON environment variable.
--verbose, -vUse verbose output.
+May also be set with the UV_SYSTEM_PYTHON environment variable.
--target targetList packages from the specified --target directory
+--verbose, -vUse verbose output.
You can configure fine-grained logging using the RUST_LOG environment variable. (https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives)
@@ -5244,7 +5248,8 @@ uv pip show [OPTIONS] [PACKAGE]...
May also be set with the UV_NO_PROGRESS environment variable.
--no-python-downloadsDisable automatic downloads of Python.
--offlineDisable network access.
When disabled, uv will only use locally cached data and locally available files.
-May also be set with the UV_OFFLINE environment variable.
--project projectRun the command within the given project directory.
+May also be set with the UV_OFFLINE environment variable.
--prefix prefixShow a package from the specified --prefix directory
+--project projectRun the command within the given project directory.
All pyproject.toml, uv.toml, and .python-version files will be discovered by walking up the directory tree from the project root, as will the project's virtual environment (.venv).
Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.
See --directory to change the working directory entirely.
@@ -5259,7 +5264,8 @@ system Python environment if no virtual environment is found.
--systemShow a package in the system Python environment.
Disables discovery of virtual environments.
See uv python for details on Python discovery.
-May also be set with the UV_SYSTEM_PYTHON environment variable.
--verbose, -vUse verbose output.
+May also be set with the UV_SYSTEM_PYTHON environment variable.
--target targetShow a package from the specified --target directory
+--verbose, -vUse verbose output.
You can configure fine-grained logging using the RUST_LOG environment variable. (https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives)