mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-28 21:14:47 +00:00
Add a diagnostic to detect invalid Python versions (#630)
Related to: https://github.com/astral-sh/puffin/issues/410.
This commit is contained in:
parent
a24eb57e93
commit
edd741bf13
2 changed files with 31 additions and 4 deletions
|
@ -384,7 +384,7 @@ fn allow_incompatibilities() -> Result<()> {
|
||||||
Installed 1 package in [TIME]
|
Installed 1 package in [TIME]
|
||||||
- jinja2==3.1.2
|
- jinja2==3.1.2
|
||||||
+ jinja2==2.11.3
|
+ jinja2==2.11.3
|
||||||
warning: The package `flask` requires `jinja2 >=3.1.2` but `2.11.3` is installed.
|
warning: The package `flask` requires `jinja2 >=3.1.2`, but `2.11.3` is installed.
|
||||||
"###);
|
"###);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ use fs_err as fs;
|
||||||
use rustc_hash::FxHashSet;
|
use rustc_hash::FxHashSet;
|
||||||
|
|
||||||
use distribution_types::{InstalledDist, Metadata, VersionOrUrl};
|
use distribution_types::{InstalledDist, Metadata, VersionOrUrl};
|
||||||
use pep440_rs::Version;
|
use pep440_rs::{Version, VersionSpecifiers};
|
||||||
use pep508_rs::Requirement;
|
use pep508_rs::Requirement;
|
||||||
use puffin_interpreter::Virtualenv;
|
use puffin_interpreter::Virtualenv;
|
||||||
use puffin_normalize::PackageName;
|
use puffin_normalize::PackageName;
|
||||||
|
@ -95,6 +95,17 @@ impl<'a> SitePackages<'a> {
|
||||||
// Determine the dependencies for the given package.
|
// Determine the dependencies for the given package.
|
||||||
let metadata = distribution.metadata()?;
|
let metadata = distribution.metadata()?;
|
||||||
|
|
||||||
|
// Verify that the package is compatible with the current Python version.
|
||||||
|
if let Some(requires_python) = metadata.requires_python.as_ref() {
|
||||||
|
if !requires_python.contains(self.venv.interpreter().version()) {
|
||||||
|
diagnostics.push(Diagnostic::IncompatiblePythonVersion {
|
||||||
|
package: package.clone(),
|
||||||
|
version: self.venv.interpreter().version().clone(),
|
||||||
|
requires_python: requires_python.clone(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Verify that the dependencies are installed.
|
// Verify that the dependencies are installed.
|
||||||
for requirement in &metadata.requires_dist {
|
for requirement in &metadata.requires_dist {
|
||||||
if !requirement.evaluate_markers(self.venv.interpreter().markers(), &[]) {
|
if !requirement.evaluate_markers(self.venv.interpreter().markers(), &[]) {
|
||||||
|
@ -198,6 +209,14 @@ impl IntoIterator for SitePackages<'_> {
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Diagnostic {
|
pub enum Diagnostic {
|
||||||
|
IncompatiblePythonVersion {
|
||||||
|
/// The package that requires a different version of Python.
|
||||||
|
package: PackageName,
|
||||||
|
/// The version of Python that is installed.
|
||||||
|
version: Version,
|
||||||
|
/// The version of Python that is required.
|
||||||
|
requires_python: VersionSpecifiers,
|
||||||
|
},
|
||||||
MissingDependency {
|
MissingDependency {
|
||||||
/// The package that is missing a dependency.
|
/// The package that is missing a dependency.
|
||||||
package: PackageName,
|
package: PackageName,
|
||||||
|
@ -218,18 +237,25 @@ impl Diagnostic {
|
||||||
/// Convert the diagnostic into a user-facing message.
|
/// Convert the diagnostic into a user-facing message.
|
||||||
pub fn message(&self) -> String {
|
pub fn message(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
|
Self::IncompatiblePythonVersion {
|
||||||
|
package,
|
||||||
|
version,
|
||||||
|
requires_python,
|
||||||
|
} => format!(
|
||||||
|
"The package `{package}` requires Python {requires_python}, but `{version}` is installed."
|
||||||
|
),
|
||||||
Self::MissingDependency {
|
Self::MissingDependency {
|
||||||
package,
|
package,
|
||||||
requirement,
|
requirement,
|
||||||
} => {
|
} => {
|
||||||
format!("The package `{package}` requires `{requirement}` but it is not installed.")
|
format!("The package `{package}` requires `{requirement}`, but it's not installed.")
|
||||||
}
|
}
|
||||||
Self::IncompatibleDependency {
|
Self::IncompatibleDependency {
|
||||||
package,
|
package,
|
||||||
version,
|
version,
|
||||||
requirement,
|
requirement,
|
||||||
} => format!(
|
} => format!(
|
||||||
"The package `{package}` requires `{requirement}` but `{version}` is installed."
|
"The package `{package}` requires `{requirement}`, but `{version}` is installed."
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -237,6 +263,7 @@ impl Diagnostic {
|
||||||
/// Returns `true` if the [`PackageName`] is involved in this diagnostic.
|
/// Returns `true` if the [`PackageName`] is involved in this diagnostic.
|
||||||
pub fn includes(&self, name: &PackageName) -> bool {
|
pub fn includes(&self, name: &PackageName) -> bool {
|
||||||
match self {
|
match self {
|
||||||
|
Self::IncompatiblePythonVersion { package, .. } => name == package,
|
||||||
Self::MissingDependency { package, .. } => name == package,
|
Self::MissingDependency { package, .. } => name == package,
|
||||||
Self::IncompatibleDependency {
|
Self::IncompatibleDependency {
|
||||||
package,
|
package,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue