mirror of https://github.com/astral-sh/uv
Show variants in `uv pip list` (#16091)
## Summary Looks like: ``` Package Version Variant ------- ------- ---------- numpy 2.3.3 accelerate scipy 1.16.2 accelerate ``` Closes #16086.
This commit is contained in:
parent
7902beec75
commit
fa1585cadf
|
|
@ -19,7 +19,8 @@ use uv_pypi_types::{DirectUrl, MetadataError};
|
||||||
use uv_redacted::DisplaySafeUrl;
|
use uv_redacted::DisplaySafeUrl;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BuildInfo, DistributionMetadata, InstalledMetadata, InstalledVersion, Name, VersionOrUrlRef,
|
BuildInfo, DistributionMetadata, InstalledMetadata, InstalledVersion, Name, VariantsJson,
|
||||||
|
VersionOrUrlRef,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
|
@ -484,6 +485,19 @@ impl InstalledDist {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Read the `variant.json` file of the distribution, if it exists.
|
||||||
|
pub fn read_variant_json(&self) -> Result<Option<VariantsJson>, InstalledDistError> {
|
||||||
|
let path = self.install_path().join("variant.json");
|
||||||
|
let file = match fs_err::File::open(&path) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return Ok(None),
|
||||||
|
Err(err) => return Err(err.into()),
|
||||||
|
};
|
||||||
|
let variants_json =
|
||||||
|
serde_json::from_reader::<BufReader<fs_err::File>, VariantsJson>(BufReader::new(file))?;
|
||||||
|
Ok(Some(variants_json))
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the supported wheel tags for the distribution from the `WHEEL` file, if available.
|
/// Return the supported wheel tags for the distribution from the `WHEEL` file, if available.
|
||||||
pub fn read_tags(&self) -> Result<Option<&ExpandedTags>, InstalledDistError> {
|
pub fn read_tags(&self) -> Result<Option<&ExpandedTags>, InstalledDistError> {
|
||||||
if let Some(tags) = self.tags_cache.get() {
|
if let Some(tags) = self.tags_cache.get() {
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,38 @@
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
use std::{fmt::Display, str::FromStr};
|
use std::{fmt::Display, str::FromStr};
|
||||||
use uv_normalize::{InvalidNameError, PackageName};
|
use uv_normalize::{InvalidNameError, PackageName};
|
||||||
use uv_pep440::{Version, VersionParseError};
|
use uv_pep440::{Version, VersionParseError};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum VariantsJsonError {
|
pub enum VariantsJsonError {
|
||||||
#[error("Invalid variants.json filename")]
|
#[error("Invalid `variants.json` filename")]
|
||||||
InvalidFilename,
|
InvalidFilename,
|
||||||
#[error("Invalid variants.json package name: {0}")]
|
#[error("Invalid `variants.json` package name: {0}")]
|
||||||
InvalidName(#[from] InvalidNameError),
|
InvalidName(#[from] InvalidNameError),
|
||||||
#[error("Invalid variants.json version: {0}")]
|
#[error("Invalid `variants.json` version: {0}")]
|
||||||
InvalidVersion(#[from] VersionParseError),
|
InvalidVersion(#[from] VersionParseError),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `<name>-<version>-variants.json` file.
|
/// A `<name>-<version>-variants.json` file.
|
||||||
|
#[derive(Debug, Clone, serde::Deserialize)]
|
||||||
|
pub struct VariantsJson {
|
||||||
|
variants: FxHashMap<String, serde_json::Value>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VariantsJson {
|
||||||
|
/// Returns the label for the current variant.
|
||||||
|
pub fn label(&self) -> Option<&str> {
|
||||||
|
let mut keys = self.variants.keys();
|
||||||
|
let label = keys.next()?;
|
||||||
|
if keys.next().is_some() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(label)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A `<name>-<version>-variants.json` filename.
|
||||||
#[derive(
|
#[derive(
|
||||||
Debug,
|
Debug,
|
||||||
Clone,
|
Clone,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ use uv_configuration::{Concurrency, IndexStrategy, KeyringProviderType};
|
||||||
use uv_distribution_filename::DistFilename;
|
use uv_distribution_filename::DistFilename;
|
||||||
use uv_distribution_types::{
|
use uv_distribution_types::{
|
||||||
Diagnostic, IndexCapabilities, IndexLocations, InstalledDist, Name, RequiresPython,
|
Diagnostic, IndexCapabilities, IndexLocations, InstalledDist, Name, RequiresPython,
|
||||||
|
VariantsJson,
|
||||||
};
|
};
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_installer::SitePackages;
|
use uv_installer::SitePackages;
|
||||||
|
|
@ -166,6 +167,13 @@ pub(crate) async fn pip_list(
|
||||||
.map(|dist| Entry {
|
.map(|dist| Entry {
|
||||||
name: dist.name().clone(),
|
name: dist.name().clone(),
|
||||||
version: dist.version().clone(),
|
version: dist.version().clone(),
|
||||||
|
variant: dist
|
||||||
|
.read_variant_json()
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.as_ref()
|
||||||
|
.and_then(VariantsJson::label)
|
||||||
|
.map(ToString::to_string),
|
||||||
latest_version: latest
|
latest_version: latest
|
||||||
.get(dist.name())
|
.get(dist.name())
|
||||||
.and_then(|filename| filename.as_ref())
|
.and_then(|filename| filename.as_ref())
|
||||||
|
|
@ -204,6 +212,28 @@ pub(crate) async fn pip_list(
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Variant column is only displayed if at least one package has a variant.
|
||||||
|
let variants = results
|
||||||
|
.iter()
|
||||||
|
.map(|dist| {
|
||||||
|
dist.read_variant_json()
|
||||||
|
.ok()
|
||||||
|
.flatten()
|
||||||
|
.as_ref()
|
||||||
|
.and_then(VariantsJson::label)
|
||||||
|
.map(ToString::to_string)
|
||||||
|
})
|
||||||
|
.collect_vec();
|
||||||
|
if variants.iter().any(Option::is_some) {
|
||||||
|
columns.push(Column {
|
||||||
|
header: String::from("Variant"),
|
||||||
|
rows: variants
|
||||||
|
.into_iter()
|
||||||
|
.map(std::option::Option::unwrap_or_default)
|
||||||
|
.collect_vec(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// The latest version and type are only displayed if outdated.
|
// The latest version and type are only displayed if outdated.
|
||||||
if outdated {
|
if outdated {
|
||||||
columns.push(Column {
|
columns.push(Column {
|
||||||
|
|
@ -330,6 +360,8 @@ struct Entry {
|
||||||
name: PackageName,
|
name: PackageName,
|
||||||
version: Version,
|
version: Version,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
variant: Option<String>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
latest_version: Option<Version>,
|
latest_version: Option<Version>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
latest_filetype: Option<FileType>,
|
latest_filetype: Option<FileType>,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue