mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 12:55:05 +00:00
Use ast::PythonVersion
internally in the formatter and linter (#16170)
## Summary This PR updates the formatter and linter to use the `PythonVersion` struct from the `ruff_python_ast` crate internally. While this doesn't remove the need for the `linter::PythonVersion` enum, it does remove the `formatter::PythonVersion` enum and limits the use in the linter to deserializing from CLI arguments and config files and moves most of the remaining methods to the `ast::PythonVersion` struct. ## Test Plan Existing tests, with some inputs and outputs updated to reflect the new (de)serialization format. I think these are test-specific and shouldn't affect any external (de)serialization. --------- Co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
This commit is contained in:
parent
0868e73d2c
commit
a9efdea113
153 changed files with 456 additions and 539 deletions
|
@ -4,8 +4,9 @@ use std::path::{Path, PathBuf};
|
|||
|
||||
use anyhow::{Context, Result};
|
||||
use log::debug;
|
||||
use pep440_rs::VersionSpecifiers;
|
||||
use pep440_rs::{Operator, Version, VersionSpecifiers};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use ruff_linter::settings::types::PythonVersion;
|
||||
|
||||
|
@ -150,8 +151,7 @@ pub(super) fn load_options<P: AsRef<Path>>(path: P) -> Result<Options> {
|
|||
if ruff.target_version.is_none() {
|
||||
if let Some(project) = pyproject.project {
|
||||
if let Some(requires_python) = project.requires_python {
|
||||
ruff.target_version =
|
||||
PythonVersion::get_minimum_supported_version(&requires_python);
|
||||
ruff.target_version = get_minimum_supported_version(&requires_python);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -167,6 +167,38 @@ pub(super) fn load_options<P: AsRef<Path>>(path: P) -> Result<Options> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Infer the minimum supported [`PythonVersion`] from a `requires-python` specifier.
|
||||
fn get_minimum_supported_version(requires_version: &VersionSpecifiers) -> Option<PythonVersion> {
|
||||
/// Truncate a version to its major and minor components.
|
||||
fn major_minor(version: &Version) -> Option<Version> {
|
||||
let major = version.release().first()?;
|
||||
let minor = version.release().get(1)?;
|
||||
Some(Version::new([major, minor]))
|
||||
}
|
||||
|
||||
// Extract the minimum supported version from the specifiers.
|
||||
let minimum_version = requires_version
|
||||
.iter()
|
||||
.filter(|specifier| {
|
||||
matches!(
|
||||
specifier.operator(),
|
||||
Operator::Equal
|
||||
| Operator::EqualStar
|
||||
| Operator::ExactEqual
|
||||
| Operator::TildeEqual
|
||||
| Operator::GreaterThan
|
||||
| Operator::GreaterThanEqual
|
||||
)
|
||||
})
|
||||
.filter_map(|specifier| major_minor(specifier.version()))
|
||||
.min()?;
|
||||
|
||||
debug!("Detected minimum supported `requires-python` version: {minimum_version}");
|
||||
|
||||
// Find the Python version that matches the minimum supported version.
|
||||
PythonVersion::iter().find(|version| Version::from(*version) == minimum_version)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::fs;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue