mirror of
https://github.com/astral-sh/uv.git
synced 2025-11-01 20:31:12 +00:00
Show target Python version in error messages (#10582)
## Summary See: https://github.com/astral-sh/uv/pull/10527#discussion_r1913593405 --------- Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
parent
1480f28f93
commit
04fc36f066
8 changed files with 161 additions and 29 deletions
|
|
@ -43,6 +43,26 @@ pub enum AbiTag {
|
|||
Pyston { implementation_version: (u8, u8) },
|
||||
}
|
||||
|
||||
impl AbiTag {
|
||||
/// Return a pretty string representation of the ABI tag.
|
||||
pub fn pretty(self) -> Option<String> {
|
||||
match self {
|
||||
AbiTag::None => None,
|
||||
AbiTag::Abi3 => None,
|
||||
AbiTag::CPython { python_version, .. } => {
|
||||
Some(format!("CPython {}.{}", python_version.0, python_version.1))
|
||||
}
|
||||
AbiTag::PyPy { python_version, .. } => {
|
||||
Some(format!("PyPy {}.{}", python_version.0, python_version.1))
|
||||
}
|
||||
AbiTag::GraalPy { python_version, .. } => {
|
||||
Some(format!("GraalPy {}.{}", python_version.0, python_version.1))
|
||||
}
|
||||
AbiTag::Pyston { .. } => Some("Pyston".to_string()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for AbiTag {
|
||||
/// Format an [`AbiTag`] as a string.
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,34 @@ pub enum LanguageTag {
|
|||
Pyston { python_version: (u8, u8) },
|
||||
}
|
||||
|
||||
impl LanguageTag {
|
||||
/// Return a pretty string representation of the language tag.
|
||||
pub fn pretty(self) -> Option<String> {
|
||||
match self {
|
||||
Self::None => None,
|
||||
Self::Python { major, minor } => {
|
||||
if let Some(minor) = minor {
|
||||
Some(format!("Python {major}.{minor}"))
|
||||
} else {
|
||||
Some(format!("Python {major}"))
|
||||
}
|
||||
}
|
||||
Self::CPython {
|
||||
python_version: (major, minor),
|
||||
} => Some(format!("CPython {major}.{minor}")),
|
||||
Self::PyPy {
|
||||
python_version: (major, minor),
|
||||
} => Some(format!("PyPy {major}.{minor}")),
|
||||
Self::GraalPy {
|
||||
python_version: (major, minor),
|
||||
} => Some(format!("GraalPy {major}.{minor}")),
|
||||
Self::Pyston {
|
||||
python_version: (major, minor),
|
||||
} => Some(format!("Pyston {major}.{minor}")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for LanguageTag {
|
||||
/// Format a [`LanguageTag`] as a string.
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
|
|
|
|||
|
|
@ -71,6 +71,33 @@ pub enum PlatformTag {
|
|||
Solaris { release_arch: SmallString },
|
||||
}
|
||||
|
||||
impl PlatformTag {
|
||||
/// Return a pretty string representation of the language tag.
|
||||
pub fn pretty(&self) -> Option<&'static str> {
|
||||
match self {
|
||||
PlatformTag::Any => None,
|
||||
PlatformTag::Manylinux { .. } => Some("Linux"),
|
||||
PlatformTag::Manylinux1 { .. } => Some("Linux"),
|
||||
PlatformTag::Manylinux2010 { .. } => Some("Linux"),
|
||||
PlatformTag::Manylinux2014 { .. } => Some("Linux"),
|
||||
PlatformTag::Linux { .. } => Some("Linux"),
|
||||
PlatformTag::Musllinux { .. } => Some("Linux"),
|
||||
PlatformTag::Macos { .. } => Some("macOS"),
|
||||
PlatformTag::Win32 => Some("Windows"),
|
||||
PlatformTag::WinAmd64 => Some("Windows"),
|
||||
PlatformTag::WinArm64 => Some("Windows"),
|
||||
PlatformTag::Android { .. } => Some("Android"),
|
||||
PlatformTag::FreeBsd { .. } => Some("FreeBSD"),
|
||||
PlatformTag::NetBsd { .. } => Some("NetBSD"),
|
||||
PlatformTag::OpenBsd { .. } => Some("OpenBSD"),
|
||||
PlatformTag::Dragonfly { .. } => Some("DragonFly"),
|
||||
PlatformTag::Haiku { .. } => Some("Haiku"),
|
||||
PlatformTag::Illumos { .. } => Some("Illumos"),
|
||||
PlatformTag::Solaris { .. } => Some("Solaris"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformTag {
|
||||
/// Returns `true` if the platform is manylinux-only.
|
||||
pub fn is_manylinux(&self) -> bool {
|
||||
|
|
|
|||
|
|
@ -447,6 +447,7 @@ impl std::fmt::Display for NoSolutionError {
|
|||
&self.fork_urls,
|
||||
&self.fork_indexes,
|
||||
&self.env,
|
||||
self.tags.as_ref(),
|
||||
&self.workspace_members,
|
||||
&self.options,
|
||||
&mut additional_hints,
|
||||
|
|
|
|||
|
|
@ -536,6 +536,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
fork_urls: &ForkUrls,
|
||||
fork_indexes: &ForkIndexes,
|
||||
env: &ResolverEnvironment,
|
||||
tags: Option<&Tags>,
|
||||
workspace_members: &BTreeSet<PackageName>,
|
||||
options: &Options,
|
||||
output_hints: &mut IndexSet<PubGrubHint>,
|
||||
|
|
@ -591,6 +592,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
selector,
|
||||
fork_indexes,
|
||||
env,
|
||||
tags,
|
||||
) {
|
||||
output_hints.insert(hint);
|
||||
}
|
||||
|
|
@ -686,6 +688,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
fork_urls,
|
||||
fork_indexes,
|
||||
env,
|
||||
tags,
|
||||
workspace_members,
|
||||
options,
|
||||
output_hints,
|
||||
|
|
@ -702,6 +705,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
fork_urls,
|
||||
fork_indexes,
|
||||
env,
|
||||
tags,
|
||||
workspace_members,
|
||||
options,
|
||||
output_hints,
|
||||
|
|
@ -721,6 +725,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
selector: &CandidateSelector,
|
||||
fork_indexes: &ForkIndexes,
|
||||
env: &ResolverEnvironment,
|
||||
tags: Option<&Tags>,
|
||||
) -> Option<PubGrubHint> {
|
||||
let response = if let Some(url) = fork_indexes.get(name) {
|
||||
index.explicit().get(&(name.clone(), url.clone()))
|
||||
|
|
@ -739,7 +744,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
match tag {
|
||||
IncompatibleTag::Invalid => None,
|
||||
IncompatibleTag::Python => {
|
||||
// Return all available language tags.
|
||||
let best = tags.and_then(Tags::python_tag);
|
||||
let tags = prioritized.python_tags();
|
||||
if tags.is_empty() {
|
||||
None
|
||||
|
|
@ -748,10 +753,12 @@ impl PubGrubReportFormatter<'_> {
|
|||
package: name.clone(),
|
||||
version: candidate.version().clone(),
|
||||
tags,
|
||||
best,
|
||||
})
|
||||
}
|
||||
}
|
||||
IncompatibleTag::Abi | IncompatibleTag::AbiPythonVersion => {
|
||||
let best = tags.and_then(Tags::abi_tag);
|
||||
let tags = prioritized
|
||||
.abi_tags()
|
||||
.into_iter()
|
||||
|
|
@ -772,6 +779,7 @@ impl PubGrubReportFormatter<'_> {
|
|||
package: name.clone(),
|
||||
version: candidate.version().clone(),
|
||||
tags,
|
||||
best,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1105,6 +1113,8 @@ pub(crate) enum PubGrubHint {
|
|||
version: Version,
|
||||
// excluded from `PartialEq` and `Hash`
|
||||
tags: BTreeSet<LanguageTag>,
|
||||
// excluded from `PartialEq` and `Hash`
|
||||
best: Option<LanguageTag>,
|
||||
},
|
||||
/// No wheels are available for a package, and using source distributions was disabled.
|
||||
AbiTags {
|
||||
|
|
@ -1113,6 +1123,8 @@ pub(crate) enum PubGrubHint {
|
|||
version: Version,
|
||||
// excluded from `PartialEq` and `Hash`
|
||||
tags: BTreeSet<AbiTag>,
|
||||
// excluded from `PartialEq` and `Hash`
|
||||
best: Option<AbiTag>,
|
||||
},
|
||||
/// No wheels are available for a package, and using source distributions was disabled.
|
||||
PlatformTags {
|
||||
|
|
@ -1562,37 +1574,81 @@ impl std::fmt::Display for PubGrubHint {
|
|||
package,
|
||||
version,
|
||||
tags,
|
||||
best,
|
||||
} => {
|
||||
let s = if tags.len() == 1 { "" } else { "s" };
|
||||
write!(
|
||||
f,
|
||||
"{}{} Wheels are available for `{}` ({}) with the following Python tag{s}: {}",
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
package.cyan(),
|
||||
format!("v{version}").cyan(),
|
||||
tags.iter()
|
||||
.map(|tag| format!("`{}`", tag.cyan()))
|
||||
.join(", "),
|
||||
)
|
||||
if let Some(best) = best {
|
||||
let s = if tags.len() == 1 { "" } else { "s" };
|
||||
let best = if let Some(pretty) = best.pretty() {
|
||||
format!("{} (`{}`)", pretty.cyan(), best.cyan())
|
||||
} else {
|
||||
format!("{}", best.cyan())
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{}{} You require {}, but we only found wheels for `{}` ({}) with the following Python implementation tag{s}: {}",
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
best,
|
||||
package.cyan(),
|
||||
format!("v{version}").cyan(),
|
||||
tags.iter()
|
||||
.map(|tag| format!("`{}`", tag.cyan()))
|
||||
.join(", "),
|
||||
)
|
||||
} else {
|
||||
let s = if tags.len() == 1 { "" } else { "s" };
|
||||
write!(
|
||||
f,
|
||||
"{}{} Wheels are available for `{}` ({}) with the following Python implementation tag{s}: {}",
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
package.cyan(),
|
||||
format!("v{version}").cyan(),
|
||||
tags.iter()
|
||||
.map(|tag| format!("`{}`", tag.cyan()))
|
||||
.join(", "),
|
||||
)
|
||||
}
|
||||
}
|
||||
Self::AbiTags {
|
||||
package,
|
||||
version,
|
||||
tags,
|
||||
best,
|
||||
} => {
|
||||
let s = if tags.len() == 1 { "" } else { "s" };
|
||||
write!(
|
||||
f,
|
||||
"{}{} Wheels are available for `{}` ({}) with the following ABI tag{s}: {}",
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
package.cyan(),
|
||||
format!("v{version}").cyan(),
|
||||
tags.iter()
|
||||
.map(|tag| format!("`{}`", tag.cyan()))
|
||||
.join(", "),
|
||||
)
|
||||
if let Some(best) = best {
|
||||
let s = if tags.len() == 1 { "" } else { "s" };
|
||||
let best = if let Some(pretty) = best.pretty() {
|
||||
format!("{} (`{}`)", pretty.cyan(), best.cyan())
|
||||
} else {
|
||||
format!("{}", best.cyan())
|
||||
};
|
||||
write!(
|
||||
f,
|
||||
"{}{} You require {}, but we only found wheels for `{}` ({}) with the following Python ABI tag{s}: {}",
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
best,
|
||||
package.cyan(),
|
||||
format!("v{version}").cyan(),
|
||||
tags.iter()
|
||||
.map(|tag| format!("`{}`", tag.cyan()))
|
||||
.join(", "),
|
||||
)
|
||||
} else {
|
||||
let s = if tags.len() == 1 { "" } else { "s" };
|
||||
write!(
|
||||
f,
|
||||
"{}{} Wheels are available for `{}` ({}) with the following Python ABI tag{s}: {}",
|
||||
"hint".bold().cyan(),
|
||||
":".bold(),
|
||||
package.cyan(),
|
||||
format!("v{version}").cyan(),
|
||||
tags.iter()
|
||||
.map(|tag| format!("`{}`", tag.cyan()))
|
||||
.join(", "),
|
||||
)
|
||||
}
|
||||
}
|
||||
Self::PlatformTags {
|
||||
package,
|
||||
|
|
|
|||
|
|
@ -6758,7 +6758,7 @@ fn lock_requires_python_no_wheels() -> Result<()> {
|
|||
× No solution found when resolving dependencies:
|
||||
╰─▶ Because dearpygui==1.9.1 has no wheels with a matching Python version tag (e.g., `cp312`) and your project depends on dearpygui==1.9.1, we can conclude that your project's requirements are unsatisfiable.
|
||||
|
||||
hint: Wheels are available for `dearpygui` (v1.9.1) with the following ABI tags: `cp37m`, `cp38`, `cp39`, `cp310`, `cp311`
|
||||
hint: Wheels are available for `dearpygui` (v1.9.1) with the following Python ABI tags: `cp37m`, `cp38`, `cp39`, `cp310`, `cp311`
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -13981,7 +13981,7 @@ fn invalid_platform() -> Result<()> {
|
|||
╰─▶ Because only open3d<=0.18.0 is available and open3d<=0.15.2 has no wheels with a matching Python ABI tag (e.g., `cp310`), we can conclude that open3d<=0.15.2 cannot be used.
|
||||
And because open3d>=0.16.0,<=0.18.0 has no wheels with a matching platform tag (e.g., `manylinux_2_17_x86_64`) and you require open3d, we can conclude that your requirements are unsatisfiable.
|
||||
|
||||
hint: Wheels are available for `open3d` (v0.15.2) with the following ABI tags: `cp36m`, `cp37m`, `cp38`, `cp39`
|
||||
hint: You require CPython 3.10 (`cp310`), but we only found wheels for `open3d` (v0.15.2) with the following Python ABI tags: `cp36m`, `cp37m`, `cp38`, `cp39`
|
||||
|
||||
hint: Wheels are available for `open3d` (v0.18.0) on the following platforms: `manylinux_2_27_aarch64`, `manylinux_2_27_x86_64`, `macosx_11_0_x86_64`, `macosx_13_0_arm64`, `win_amd64`
|
||||
"###);
|
||||
|
|
|
|||
|
|
@ -4091,7 +4091,7 @@ fn no_sdist_no_wheels_with_matching_abi() {
|
|||
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no wheels with a matching Python ABI tag (e.g., `cp38`), we can conclude that all versions of package-a cannot be used.
|
||||
And because you require package-a, we can conclude that your requirements are unsatisfiable.
|
||||
|
||||
hint: Wheels are available for `package-a` (v1.0.0) with the following ABI tag: `graalpy310_graalpy240_310_native`
|
||||
hint: You require CPython 3.8 (`cp38`), but we only found wheels for `package-a` (v1.0.0) with the following Python ABI tag: `graalpy310_graalpy240_310_native`
|
||||
"###);
|
||||
|
||||
assert_not_installed(
|
||||
|
|
@ -4177,7 +4177,7 @@ fn no_sdist_no_wheels_with_matching_python() {
|
|||
╰─▶ Because only package-a==1.0.0 is available and package-a==1.0.0 has no wheels with a matching Python implementation tag (e.g., `cp38`), we can conclude that all versions of package-a cannot be used.
|
||||
And because you require package-a, we can conclude that your requirements are unsatisfiable.
|
||||
|
||||
hint: Wheels are available for `package-a` (v1.0.0) with the following Python tag: `graalpy310`
|
||||
hint: You require CPython 3.8 (`cp38`), but we only found wheels for `package-a` (v1.0.0) with the following Python implementation tag: `graalpy310`
|
||||
"###);
|
||||
|
||||
assert_not_installed(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue