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:
Brent Westbrook 2025-02-18 12:03:13 -05:00 committed by GitHub
parent 0868e73d2c
commit a9efdea113
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
153 changed files with 456 additions and 539 deletions

View file

@ -15,7 +15,7 @@ use crate::comments::{
pub use crate::context::PyFormatContext;
pub use crate::options::{
DocstringCode, DocstringCodeLineWidth, MagicTrailingComma, PreviewMode, PyFormatOptions,
PythonVersion, QuoteStyle,
QuoteStyle,
};
use crate::range::is_logical_line;
pub use crate::shared_traits::{AsFormat, FormattedIter, FormattedIterExt, IntoFormat};

View file

@ -5,7 +5,7 @@ use std::str::FromStr;
use ruff_formatter::printer::{LineEnding, PrinterOptions, SourceMapGeneration};
use ruff_formatter::{FormatOptions, IndentStyle, IndentWidth, LineWidth};
use ruff_macros::CacheKey;
use ruff_python_ast::PySourceType;
use ruff_python_ast::{self as ast, PySourceType};
/// Resolved options for formatting one individual file. The difference to `FormatterSettings`
/// is that `FormatterSettings` stores the settings for multiple files (the entire project, a subdirectory, ..)
@ -21,7 +21,7 @@ pub struct PyFormatOptions {
/// The (minimum) Python version used to run the formatted code. This is used
/// to determine the supported Python syntax.
target_version: PythonVersion,
target_version: ast::PythonVersion,
/// Specifies the indent style:
/// * Either a tab
@ -80,7 +80,7 @@ impl Default for PyFormatOptions {
fn default() -> Self {
Self {
source_type: PySourceType::default(),
target_version: PythonVersion::default(),
target_version: ast::PythonVersion::default(),
indent_style: default_indent_style(),
line_width: default_line_width(),
indent_width: default_indent_width(),
@ -108,7 +108,7 @@ impl PyFormatOptions {
}
}
pub const fn target_version(&self) -> PythonVersion {
pub const fn target_version(&self) -> ast::PythonVersion {
self.target_version
}
@ -145,7 +145,7 @@ impl PyFormatOptions {
}
#[must_use]
pub fn with_target_version(mut self, target_version: PythonVersion) -> Self {
pub fn with_target_version(mut self, target_version: ast::PythonVersion) -> Self {
self.target_version = target_version;
self
}
@ -468,52 +468,3 @@ where
)),
}
}
#[derive(CacheKey, Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Default)]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(rename_all = "lowercase")
)]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum PythonVersion {
Py37,
Py38,
// Make sure to also change the default for `ruff_linter::settings::types::PythonVersion`
// when changing the default here.
#[default]
Py39,
Py310,
Py311,
Py312,
Py313,
}
impl PythonVersion {
/// Return `true` if the current version supports [PEP 701].
///
/// [PEP 701]: https://peps.python.org/pep-0701/
pub fn supports_pep_701(self) -> bool {
self >= Self::Py312
}
pub fn as_tuple(self) -> (u8, u8) {
match self {
Self::Py37 => (3, 7),
Self::Py38 => (3, 8),
Self::Py39 => (3, 9),
Self::Py310 => (3, 10),
Self::Py311 => (3, 11),
Self::Py312 => (3, 12),
Self::Py313 => (3, 13),
}
}
pub fn latest() -> Self {
Self::Py313
}
pub fn minimal_supported() -> Self {
Self::Py37
}
}

View file

@ -1,4 +1,5 @@
use ruff_formatter::{format_args, write, FormatContext, FormatError};
use ruff_python_ast::PythonVersion;
use ruff_python_ast::{StmtWith, WithItem};
use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange};
@ -14,7 +15,6 @@ use crate::other::with_item::WithItemLayout;
use crate::prelude::*;
use crate::statement::clause::{clause_body, clause_header, ClauseHeader};
use crate::statement::suite::SuiteKind;
use crate::PythonVersion;
#[derive(Default)]
pub struct FormatStmtWith;
@ -302,7 +302,7 @@ impl<'a> WithItemsLayout<'a> {
}
}
let can_parenthesize = context.options().target_version() >= PythonVersion::Py39
let can_parenthesize = context.options().target_version() >= PythonVersion::PY39
|| are_with_items_parenthesized(with, context)?;
// If the target version doesn't support parenthesized context managers and they aren't