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

@ -40,7 +40,7 @@ impl std::fmt::Display for PythonVersion {
}
}
impl From<PythonVersion> for ruff_python_ast::python_version::PythonVersion {
impl From<PythonVersion> for ruff_python_ast::PythonVersion {
fn from(value: PythonVersion) -> Self {
match value {
PythonVersion::Py37 => Self::PY37,
@ -61,8 +61,8 @@ mod tests {
#[test]
fn same_default_as_python_version() {
assert_eq!(
ruff_python_ast::python_version::PythonVersion::from(PythonVersion::default()),
ruff_python_ast::python_version::PythonVersion::default()
ruff_python_ast::PythonVersion::from(PythonVersion::default()),
ruff_python_ast::PythonVersion::default()
);
}
}

View file

@ -16,7 +16,7 @@ use ruff_db::system::{
OsSystem, System, SystemPath, SystemPathBuf, UserConfigDirectoryOverrideGuard,
};
use ruff_db::Upcast;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
struct TestCase {
db: ProjectDatabase,

View file

@ -2,7 +2,7 @@ use std::{collections::HashMap, hash::BuildHasher};
use red_knot_python_semantic::{PythonPlatform, SitePackages};
use ruff_db::system::SystemPathBuf;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
/// Combine two values, preferring the values in `self`.
///

View file

@ -310,7 +310,7 @@ mod tests {
use anyhow::{anyhow, Context};
use insta::assert_ron_snapshot;
use ruff_db::system::{SystemPathBuf, TestSystem};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use crate::{ProjectDiscoveryError, ProjectMetadata};

View file

@ -6,7 +6,7 @@ use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity, Span};
use ruff_db::files::system_path_to_file;
use ruff_db::system::{System, SystemPath};
use ruff_macros::Combine;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use rustc_hash::FxHashMap;
use serde::{Deserialize, Serialize};
use std::borrow::Cow;

View file

@ -1,7 +1,7 @@
use crate::metadata::options::Options;
use crate::metadata::value::{RangedValue, ValueSource, ValueSourceGuard};
use pep440_rs::{release_specifiers_to_ranges, Version, VersionSpecifiers};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use serde::{Deserialize, Deserializer, Serialize};
use std::collections::Bound;
use std::ops::Deref;

View file

@ -28,7 +28,7 @@ pub(crate) mod tests {
use ruff_db::system::{DbWithTestSystem, System, SystemPathBuf, TestSystem};
use ruff_db::vendored::VendoredFileSystem;
use ruff_db::{Db as SourceDb, Upcast};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
#[salsa::db]
#[derive(Clone)]

View file

@ -631,7 +631,7 @@ impl PartialEq<SearchPath> for VendoredPathBuf {
#[cfg(test)]
mod tests {
use ruff_db::Db;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use crate::db::tests::TestDb;
use crate::module_resolver::testing::{FileSpec, MockedTypeshed, TestCase, TestCaseBuilder};

View file

@ -6,7 +6,7 @@ use rustc_hash::{FxBuildHasher, FxHashSet};
use ruff_db::files::{File, FilePath, FileRootKind};
use ruff_db::system::{DirectoryEntry, System, SystemPath, SystemPathBuf};
use ruff_db::vendored::{VendoredFileSystem, VendoredPath};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use crate::db::Db;
use crate::module_name::ModuleName;
@ -725,7 +725,7 @@ mod tests {
assert_const_function_query_was_not_run, assert_function_query_was_not_run,
};
use ruff_db::Db;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use crate::db::tests::TestDb;
use crate::module_name::ModuleName;

View file

@ -1,6 +1,6 @@
use ruff_db::system::{DbWithTestSystem, SystemPath, SystemPathBuf};
use ruff_db::vendored::VendoredPathBuf;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use crate::db::tests::TestDb;
use crate::program::{Program, SearchPathSettings};

View file

@ -4,7 +4,7 @@ use std::num::{NonZeroU16, NonZeroUsize};
use std::ops::{RangeFrom, RangeInclusive};
use std::str::FromStr;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use rustc_hash::FxHashMap;
use crate::db::Db;

View file

@ -4,7 +4,7 @@ use crate::Db;
use anyhow::Context;
use ruff_db::system::{SystemPath, SystemPathBuf};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use salsa::Durability;
use salsa::Setter;

View file

@ -14,7 +14,7 @@ use std::num::NonZeroUsize;
use std::ops::Deref;
use ruff_db::system::{System, SystemPath, SystemPathBuf};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
type SitePackagesDiscoveryResult<T> = Result<T, SitePackagesDiscoveryError>;

View file

@ -8,7 +8,7 @@ use indexmap::IndexSet;
use itertools::Itertools;
use ruff_db::files::File;
use ruff_python_ast as ast;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use type_ordering::union_elements_ordering;
pub(crate) use self::builder::{IntersectionBuilder, UnionBuilder};
@ -4535,7 +4535,7 @@ pub(crate) mod tests {
use ruff_db::parsed::parsed_module;
use ruff_db::system::DbWithTestSystem;
use ruff_db::testing::assert_function_query_was_not_run;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use test_case::test_case;
/// Explicitly test for Python version <3.13 and >=3.13, to ensure that

View file

@ -10,7 +10,7 @@
use anyhow::Context;
use red_knot_python_semantic::PythonPlatform;
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use serde::Deserialize;
#[derive(Deserialize, Debug, Default, Clone)]

View file

@ -9,7 +9,7 @@ use ruff_db::files::{File, Files};
use ruff_db::system::{DbWithTestSystem, System, SystemPath, SystemPathBuf, TestSystem};
use ruff_db::vendored::VendoredFileSystem;
use ruff_db::{Db as SourceDb, Upcast};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
#[salsa::db]
#[derive(Clone)]

View file

@ -198,7 +198,7 @@ pub enum PythonVersion {
Py313,
}
impl From<PythonVersion> for ruff_python_ast::python_version::PythonVersion {
impl From<PythonVersion> for ruff_python_ast::PythonVersion {
fn from(value: PythonVersion) -> Self {
match value {
PythonVersion::Py37 => Self::PY37,
@ -308,8 +308,8 @@ mod tests {
#[test]
fn same_default_as_python_version() {
assert_eq!(
ruff_python_ast::python_version::PythonVersion::from(PythonVersion::default()),
ruff_python_ast::python_version::PythonVersion::default()
ruff_python_ast::PythonVersion::from(PythonVersion::default()),
ruff_python_ast::PythonVersion::default()
);
}
}

View file

@ -21,6 +21,7 @@ use ruff_linter::settings::types::{
PythonVersion, UnsafeFixes,
};
use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
use ruff_python_ast as ast;
use ruff_source_file::{LineIndex, OneIndexed};
use ruff_text_size::TextRange;
use ruff_workspace::configuration::{Configuration, RuleSelection};
@ -728,7 +729,7 @@ impl CheckCommand {
preview: resolve_bool_arg(self.preview, self.no_preview).map(PreviewMode::from),
respect_gitignore: resolve_bool_arg(self.respect_gitignore, self.no_respect_gitignore),
select: self.select,
target_version: self.target_version,
target_version: self.target_version.map(ast::PythonVersion::from),
unfixable: self.unfixable,
// TODO(charlie): Included in `pyproject.toml`, but not inherited.
cache_dir: self.cache_dir,
@ -770,7 +771,7 @@ impl FormatCommand {
exclude: self.exclude,
preview: resolve_bool_arg(self.preview, self.no_preview).map(PreviewMode::from),
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
target_version: self.target_version,
target_version: self.target_version.map(ast::PythonVersion::from),
cache_dir: self.cache_dir,
extension: self.extension,
..ExplicitConfigOverrides::default()
@ -800,7 +801,7 @@ impl AnalyzeGraphCommand {
None
},
preview: resolve_bool_arg(self.preview, self.no_preview).map(PreviewMode::from),
target_version: self.target_version,
target_version: self.target_version.map(ast::PythonVersion::from),
..ExplicitConfigOverrides::default()
};
@ -1264,7 +1265,7 @@ struct ExplicitConfigOverrides {
preview: Option<PreviewMode>,
respect_gitignore: Option<bool>,
select: Option<Vec<RuleSelector>>,
target_version: Option<PythonVersion>,
target_version: Option<ast::PythonVersion>,
unfixable: Option<Vec<RuleSelector>>,
// TODO(charlie): Captured in pyproject.toml as a default, but not part of `Settings`.
cache_dir: Option<PathBuf>,

View file

@ -189,7 +189,7 @@ linter.rules.should_fix = [
linter.per_file_ignores = {}
linter.safety_table.forced_safe = []
linter.safety_table.forced_unsafe = []
linter.target_version = Py37
linter.target_version = 3.7
linter.preview = disabled
linter.explicit_preview_rules = false
linter.extension = ExtensionMapping({})
@ -373,7 +373,7 @@ linter.ruff.allowed_markup_calls = []
# Formatter Settings
formatter.exclude = []
formatter.target_version = Py37
formatter.target_version = 3.7
formatter.preview = disabled
formatter.line_width = 100
formatter.line_ending = auto
@ -387,7 +387,7 @@ formatter.docstring_code_line_width = dynamic
# Analyze Settings
analyze.exclude = []
analyze.preview = disabled
analyze.target_version = Py37
analyze.target_version = 3.7
analyze.detect_string_imports = false
analyze.extension = ExtensionMapping({})
analyze.include_dependencies = {}

View file

@ -14,7 +14,7 @@ use ruff_db::diagnostic::{Diagnostic, DiagnosticId, Severity};
use ruff_db::files::{system_path_to_file, File};
use ruff_db::source::source_text;
use ruff_db::system::{MemoryFileSystem, SystemPath, SystemPathBuf, TestSystem};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
use rustc_hash::FxHashSet;
struct Case {

View file

@ -10,7 +10,7 @@ use ruff_db::files::{File, Files};
use ruff_db::system::{OsSystem, System, SystemPathBuf};
use ruff_db::vendored::{VendoredFileSystem, VendoredFileSystemBuilder};
use ruff_db::{Db as SourceDb, Upcast};
use ruff_python_ast::python_version::PythonVersion;
use ruff_python_ast::PythonVersion;
static EMPTY_VENDORED: std::sync::LazyLock<VendoredFileSystem> = std::sync::LazyLock::new(|| {
let mut builder = VendoredFileSystemBuilder::new(CompressionMethod::Stored);

View file

@ -1,6 +1,7 @@
use ruff_linter::display_settings;
use ruff_linter::settings::types::{ExtensionMapping, FilePatternSet, PreviewMode, PythonVersion};
use ruff_linter::settings::types::{ExtensionMapping, FilePatternSet, PreviewMode};
use ruff_macros::CacheKey;
use ruff_python_ast::PythonVersion;
use std::collections::BTreeMap;
use std::fmt;
use std::path::PathBuf;
@ -24,7 +25,7 @@ impl fmt::Display for AnalyzeSettings {
fields = [
self.exclude,
self.preview,
self.target_version | debug,
self.target_version,
self.detect_string_imports,
self.extension | debug,
self.include_dependencies | debug,

View file

@ -18,7 +18,7 @@ use crate::rules::{
flake8_simplify, flake8_tidy_imports, flake8_type_checking, flake8_use_pathlib, flynt, numpy,
pandas_vet, pep8_naming, pycodestyle, pyflakes, pylint, pyupgrade, refurb, ruff,
};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// Run lint rules over an [`Expr`] syntax node.
pub(crate) fn expression(expr: &Expr, checker: &Checker) {
@ -34,8 +34,8 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
{
if checker.enabled(Rule::FutureRewritableTypeAnnotation) {
if !checker.semantic.future_annotations_or_stub()
&& checker.settings.target_version < PythonVersion::Py310
&& checker.settings.target_version >= PythonVersion::Py37
&& checker.settings.target_version < PythonVersion::PY310
&& checker.settings.target_version >= PythonVersion::PY37
&& checker.semantic.in_annotation()
&& !checker.settings.pyupgrade.keep_runtime_typing
{
@ -49,8 +49,8 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
Rule::NonPEP604AnnotationOptional,
]) {
if checker.source_type.is_stub()
|| checker.settings.target_version >= PythonVersion::Py310
|| (checker.settings.target_version >= PythonVersion::Py37
|| checker.settings.target_version >= PythonVersion::PY310
|| (checker.settings.target_version >= PythonVersion::PY37
&& checker.semantic.future_annotations_or_stub()
&& checker.semantic.in_annotation()
&& !checker.settings.pyupgrade.keep_runtime_typing)
@ -64,7 +64,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
// Ex) list[...]
if checker.enabled(Rule::FutureRequiredTypeAnnotation) {
if !checker.semantic.future_annotations_or_stub()
&& checker.settings.target_version < PythonVersion::Py39
&& checker.settings.target_version < PythonVersion::PY39
&& checker.semantic.in_annotation()
&& checker.semantic.in_runtime_evaluated_annotation()
&& !checker.semantic.in_string_type_definition()
@ -135,7 +135,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
}
if checker.enabled(Rule::UnnecessaryDefaultTypeArgs) {
if checker.settings.target_version >= PythonVersion::Py313 {
if checker.settings.target_version >= PythonVersion::PY313 {
pyupgrade::rules::unnecessary_default_type_args(checker, expr);
}
}
@ -268,8 +268,8 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
{
if checker.enabled(Rule::FutureRewritableTypeAnnotation) {
if !checker.semantic.future_annotations_or_stub()
&& checker.settings.target_version < PythonVersion::Py39
&& checker.settings.target_version >= PythonVersion::Py37
&& checker.settings.target_version < PythonVersion::PY39
&& checker.settings.target_version >= PythonVersion::PY37
&& checker.semantic.in_annotation()
&& !checker.settings.pyupgrade.keep_runtime_typing
{
@ -278,8 +278,8 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
}
if checker.enabled(Rule::NonPEP585Annotation) {
if checker.source_type.is_stub()
|| checker.settings.target_version >= PythonVersion::Py39
|| (checker.settings.target_version >= PythonVersion::Py37
|| checker.settings.target_version >= PythonVersion::PY39
|| (checker.settings.target_version >= PythonVersion::PY37
&& checker.semantic.future_annotations_or_stub()
&& checker.semantic.in_annotation()
&& !checker.settings.pyupgrade.keep_runtime_typing)
@ -378,8 +378,8 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
if let Some(replacement) = typing::to_pep585_generic(expr, &checker.semantic) {
if checker.enabled(Rule::FutureRewritableTypeAnnotation) {
if !checker.semantic.future_annotations_or_stub()
&& checker.settings.target_version < PythonVersion::Py39
&& checker.settings.target_version >= PythonVersion::Py37
&& checker.settings.target_version < PythonVersion::PY39
&& checker.settings.target_version >= PythonVersion::PY37
&& checker.semantic.in_annotation()
&& !checker.settings.pyupgrade.keep_runtime_typing
{
@ -390,8 +390,8 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
}
if checker.enabled(Rule::NonPEP585Annotation) {
if checker.source_type.is_stub()
|| checker.settings.target_version >= PythonVersion::Py39
|| (checker.settings.target_version >= PythonVersion::Py37
|| checker.settings.target_version >= PythonVersion::PY39
|| (checker.settings.target_version >= PythonVersion::PY37
&& checker.semantic.future_annotations_or_stub()
&& checker.semantic.in_annotation()
&& !checker.settings.pyupgrade.keep_runtime_typing)
@ -405,7 +405,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
refurb::rules::regex_flag_alias(checker, expr);
}
if checker.enabled(Rule::DatetimeTimezoneUTC) {
if checker.settings.target_version >= PythonVersion::Py311 {
if checker.settings.target_version >= PythonVersion::PY311 {
pyupgrade::rules::datetime_utc_alias(checker, expr);
}
}
@ -610,12 +610,12 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
pyupgrade::rules::os_error_alias_call(checker, func);
}
if checker.enabled(Rule::TimeoutErrorAlias) {
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
pyupgrade::rules::timeout_error_alias_call(checker, func);
}
}
if checker.enabled(Rule::NonPEP604Isinstance) {
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
pyupgrade::rules::use_pep604_isinstance(checker, expr, func, args);
}
}
@ -690,7 +690,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
);
}
if checker.enabled(Rule::ZipWithoutExplicitStrict) {
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
flake8_bugbear::rules::zip_without_explicit_strict(checker, call);
}
}
@ -963,7 +963,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
flake8_pytest_style::rules::fail_call(checker, call);
}
if checker.enabled(Rule::ZipInsteadOfPairwise) {
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
ruff::rules::zip_instead_of_pairwise(checker, call);
}
}
@ -1385,7 +1385,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
// Ex) `str | None`
if checker.enabled(Rule::FutureRequiredTypeAnnotation) {
if !checker.semantic.future_annotations_or_stub()
&& checker.settings.target_version < PythonVersion::Py310
&& checker.settings.target_version < PythonVersion::PY310
&& checker.semantic.in_annotation()
&& checker.semantic.in_runtime_evaluated_annotation()
&& !checker.semantic.in_string_type_definition()

View file

@ -14,7 +14,7 @@ use crate::rules::{
flake8_slots, flake8_tidy_imports, flake8_type_checking, mccabe, pandas_vet, pep8_naming,
perflint, pycodestyle, pyflakes, pygrep_hooks, pylint, pyupgrade, refurb, ruff, tryceratops,
};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// Run lint rules over a [`Stmt`] syntax node.
pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
@ -165,7 +165,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
if checker.source_type.is_stub()
|| checker.settings.target_version >= PythonVersion::Py311
|| checker.settings.target_version >= PythonVersion::PY311
{
if checker.enabled(Rule::NoReturnArgumentAnnotationInStub) {
flake8_pyi::rules::no_return_argument_annotation(checker, parameters);
@ -194,12 +194,12 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pylint::rules::global_statement(checker, name);
}
if checker.enabled(Rule::LRUCacheWithoutParameters) {
if checker.settings.target_version >= PythonVersion::Py38 {
if checker.settings.target_version >= PythonVersion::PY38 {
pyupgrade::rules::lru_cache_without_parameters(checker, decorator_list);
}
}
if checker.enabled(Rule::LRUCacheWithMaxsizeNone) {
if checker.settings.target_version >= PythonVersion::Py39 {
if checker.settings.target_version >= PythonVersion::PY39 {
pyupgrade::rules::lru_cache_with_maxsize_none(checker, decorator_list);
}
}
@ -445,7 +445,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pyupgrade::rules::useless_object_inheritance(checker, class_def);
}
if checker.enabled(Rule::ReplaceStrEnum) {
if checker.settings.target_version >= PythonVersion::Py311 {
if checker.settings.target_version >= PythonVersion::PY311 {
pyupgrade::rules::replace_str_enum(checker, class_def);
}
}
@ -765,7 +765,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
if checker.enabled(Rule::UnnecessaryFutureImport) {
if checker.settings.target_version >= PythonVersion::Py37 {
if checker.settings.target_version >= PythonVersion::PY37 {
if let Some("__future__") = module {
pyupgrade::rules::unnecessary_future_import(checker, stmt, names);
}
@ -1039,7 +1039,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
if checker.enabled(Rule::TimeoutErrorAlias) {
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
if let Some(item) = exc {
pyupgrade::rules::timeout_error_alias_raise(checker, item);
}
@ -1431,7 +1431,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
flake8_bugbear::rules::jump_statement_in_finally(checker, finalbody);
}
if checker.enabled(Rule::ContinueInFinally) {
if checker.settings.target_version <= PythonVersion::Py38 {
if checker.settings.target_version <= PythonVersion::PY38 {
pylint::rules::continue_in_finally(checker, finalbody);
}
}
@ -1455,7 +1455,7 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
pyupgrade::rules::os_error_alias_handlers(checker, handlers);
}
if checker.enabled(Rule::TimeoutErrorAlias) {
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
pyupgrade::rules::timeout_error_alias_handlers(checker, handlers);
}
}

View file

@ -2115,7 +2115,7 @@ impl<'a> Checker<'a> {
};
let standard_builtins = python_builtins(
self.settings.target_version.minor(),
self.settings.target_version.minor,
self.source_type.is_ipynb(),
);
for builtin in standard_builtins {

View file

@ -399,7 +399,7 @@ impl ShadowedKind {
if is_python_builtin(
new_name,
checker.settings.target_version.minor(),
checker.settings.target_version.minor,
checker.source_type.is_ipynb(),
) {
return ShadowedKind::BuiltIn;

View file

@ -36,7 +36,7 @@ mod tests {
let diagnostics = test_path(
Path::new("fastapi").join(path).as_path(),
&settings::LinterSettings {
target_version: settings::types::PythonVersion::Py38,
target_version: ruff_python_ast::PythonVersion::PY38,
..settings::LinterSettings::for_rule(rule_code)
},
)?;

View file

@ -8,7 +8,7 @@ use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::rules::fastapi::rules::is_fastapi_route;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Identifies FastAPI routes with deprecated uses of `Depends` or similar.
@ -77,7 +77,7 @@ impl Violation for FastApiNonAnnotatedDependency {
}
fn fix_title(&self) -> Option<String> {
let title = if self.py_version >= PythonVersion::Py39 {
let title = if self.py_version >= PythonVersion::PY39 {
"Replace with `typing.Annotated`"
} else {
"Replace with `typing_extensions.Annotated`"
@ -232,7 +232,7 @@ fn create_diagnostic(
);
let try_generate_fix = || {
let module = if checker.settings.target_version >= PythonVersion::Py39 {
let module = if checker.settings.target_version >= PythonVersion::PY39 {
"typing"
} else {
"typing_extensions"

View file

@ -15,7 +15,7 @@ use ruff_python_semantic::{Definition, SemanticModel};
use ruff_text_size::{TextRange, TextSize};
use crate::importer::{ImportRequest, Importer};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// Return the name of the function, if it's overloaded.
pub(crate) fn overloaded_name<'a>(
@ -130,7 +130,7 @@ impl AutoPythonType {
.get_or_import_symbol(
&ImportRequest::import_from(
"typing",
if target_version >= PythonVersion::Py311 {
if target_version >= PythonVersion::PY311 {
"Never"
} else {
"NoReturn"
@ -152,7 +152,7 @@ impl AutoPythonType {
Some((expr, vec![]))
}
AutoPythonType::Union(python_types) => {
if target_version >= PythonVersion::Py310 {
if target_version >= PythonVersion::PY310 {
// Aggregate all the individual types (e.g., `int`, `float`).
let names = python_types
.iter()

View file

@ -11,9 +11,9 @@ mod tests {
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::types::PythonVersion;
use crate::settings::LinterSettings;
use crate::test::test_path;
use ruff_python_ast::PythonVersion;
#[test]
fn defaults() -> Result<()> {
@ -128,7 +128,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_annotations/auto_return_type.py"),
&LinterSettings {
target_version: PythonVersion::Py38,
target_version: PythonVersion::PY38,
..LinterSettings::for_rules(vec![
Rule::MissingReturnTypeUndocumentedPublicFunction,
Rule::MissingReturnTypePrivateFunction,

View file

@ -523,7 +523,7 @@ fn check_dynamically_typed<F>(
if type_hint_resolves_to_any(
parsed_annotation.expression(),
checker,
checker.settings.target_version.minor(),
checker.settings.target_version.minor,
) {
diagnostics.push(Diagnostic::new(
AnyType { name: func() },
@ -532,7 +532,7 @@ fn check_dynamically_typed<F>(
}
}
} else {
if type_hint_resolves_to_any(annotation, checker, checker.settings.target_version.minor()) {
if type_hint_resolves_to_any(annotation, checker, checker.settings.target_version.minor) {
diagnostics.push(Diagnostic::new(
AnyType { name: func() },
annotation.range(),

View file

@ -11,9 +11,9 @@ mod tests {
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::types::PythonVersion;
use crate::settings::LinterSettings;
use crate::test::test_path;
use ruff_python_ast::PythonVersion;
#[test_case(Rule::CancelScopeNoCheckpoint, Path::new("ASYNC100.py"))]
#[test_case(Rule::TrioSyncCall, Path::new("ASYNC105.py"))]
@ -44,7 +44,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_async").join(path),
&LinterSettings {
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..LinterSettings::for_rule(Rule::AsyncFunctionWithTimeout)
},
)?;

View file

@ -6,7 +6,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::rules::flake8_async::helpers::AsyncModule;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
#[allow(clippy::doc_link_with_quotes)]
/// ## What it does
@ -108,7 +108,7 @@ pub(crate) fn async_function_with_timeout(checker: &Checker, function_def: &ast:
};
// asyncio.timeout feature was first introduced in Python 3.11
if module == AsyncModule::AsyncIo && checker.settings.target_version < PythonVersion::Py311 {
if module == AsyncModule::AsyncIo && checker.settings.target_version < PythonVersion::PY311 {
return;
}

View file

@ -16,7 +16,7 @@ mod tests {
use crate::settings::LinterSettings;
use crate::test::test_path;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
#[test_case(Rule::AbstractBaseClassWithoutAbstractMethod, Path::new("B024.py"))]
#[test_case(Rule::AssertFalse, Path::new("B011.py"))]
@ -83,7 +83,7 @@ mod tests {
#[test_case(
Rule::ClassAsDataStructure,
Path::new("class_as_data_structure.py"),
PythonVersion::Py39
PythonVersion::PY39
)]
fn rules_with_target_version(
rule_code: Rule,
@ -93,8 +93,8 @@ mod tests {
let snapshot = format!(
"{}_py{}{}_{}",
rule_code.noqa_code(),
target_version.major(),
target_version.minor(),
target_version.major,
target_version.minor,
path.to_string_lossy(),
);
let diagnostics = test_path(

View file

@ -1,9 +1,9 @@
use crate::checkers::ast::Checker;
use crate::rules::flake8_bugbear::rules::is_infinite_iterable;
use crate::settings::types::PythonVersion;
use ruff_diagnostics::{Diagnostic, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::ExprCall;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for `itertools.batched` calls without an explicit `strict` parameter.
@ -59,7 +59,7 @@ impl Violation for BatchedWithoutExplicitStrict {
/// B911
pub(crate) fn batched_without_explicit_strict(checker: &Checker, call: &ExprCall) {
if checker.settings.target_version < PythonVersion::Py313 {
if checker.settings.target_version < PythonVersion::PY313 {
return;
}

View file

@ -5,7 +5,7 @@ use ruff_python_semantic::analyze::visibility::{self, Visibility::Public};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for classes that only have a public `__init__` method,
@ -78,7 +78,7 @@ pub(crate) fn class_as_data_structure(checker: &Checker, class_def: &ast::StmtCl
// skip `self`
.skip(1)
.all(|param| param.annotation().is_some() && !param.is_variadic())
&& (func_def.parameters.kwonlyargs.is_empty() || checker.settings.target_version >= PythonVersion::Py310)
&& (func_def.parameters.kwonlyargs.is_empty() || checker.settings.target_version >= PythonVersion::PY310)
// `__init__` should not have complicated logic in it
// only assignments
&& func_def

View file

@ -1,5 +1,5 @@
use crate::settings::types::PythonVersion;
use ruff_python_ast::PySourceType;
use ruff_python_ast::PythonVersion;
use ruff_python_stdlib::builtins::is_python_builtin;
pub(super) fn shadows_builtin(
@ -8,7 +8,7 @@ pub(super) fn shadows_builtin(
ignorelist: &[String],
python_version: PythonVersion,
) -> bool {
if is_python_builtin(name, python_version.minor(), source_type.is_ipynb()) {
if is_python_builtin(name, python_version.minor, source_type.is_ipynb()) {
ignorelist.iter().all(|ignore| ignore != name)
} else {
false

View file

@ -13,9 +13,9 @@ mod tests {
use crate::assert_messages;
use crate::registry::Rule;
use crate::rules::flake8_builtins;
use crate::settings::types::PythonVersion;
use crate::settings::LinterSettings;
use crate::test::{test_path, test_resource_path};
use ruff_python_ast::PythonVersion;
#[test_case(Rule::BuiltinVariableShadowing, Path::new("A001.py"))]
#[test_case(Rule::BuiltinArgumentShadowing, Path::new("A002.py"))]
@ -217,7 +217,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_builtins").join(path).as_path(),
&LinterSettings {
target_version: PythonVersion::Py38,
target_version: PythonVersion::PY38,
..LinterSettings::for_rule(rule_code)
},
)?;

View file

@ -145,5 +145,5 @@ fn is_allowed_module(settings: &LinterSettings, module: &str) -> bool {
return true;
}
!is_known_standard_library(settings.target_version.minor(), module)
!is_known_standard_library(settings.target_version.minor, module)
}

View file

@ -9,9 +9,9 @@ mod tests {
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::PythonVersion;
use crate::test::test_path;
use crate::{assert_messages, settings};
use ruff_python_ast::PythonVersion;
#[test_case(Path::new("edge_case.py"))]
#[test_case(Path::new("from_typing_import.py"))]
@ -30,7 +30,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_future_annotations").join(path).as_path(),
&settings::LinterSettings {
target_version: PythonVersion::Py37,
target_version: PythonVersion::PY37,
..settings::LinterSettings::for_rule(Rule::FutureRewritableTypeAnnotation)
},
)?;
@ -49,7 +49,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_future_annotations").join(path).as_path(),
&settings::LinterSettings {
target_version: PythonVersion::Py37,
target_version: PythonVersion::PY37,
..settings::LinterSettings::for_rule(Rule::FutureRequiredTypeAnnotation)
},
)?;

View file

@ -6,11 +6,12 @@ mod tests {
use std::path::Path;
use anyhow::Result;
use ruff_python_ast::PythonVersion;
use test_case::test_case;
use crate::registry::Rule;
use crate::rules::pep8_naming;
use crate::settings::types::{PreviewMode, PythonVersion};
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@ -188,7 +189,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_pyi").join(path).as_path(),
&settings::LinterSettings {
target_version: PythonVersion::Py38,
target_version: PythonVersion::PY38,
..settings::LinterSettings::for_rule(rule_code)
},
)?;

View file

@ -12,7 +12,7 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::checkers::ast::Checker;
use crate::importer::{ImportRequest, ResolutionError};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for methods that use custom [`TypeVar`s][typing_TypeVar] in their
@ -560,7 +560,7 @@ fn replace_custom_typevar_with_self(
/// This is because it was added to the `typing` module on Python 3.11,
/// but is available from the backport package `typing_extensions` on all versions.
fn import_self(checker: &Checker, position: TextSize) -> Result<(Edit, String), ResolutionError> {
let source_module = if checker.settings.target_version >= PythonVersion::Py311 {
let source_module = if checker.settings.target_version >= PythonVersion::PY311 {
"typing"
} else {
"typing_extensions"

View file

@ -6,7 +6,7 @@ use ruff_python_ast as ast;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion::Py311;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for uses of `typing.NoReturn` (and `typing_extensions.NoReturn`) for
@ -67,7 +67,7 @@ pub(crate) fn no_return_argument_annotation(checker: &Checker, parameters: &ast:
if is_no_return(annotation, checker) {
checker.report_diagnostic(Diagnostic::new(
NoReturnArgumentAnnotationInStub {
module: if checker.settings.target_version >= Py311 {
module: if checker.settings.target_version >= PythonVersion::PY311 {
TypingModule::Typing
} else {
TypingModule::TypingExtensions

View file

@ -1,11 +1,11 @@
use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::settings::types::PythonVersion;
use ruff_diagnostics::{Applicability, Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast as ast;
use ruff_python_ast::helpers::map_subscript;
use ruff_python_ast::identifier::Identifier;
use ruff_python_ast::PythonVersion;
use ruff_python_semantic::analyze;
use ruff_python_semantic::analyze::class::might_be_generic;
use ruff_python_semantic::analyze::visibility::{is_abstract, is_final, is_overload};
@ -215,7 +215,7 @@ fn replace_with_self_fix(
let semantic = checker.semantic();
let (self_import, self_binding) = {
let source_module = if checker.settings.target_version >= PythonVersion::Py311 {
let source_module = if checker.settings.target_version >= PythonVersion::PY311 {
"typing"
} else {
"typing_extensions"

View file

@ -5,7 +5,7 @@ use ruff_python_ast::{self as ast, ParameterWithDefault};
use ruff_python_semantic::analyze::function_type;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for the presence of [PEP 484]-style positional-only parameters.
@ -56,7 +56,7 @@ impl Violation for Pep484StylePositionalOnlyParameter {
/// PYI063
pub(crate) fn pep_484_positional_parameter(checker: &Checker, function_def: &ast::StmtFunctionDef) {
// PEP 570 was introduced in Python 3.8.
if checker.settings.target_version < PythonVersion::Py38 {
if checker.settings.target_version < PythonVersion::PY38 {
return;
}

View file

@ -5,14 +5,14 @@ use ruff_python_ast::{
self as ast,
helpers::{pep_604_union, typing_optional},
name::Name,
Expr, ExprBinOp, ExprContext, ExprNoneLiteral, ExprSubscript, Operator,
Expr, ExprBinOp, ExprContext, ExprNoneLiteral, ExprSubscript, Operator, PythonVersion,
};
use ruff_python_semantic::analyze::typing::{traverse_literal, traverse_union};
use ruff_text_size::{Ranged, TextRange};
use smallvec::SmallVec;
use crate::{checkers::ast::Checker, importer::ImportRequest, settings::types::PythonVersion};
use crate::{checkers::ast::Checker, importer::ImportRequest};
/// ## What it does
/// Checks for redundant `Literal[None]` annotations.
@ -112,7 +112,7 @@ pub(crate) fn redundant_none_literal<'a>(checker: &Checker, literal_expr: &'a Ex
let union_kind = if literal_elements.is_empty() {
UnionKind::NoUnion
} else if (checker.settings.target_version >= PythonVersion::Py310)
} else if (checker.settings.target_version >= PythonVersion::PY310)
|| checker.source_type.is_stub()
{
UnionKind::BitOr

View file

@ -8,8 +8,8 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::rules::flake8_pyi::rules::TypingModule;
use crate::settings::types::PythonVersion;
use crate::Locator;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for typed function arguments in stubs with complex default values.
@ -667,7 +667,7 @@ pub(crate) fn type_alias_without_annotation(checker: &Checker, value: &Expr, tar
return;
}
let module = if checker.settings.target_version >= PythonVersion::Py310 {
let module = if checker.settings.target_version >= PythonVersion::PY310 {
TypingModule::Typing
} else {
TypingModule::TypingExtensions

View file

@ -12,9 +12,9 @@ mod tests {
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::types::PythonVersion;
use crate::settings::LinterSettings;
use crate::test::test_path;
use ruff_python_ast::PythonVersion;
use super::settings::Quote;
@ -62,7 +62,7 @@ mod tests {
avoid_escape: true,
},
..LinterSettings::for_rule(Rule::AvoidableEscapedQuote)
.with_target_version(PythonVersion::Py311)
.with_target_version(PythonVersion::PY311)
},
)?;
assert_messages!(diagnostics);
@ -81,7 +81,7 @@ mod tests {
avoid_escape: true,
},
..LinterSettings::for_rule(Rule::AvoidableEscapedQuote)
.with_target_version(PythonVersion::Py311)
.with_target_version(PythonVersion::PY311)
},
)?;
assert_messages!(diagnostics);

View file

@ -92,7 +92,7 @@ impl<'a> AvoidableEscapedQuoteChecker<'a> {
Self {
locator,
quotes_settings: &settings.flake8_quotes,
supports_pep701: settings.target_version.supports_pep701(),
supports_pep701: settings.target_version.supports_pep_701(),
diagnostics: vec![],
}
}

View file

@ -10,6 +10,7 @@ mod tests {
use std::path::Path;
use anyhow::Result;
use ruff_python_ast::PythonVersion;
use test_case::test_case;
use crate::registry::{Linter, Rule};
@ -91,7 +92,7 @@ mod tests {
let diagnostics = test_path(
Path::new("flake8_type_checking").join(path).as_path(),
&settings::LinterSettings {
target_version: settings::types::PythonVersion::Py39,
target_version: PythonVersion::PY39,
..settings::LinterSettings::for_rule(rule_code)
},
)?;

View file

@ -10,8 +10,8 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::registry::Rule;
use crate::rules::flake8_type_checking::helpers::quote_type_expression;
use crate::settings::types::PythonVersion;
use crate::settings::LinterSettings;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks if [PEP 613] explicit type aliases contain references to
@ -313,7 +313,7 @@ fn quotes_are_unremovable(
}) => {
match op {
Operator::BitOr => {
if settings.target_version < PythonVersion::Py310 {
if settings.target_version < PythonVersion::PY310 {
return true;
}
quotes_are_unremovable(semantic, left, settings)

View file

@ -15,7 +15,7 @@ use crate::rules::flake8_use_pathlib::violations::{
OsPathIsfile, OsPathIslink, OsPathJoin, OsPathSamefile, OsPathSplitext, OsReadlink, OsRemove,
OsRename, OsReplace, OsRmdir, OsStat, OsUnlink, PyPath,
};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
pub(crate) fn replaceable_by_pathlib(checker: &Checker, call: &ExprCall) {
if let Some(diagnostic_kind) = checker
@ -152,7 +152,7 @@ pub(crate) fn replaceable_by_pathlib(checker: &Checker, call: &ExprCall) {
),
// PTH115
// Python 3.9+
["os", "readlink"] if checker.settings.target_version >= PythonVersion::Py39 => {
["os", "readlink"] if checker.settings.target_version >= PythonVersion::PY39 => {
Some(OsReadlink.into())
}
// PTH208,

View file

@ -9,9 +9,9 @@ use serde::{Deserialize, Serialize};
use strum_macros::EnumIter;
use crate::package::PackageRoot;
use crate::settings::types::PythonVersion;
use crate::warn_user_once;
use ruff_macros::CacheKey;
use ruff_python_ast::PythonVersion;
use ruff_python_stdlib::sys::is_known_standard_library;
use super::types::{ImportBlock, Importable};
@ -117,7 +117,7 @@ pub(crate) fn categorize<'a>(
)
} else if let Some((import_type, reason)) = known_modules.categorize(module_name) {
(import_type, reason)
} else if is_known_standard_library(target_version.minor(), module_base) {
} else if is_known_standard_library(target_version.minor, module_base) {
(
&ImportSection::Known(ImportType::StandardLibrary),
Reason::KnownStandardLibrary,

View file

@ -19,8 +19,8 @@ use types::{AliasData, ImportBlock, TrailingComma};
use crate::line_width::{LineLength, LineWidthBuilder};
use crate::package::PackageRoot;
use crate::settings::types::PythonVersion;
use crate::Locator;
use ruff_python_ast::PythonVersion;
mod annotate;
pub(crate) mod block;

View file

@ -6,11 +6,12 @@ mod tests {
use std::path::Path;
use anyhow::Result;
use ruff_python_ast::PythonVersion;
use test_case::test_case;
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::types::{PreviewMode, PythonVersion};
use crate::settings::types::PreviewMode;
use crate::settings::LinterSettings;
use crate::test::test_path;
@ -24,7 +25,7 @@ mod tests {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Path::new("perflint").join(path).as_path(),
&LinterSettings::for_rule(rule_code).with_target_version(PythonVersion::Py310),
&LinterSettings::for_rule(rule_code).with_target_version(PythonVersion::PY310),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
@ -42,7 +43,7 @@ mod tests {
Path::new("perflint").join(path).as_path(),
&LinterSettings {
preview: PreviewMode::Enabled,
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..LinterSettings::for_rule(rule_code)
},
)?;

View file

@ -5,7 +5,7 @@ use ruff_python_ast::{self as ast, Stmt};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for uses of except handling via `try`-`except` within `for` and
@ -89,7 +89,7 @@ impl Violation for TryExceptInLoop {
/// PERF203
pub(crate) fn try_except_in_loop(checker: &Checker, body: &[Stmt]) {
if checker.settings.target_version >= PythonVersion::Py311 {
if checker.settings.target_version >= PythonVersion::PY311 {
return;
}

View file

@ -218,7 +218,7 @@ mod tests {
let diagnostics = test_snippet(
"PythonFinalizationError",
&LinterSettings {
target_version: crate::settings::types::PythonVersion::Py312,
target_version: ruff_python_ast::PythonVersion::PY312,
..LinterSettings::for_rule(Rule::UndefinedName)
},
);

View file

@ -9,13 +9,14 @@ mod tests {
use anyhow::Result;
use regex::Regex;
use ruff_python_ast::PythonVersion;
use rustc_hash::FxHashSet;
use test_case::test_case;
use crate::registry::Rule;
use crate::rules::{flake8_tidy_imports, pylint};
use crate::settings::types::{PreviewMode, PythonVersion};
use crate::settings::types::PreviewMode;
use crate::settings::LinterSettings;
use crate::test::test_path;
use crate::{assert_messages, settings};
@ -249,7 +250,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pylint/continue_in_finally.py"),
&LinterSettings::for_rule(Rule::ContinueInFinally)
.with_target_version(PythonVersion::Py37),
.with_target_version(PythonVersion::PY37),
)?;
assert_messages!(diagnostics);
Ok(())

View file

@ -10,7 +10,7 @@ use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks duplicate characters in `str.strip` calls.
@ -211,7 +211,7 @@ pub(crate) fn bad_str_strip_call(checker: &Checker, call: &ast::ExprCall) {
return;
}
let removal = if checker.settings.target_version >= PythonVersion::Py39 {
let removal = if checker.settings.target_version >= PythonVersion::PY39 {
RemovalKind::for_strip(strip)
} else {
None

View file

@ -6,7 +6,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::rules::pylint::helpers::is_known_dunder_method;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for explicit use of dunder methods, like `__str__` and `__add__`.
@ -248,7 +248,7 @@ fn allowed_dunder_constants(dunder_method: &str, target_version: PythonVersion)
return true;
}
if target_version < PythonVersion::Py310 && matches!(dunder_method, "__aiter__" | "__anext__") {
if target_version < PythonVersion::PY310 && matches!(dunder_method, "__aiter__" | "__anext__") {
return true;
}

View file

@ -6,7 +6,7 @@ use ruff_python_stdlib::builtins;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for an exception that is not raised.
@ -75,6 +75,6 @@ fn is_builtin_exception(
.resolve_qualified_name(expr)
.is_some_and(|qualified_name| {
matches!(qualified_name.segments(), ["" | "builtins", name]
if builtins::is_exception(name, target_version.minor()))
if builtins::is_exception(name, target_version.minor))
})
}

View file

@ -10,11 +10,12 @@ mod tests {
use std::path::Path;
use anyhow::Result;
use ruff_python_ast::PythonVersion;
use test_case::test_case;
use crate::registry::Rule;
use crate::rules::pyupgrade;
use crate::settings::types::{PreviewMode, PythonVersion};
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@ -155,7 +156,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/UP041.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..settings::LinterSettings::for_rule(Rule::TimeoutErrorAlias)
},
)?;
@ -168,7 +169,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/UP040.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py311,
target_version: PythonVersion::PY311,
..settings::LinterSettings::for_rule(Rule::NonPEP695TypeAlias)
},
)?;
@ -184,7 +185,7 @@ mod tests {
pyupgrade: pyupgrade::settings::Settings {
keep_runtime_typing: true,
},
target_version: PythonVersion::Py37,
target_version: PythonVersion::PY37,
..settings::LinterSettings::for_rule(Rule::NonPEP585Annotation)
},
)?;
@ -200,7 +201,7 @@ mod tests {
pyupgrade: pyupgrade::settings::Settings {
keep_runtime_typing: true,
},
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..settings::LinterSettings::for_rule(Rule::NonPEP585Annotation)
},
)?;
@ -213,7 +214,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/future_annotations.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py37,
target_version: PythonVersion::PY37,
..settings::LinterSettings::for_rule(Rule::NonPEP585Annotation)
},
)?;
@ -226,7 +227,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/future_annotations.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..settings::LinterSettings::for_rule(Rule::NonPEP585Annotation)
},
)?;
@ -239,7 +240,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/future_annotations.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py37,
target_version: PythonVersion::PY37,
..settings::LinterSettings::for_rules([
Rule::NonPEP604AnnotationUnion,
Rule::NonPEP604AnnotationOptional,
@ -255,7 +256,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/future_annotations.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..settings::LinterSettings::for_rules([
Rule::NonPEP604AnnotationUnion,
Rule::NonPEP604AnnotationOptional,
@ -271,7 +272,7 @@ mod tests {
let diagnostics = test_path(
Path::new("pyupgrade/UP017.py"),
&settings::LinterSettings {
target_version: PythonVersion::Py311,
target_version: PythonVersion::PY311,
..settings::LinterSettings::for_rule(Rule::DatetimeTimezoneUTC)
},
)?;
@ -285,7 +286,7 @@ mod tests {
Path::new("pyupgrade/UP044.py"),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
target_version: PythonVersion::Py311,
target_version: PythonVersion::PY311,
..settings::LinterSettings::for_rule(Rule::NonPEP646Unpack)
},
)?;

View file

@ -10,8 +10,8 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::rules::pyupgrade::fixes;
use crate::settings::types::PythonVersion;
use crate::Locator;
use ruff_python_ast::PythonVersion;
/// An import was moved and renamed as part of a deprecation.
/// For example, `typing.AbstractSet` was moved to `collections.abc.Set`.
@ -432,7 +432,7 @@ impl<'a> ImportReplacer<'a> {
fn with_renames(&self) -> Vec<WithRename> {
let mut operations = vec![];
if self.module == "typing" {
if self.version >= PythonVersion::Py39 {
if self.version >= PythonVersion::PY39 {
for member in &self.import_from_stmt.names {
if let Some(target) = TYPING_TO_RENAME_PY39.iter().find_map(|(name, target)| {
if &member.name == *name {
@ -470,7 +470,7 @@ impl<'a> ImportReplacer<'a> {
"typing_extensions" => {
// `typing_extensions` to `collections.abc`
let mut typing_extensions_to_collections_abc = vec![];
if self.version >= PythonVersion::Py312 {
if self.version >= PythonVersion::PY312 {
typing_extensions_to_collections_abc
.extend(TYPING_EXTENSIONS_TO_COLLECTIONS_ABC_312);
}
@ -482,7 +482,7 @@ impl<'a> ImportReplacer<'a> {
// `typing_extensions` to `warnings`
let mut typing_extensions_to_warnings = vec![];
if self.version >= PythonVersion::Py313 {
if self.version >= PythonVersion::PY313 {
typing_extensions_to_warnings.extend(TYPING_EXTENSIONS_TO_WARNINGS_313);
}
if let Some(operation) =
@ -493,10 +493,10 @@ impl<'a> ImportReplacer<'a> {
// `typing_extensions` to `types`
let mut typing_extensions_to_types = vec![];
if self.version >= PythonVersion::Py312 {
if self.version >= PythonVersion::PY312 {
typing_extensions_to_types.extend(TYPING_EXTENSIONS_TO_TYPES_312);
}
if self.version >= PythonVersion::Py313 {
if self.version >= PythonVersion::PY313 {
typing_extensions_to_types.extend(TYPING_EXTENSIONS_TO_TYPES_313);
}
if let Some(operation) = self.try_replace(&typing_extensions_to_types, "types") {
@ -505,25 +505,25 @@ impl<'a> ImportReplacer<'a> {
// `typing_extensions` to `typing`
let mut typing_extensions_to_typing = TYPING_EXTENSIONS_TO_TYPING.to_vec();
if self.version >= PythonVersion::Py37 {
if self.version >= PythonVersion::PY37 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_37);
}
if self.version >= PythonVersion::Py38 {
if self.version >= PythonVersion::PY38 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_38);
}
if self.version >= PythonVersion::Py39 {
if self.version >= PythonVersion::PY39 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_39);
}
if self.version >= PythonVersion::Py310 {
if self.version >= PythonVersion::PY310 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_310);
}
if self.version >= PythonVersion::Py311 {
if self.version >= PythonVersion::PY311 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_311);
}
if self.version >= PythonVersion::Py312 {
if self.version >= PythonVersion::PY312 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_312);
}
if self.version >= PythonVersion::Py313 {
if self.version >= PythonVersion::PY313 {
typing_extensions_to_typing.extend(TYPING_EXTENSIONS_TO_TYPING_313);
}
if let Some(operation) = self.try_replace(&typing_extensions_to_typing, "typing") {
@ -532,10 +532,10 @@ impl<'a> ImportReplacer<'a> {
}
"mypy_extensions" => {
let mut mypy_extensions_to_typing = vec![];
if self.version >= PythonVersion::Py37 {
if self.version >= PythonVersion::PY37 {
mypy_extensions_to_typing.extend(MYPY_EXTENSIONS_TO_TYPING_37);
}
if self.version >= PythonVersion::Py38 {
if self.version >= PythonVersion::PY38 {
mypy_extensions_to_typing.extend(MYPY_EXTENSIONS_TO_TYPING_38);
}
if let Some(operation) = self.try_replace(&mypy_extensions_to_typing, "typing") {
@ -545,10 +545,10 @@ impl<'a> ImportReplacer<'a> {
"typing" => {
// `typing` to `collections.abc`
let mut typing_to_collections_abc = vec![];
if self.version >= PythonVersion::Py39 {
if self.version >= PythonVersion::PY39 {
typing_to_collections_abc.extend(TYPING_TO_COLLECTIONS_ABC_39);
}
if self.version >= PythonVersion::Py310 {
if self.version >= PythonVersion::PY310 {
typing_to_collections_abc.extend(TYPING_TO_COLLECTIONS_ABC_310);
}
if let Some(operation) =
@ -559,7 +559,7 @@ impl<'a> ImportReplacer<'a> {
// `typing` to `collections`
let mut typing_to_collections = vec![];
if self.version >= PythonVersion::Py39 {
if self.version >= PythonVersion::PY39 {
typing_to_collections.extend(TYPING_TO_COLLECTIONS_39);
}
if let Some(operation) = self.try_replace(&typing_to_collections, "collections") {
@ -568,19 +568,19 @@ impl<'a> ImportReplacer<'a> {
// `typing` to `re`
let mut typing_to_re = vec![];
if self.version >= PythonVersion::Py39 {
if self.version >= PythonVersion::PY39 {
typing_to_re.extend(TYPING_TO_RE_39);
}
if let Some(operation) = self.try_replace(&typing_to_re, "re") {
operations.push(operation);
}
}
"typing.re" if self.version >= PythonVersion::Py39 => {
"typing.re" if self.version >= PythonVersion::PY39 => {
if let Some(operation) = self.try_replace(TYPING_RE_TO_RE_39, "re") {
operations.push(operation);
}
}
"backports.strenum" if self.version >= PythonVersion::Py311 => {
"backports.strenum" if self.version >= PythonVersion::PY311 => {
if let Some(operation) = self.try_replace(BACKPORTS_STR_ENUM_TO_ENUM_311, "enum") {
operations.push(operation);
}

View file

@ -13,7 +13,7 @@ use ruff_text_size::{Ranged, TextLen, TextRange};
use crate::checkers::ast::Checker;
use crate::fix::edits::{adjust_indentation, delete_stmt};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for conditional blocks gated on `sys.version_info` comparisons
@ -456,17 +456,17 @@ mod tests {
use super::*;
#[test_case(PythonVersion::Py37, & [2], true, true; "compare-2.0")]
#[test_case(PythonVersion::Py37, & [2, 0], true, true; "compare-2.0-whole")]
#[test_case(PythonVersion::Py37, & [3], true, true; "compare-3.0")]
#[test_case(PythonVersion::Py37, & [3, 0], true, true; "compare-3.0-whole")]
#[test_case(PythonVersion::Py37, & [3, 1], true, true; "compare-3.1")]
#[test_case(PythonVersion::Py37, & [3, 5], true, true; "compare-3.5")]
#[test_case(PythonVersion::Py37, & [3, 7], true, false; "compare-3.7")]
#[test_case(PythonVersion::Py37, & [3, 7], false, true; "compare-3.7-not-equal")]
#[test_case(PythonVersion::Py37, & [3, 8], false, false; "compare-3.8")]
#[test_case(PythonVersion::Py310, & [3, 9], true, true; "compare-3.9")]
#[test_case(PythonVersion::Py310, & [3, 11], true, false; "compare-3.11")]
#[test_case(PythonVersion::PY37, & [2], true, true; "compare-2.0")]
#[test_case(PythonVersion::PY37, & [2, 0], true, true; "compare-2.0-whole")]
#[test_case(PythonVersion::PY37, & [3], true, true; "compare-3.0")]
#[test_case(PythonVersion::PY37, & [3, 0], true, true; "compare-3.0-whole")]
#[test_case(PythonVersion::PY37, & [3, 1], true, true; "compare-3.1")]
#[test_case(PythonVersion::PY37, & [3, 5], true, true; "compare-3.5")]
#[test_case(PythonVersion::PY37, & [3, 7], true, false; "compare-3.7")]
#[test_case(PythonVersion::PY37, & [3, 7], false, true; "compare-3.7-not-equal")]
#[test_case(PythonVersion::PY37, & [3, 8], false, false; "compare-3.8")]
#[test_case(PythonVersion::PY310, & [3, 9], true, true; "compare-3.9")]
#[test_case(PythonVersion::PY310, & [3, 11], true, false; "compare-3.11")]
fn test_compare_version(
version: PythonVersion,
target_versions: &[u8],

View file

@ -6,7 +6,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::fix::edits::{remove_argument, Parentheses};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
use super::{
check_type_vars, find_generic, in_nested_context, DisplayTypeVars, TypeVarReferenceVisitor,
@ -106,7 +106,7 @@ impl Violation for NonPEP695GenericClass {
/// UP046
pub(crate) fn non_pep695_generic_class(checker: &Checker, class_def: &StmtClassDef) {
// PEP-695 syntax is only available on Python 3.12+
if checker.settings.target_version < PythonVersion::Py312 {
if checker.settings.target_version < PythonVersion::PY312 {
return;
}

View file

@ -5,7 +5,7 @@ use ruff_python_ast::StmtFunctionDef;
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
use super::{check_type_vars, in_nested_context, DisplayTypeVars, TypeVarReferenceVisitor};
@ -98,7 +98,7 @@ impl Violation for NonPEP695GenericFunction {
/// UP047
pub(crate) fn non_pep695_generic_function(checker: &Checker, function_def: &StmtFunctionDef) {
// PEP-695 syntax is only available on Python 3.12+
if checker.settings.target_version < PythonVersion::Py312 {
if checker.settings.target_version < PythonVersion::PY312 {
return;
}

View file

@ -9,7 +9,7 @@ use ruff_python_ast::{Expr, ExprCall, ExprName, Keyword, StmtAnnAssign, StmtAssi
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
use super::{
expr_name_to_type_var, DisplayTypeVars, TypeParamKind, TypeVar, TypeVarReferenceVisitor,
@ -111,7 +111,7 @@ impl Violation for NonPEP695TypeAlias {
/// UP040
pub(crate) fn non_pep695_type_alias_type(checker: &Checker, stmt: &StmtAssign) {
if checker.settings.target_version < PythonVersion::Py312 {
if checker.settings.target_version < PythonVersion::PY312 {
return;
}
@ -182,7 +182,7 @@ pub(crate) fn non_pep695_type_alias_type(checker: &Checker, stmt: &StmtAssign) {
/// UP040
pub(crate) fn non_pep695_type_alias(checker: &Checker, stmt: &StmtAnnAssign) {
if checker.settings.target_version < PythonVersion::Py312 {
if checker.settings.target_version < PythonVersion::PY312 {
return;
}

View file

@ -8,7 +8,7 @@ use ruff_python_ast::name::{Name, UnqualifiedName};
use ruff_python_semantic::SemanticModel;
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for uses of exceptions that alias `TimeoutError`.
@ -62,7 +62,7 @@ fn is_alias(expr: &Expr, semantic: &SemanticModel, target_version: PythonVersion
semantic
.resolve_qualified_name(expr)
.is_some_and(|qualified_name| {
if target_version >= PythonVersion::Py311 {
if target_version >= PythonVersion::PY311 {
matches!(
qualified_name.segments(),
["socket", "timeout"] | ["asyncio", "TimeoutError"]
@ -73,7 +73,7 @@ fn is_alias(expr: &Expr, semantic: &SemanticModel, target_version: PythonVersion
// fix in Python <3.10. We add an assert to make this assumption
// explicit.
assert!(
target_version >= PythonVersion::Py310,
target_version >= PythonVersion::PY310,
"lint should only be used for Python 3.10+",
);
matches!(qualified_name.segments(), ["socket", "timeout"])

View file

@ -8,7 +8,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for the use of generics that can be replaced with standard library
@ -98,7 +98,7 @@ pub(crate) fn use_pep585_annotation(checker: &Checker, expr: &Expr, replacement:
checker.semantic(),
)?;
let binding_edit = Edit::range_replacement(binding, expr.range());
let applicability = if checker.settings.target_version >= PythonVersion::Py310 {
let applicability = if checker.settings.target_version >= PythonVersion::PY310 {
Applicability::Safe
} else {
Applicability::Unsafe
@ -122,7 +122,7 @@ pub(crate) fn use_pep585_annotation(checker: &Checker, expr: &Expr, replacement:
Ok(Fix::applicable_edits(
import_edit,
[reference_edit],
if checker.settings.target_version >= PythonVersion::Py310 {
if checker.settings.target_version >= PythonVersion::PY310 {
Applicability::Safe
} else {
Applicability::Unsafe

View file

@ -3,6 +3,7 @@ use ruff_diagnostics::{
};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::helpers::{pep_604_optional, pep_604_union};
use ruff_python_ast::PythonVersion;
use ruff_python_ast::{self as ast, Expr};
use ruff_python_semantic::analyze::typing::Pep604Operator;
use ruff_text_size::Ranged;
@ -10,7 +11,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::codes::Rule;
use crate::fix::edits::pad;
use crate::settings::types::{PreviewMode, PythonVersion};
use crate::settings::types::PreviewMode;
/// ## What it does
/// Check for type annotations that can be rewritten based on [PEP 604] syntax.
@ -141,7 +142,7 @@ pub(crate) fn non_pep604_annotation(
&& !checker.semantic().in_complex_string_type_definition()
&& is_allowed_value(slice);
let applicability = if checker.settings.target_version >= PythonVersion::Py310 {
let applicability = if checker.settings.target_version >= PythonVersion::PY310 {
Applicability::Safe
} else {
Applicability::Unsafe

View file

@ -1,9 +1,9 @@
use ruff_diagnostics::{Diagnostic, Edit, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::{Expr, ExprSubscript};
use ruff_python_ast::{Expr, ExprSubscript, PythonVersion};
use ruff_python_semantic::SemanticModel;
use crate::{checkers::ast::Checker, settings::types::PythonVersion};
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for uses of `Unpack[]` on Python 3.11 and above, and suggests
@ -53,7 +53,7 @@ impl Violation for NonPEP646Unpack {
/// UP044
pub(crate) fn use_pep646_unpack(checker: &Checker, expr: &ExprSubscript) {
if checker.settings.target_version < PythonVersion::Py311 {
if checker.settings.target_version < PythonVersion::PY311 {
return;
}

View file

@ -6,7 +6,7 @@ use ruff_python_semantic::{BindingId, ResolvedReference, SemanticModel};
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// Format a code snippet to call `name.method()`.
pub(super) fn generate_method_call(name: Name, method: &str, generator: Generator) -> String {
@ -260,7 +260,7 @@ fn match_open_keywords(
if read_mode {
// newline is only valid for write_text
return None;
} else if target_version < PythonVersion::Py310 {
} else if target_version < PythonVersion::PY310 {
// `pathlib` doesn't support `newline` until Python 3.10.
return None;
}

View file

@ -8,10 +8,11 @@ mod tests {
use std::path::Path;
use anyhow::Result;
use ruff_python_ast::PythonVersion;
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::{PreviewMode, PythonVersion};
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@ -84,7 +85,7 @@ mod tests {
let diagnostics = test_path(
Path::new("refurb/FURB103.py"),
&settings::LinterSettings::for_rule(Rule::WriteWholeFile)
.with_target_version(PythonVersion::Py39),
.with_target_version(PythonVersion::PY39),
)?;
assert_messages!(diagnostics);
Ok(())

View file

@ -1,10 +1,11 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::PythonVersion;
use ruff_python_ast::{self as ast, Expr, ExprAttribute, ExprCall};
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::fix::snippet::SourceCodeSnippet;
use crate::{checkers::ast::Checker, settings::types::PythonVersion};
/// ## What it does
/// Checks for uses of `bin(...).count("1")` to perform a population count.
@ -58,7 +59,7 @@ impl AlwaysFixableViolation for BitCount {
/// FURB161
pub(crate) fn bit_count(checker: &Checker, call: &ExprCall) {
// `int.bit_count()` was added in Python 3.10
if checker.settings.target_version < PythonVersion::Py310 {
if checker.settings.target_version < PythonVersion::PY310 {
return;
}

View file

@ -3,13 +3,12 @@ use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::parenthesize::parenthesized_range;
use ruff_python_ast::{
Expr, ExprAttribute, ExprBinOp, ExprCall, ExprStringLiteral, ExprSubscript, ExprUnaryOp,
Number, Operator, UnaryOp,
Number, Operator, PythonVersion, UnaryOp,
};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::settings::types::PythonVersion;
/// ## What it does
/// Checks for `datetime.fromisoformat()` calls
@ -83,7 +82,7 @@ impl AlwaysFixableViolation for FromisoformatReplaceZ {
/// FURB162
pub(crate) fn fromisoformat_replace_z(checker: &Checker, call: &ExprCall) {
if checker.settings.target_version < PythonVersion::Py311 {
if checker.settings.target_version < PythonVersion::PY311 {
return;
}

View file

@ -1,11 +1,11 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast as ast;
use ruff_python_ast::{self as ast, PythonVersion};
use ruff_python_semantic::SemanticModel;
use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
use crate::Locator;
use crate::{checkers::ast::Checker, settings::types::PythonVersion};
/// ## What it does
/// Checks for code that could be written more idiomatically using
@ -69,7 +69,7 @@ impl AlwaysFixableViolation for SliceToRemovePrefixOrSuffix {
/// FURB188
pub(crate) fn slice_to_remove_affix_expr(checker: &Checker, if_expr: &ast::ExprIf) {
if checker.settings.target_version < PythonVersion::Py39 {
if checker.settings.target_version < PythonVersion::PY39 {
return;
}
@ -100,7 +100,7 @@ pub(crate) fn slice_to_remove_affix_expr(checker: &Checker, if_expr: &ast::ExprI
/// FURB188
pub(crate) fn slice_to_remove_affix_stmt(checker: &Checker, if_stmt: &ast::StmtIf) {
if checker.settings.target_version < PythonVersion::Py39 {
if checker.settings.target_version < PythonVersion::PY39 {
return;
}
if let Some(removal_data) = affix_removal_data_stmt(if_stmt) {

View file

@ -11,15 +11,14 @@ mod tests {
use anyhow::Result;
use regex::Regex;
use ruff_python_ast::PythonVersion;
use ruff_source_file::SourceFileBuilder;
use rustc_hash::FxHashSet;
use test_case::test_case;
use crate::pyproject_toml::lint_pyproject_toml;
use crate::registry::Rule;
use crate::settings::types::{
CompiledPerFileIgnoreList, PerFileIgnore, PreviewMode, PythonVersion,
};
use crate::settings::types::{CompiledPerFileIgnoreList, PerFileIgnore, PreviewMode};
use crate::settings::LinterSettings;
use crate::test::{test_path, test_resource_path};
use crate::{assert_messages, settings};
@ -130,7 +129,7 @@ mod tests {
extend_markup_names: vec![],
allowed_markup_calls: vec![],
},
target_version: PythonVersion::Py310,
target_version: PythonVersion::PY310,
..LinterSettings::for_rule(Rule::IncorrectlyParenthesizedTupleInSubscript)
},
)?;
@ -149,7 +148,7 @@ mod tests {
let diagnostics = test_path(
Path::new("ruff").join(path).as_path(),
&settings::LinterSettings::for_rule(Rule::ImplicitOptional)
.with_target_version(PythonVersion::Py39),
.with_target_version(PythonVersion::PY39),
)?;
assert_messages!(snapshot, diagnostics);
Ok(())

View file

@ -13,7 +13,7 @@ use crate::fix::edits::{remove_argument, Parentheses};
use crate::rules::pyupgrade::rules::pep695::{
expr_name_to_type_var, find_generic, DisplayTypeVars, TypeParamKind, TypeVar,
};
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
/// ## What it does
/// Checks for classes that have [PEP 695] [type parameter lists]
@ -79,7 +79,7 @@ impl Violation for ClassWithMixedTypeVars {
/// RUF053
pub(crate) fn class_with_mixed_type_vars(checker: &Checker, class_def: &StmtClassDef) {
if checker.settings.target_version < PythonVersion::Py312 {
if checker.settings.target_version < PythonVersion::PY312 {
return;
}

View file

@ -12,7 +12,7 @@ use ruff_text_size::{Ranged, TextRange};
use crate::checkers::ast::Checker;
use crate::importer::ImportRequest;
use crate::settings::types::PythonVersion;
use ruff_python_ast::PythonVersion;
use super::super::typing::type_hint_explicitly_allows_none;
@ -112,7 +112,7 @@ impl fmt::Display for ConversionType {
impl From<PythonVersion> for ConversionType {
fn from(target_version: PythonVersion) -> Self {
if target_version >= PythonVersion::Py310 {
if target_version >= PythonVersion::PY310 {
Self::BinOpOr
} else {
Self::Optional
@ -177,7 +177,7 @@ pub(crate) fn implicit_optional(checker: &Checker, parameters: &Parameters) {
let Some(expr) = type_hint_explicitly_allows_none(
parsed_annotation.expression(),
checker,
checker.settings.target_version.minor(),
checker.settings.target_version.minor,
) else {
continue;
};
@ -195,7 +195,7 @@ pub(crate) fn implicit_optional(checker: &Checker, parameters: &Parameters) {
let Some(expr) = type_hint_explicitly_allows_none(
annotation,
checker,
checker.settings.target_version.minor(),
checker.settings.target_version.minor,
) else {
continue;
};

View file

@ -1,9 +1,9 @@
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::{Expr, ExprSubscript};
use ruff_python_ast::{Expr, ExprSubscript, PythonVersion};
use ruff_text_size::Ranged;
use crate::{checkers::ast::Checker, settings::types::PythonVersion};
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for consistent style regarding whether nonempty tuples in subscripts
@ -88,7 +88,7 @@ pub(crate) fn subscript_with_parenthesized_tuple(checker: &Checker, subscript: &
// to a syntax error in Python 3.10.
// This is no longer a syntax error starting in Python 3.11
// see https://peps.python.org/pep-0646/#change-1-star-expressions-in-indexes
if checker.settings.target_version <= PythonVersion::Py310
if checker.settings.target_version <= PythonVersion::PY310
&& !prefer_parentheses
&& tuple_subscript.iter().any(Expr::is_starred_expr)
{

View file

@ -11,6 +11,7 @@ use std::sync::LazyLock;
use crate::codes::RuleCodePrefix;
use ruff_macros::CacheKey;
use ruff_python_ast::PythonVersion;
use crate::line_width::LineLength;
use crate::registry::{Linter, Rule};
@ -21,9 +22,7 @@ use crate::rules::{
flake8_self, flake8_tidy_imports, flake8_type_checking, flake8_unused_arguments, isort, mccabe,
pep8_naming, pycodestyle, pydoclint, pydocstyle, pyflakes, pylint, pyupgrade, ruff,
};
use crate::settings::types::{
CompiledPerFileIgnoreList, ExtensionMapping, FilePatternSet, PythonVersion,
};
use crate::settings::types::{CompiledPerFileIgnoreList, ExtensionMapping, FilePatternSet};
use crate::{codes, RuleSelector};
use super::line_width::IndentWidth;
@ -282,7 +281,7 @@ impl Display for LinterSettings {
self.per_file_ignores,
self.fix_safety | nested,
self.target_version | debug,
self.target_version,
self.preview,
self.explicit_preview_rules,
self.extension | debug,

View file

@ -7,55 +7,66 @@ use std::string::ToString;
use anyhow::{bail, Result};
use globset::{Glob, GlobMatcher, GlobSet, GlobSetBuilder};
use log::debug;
use pep440_rs::{Operator, Version as Pep440Version, Version, VersionSpecifier, VersionSpecifiers};
use pep440_rs::{VersionSpecifier, VersionSpecifiers};
use rustc_hash::FxHashMap;
use serde::{de, Deserialize, Deserializer, Serialize};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
use ruff_cache::{CacheKey, CacheKeyHasher};
use ruff_diagnostics::Applicability;
use ruff_macros::CacheKey;
use ruff_python_ast::PySourceType;
use ruff_python_ast::{self as ast, PySourceType};
use crate::registry::RuleSet;
use crate::rule_selector::RuleSelector;
use crate::{display_settings, fs};
#[derive(
Clone,
Copy,
Debug,
PartialOrd,
Ord,
PartialEq,
Eq,
Default,
Serialize,
Deserialize,
CacheKey,
EnumIter,
)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, EnumIter)]
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
#[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_python_formatter::PythonVersion`
// when changing the default here.
#[default]
Py39,
Py310,
Py311,
Py312,
Py313,
// Remember to update the `latest()` function
// when adding new versions here!
}
impl From<PythonVersion> for Pep440Version {
impl Default for PythonVersion {
fn default() -> Self {
// SAFETY: the unit test `default_python_version_works()` checks that this doesn't panic
Self::try_from(ast::PythonVersion::default()).unwrap()
}
}
impl TryFrom<ast::PythonVersion> for PythonVersion {
type Error = String;
fn try_from(value: ast::PythonVersion) -> Result<Self, Self::Error> {
match value {
ast::PythonVersion::PY37 => Ok(Self::Py37),
ast::PythonVersion::PY38 => Ok(Self::Py38),
ast::PythonVersion::PY39 => Ok(Self::Py39),
ast::PythonVersion::PY310 => Ok(Self::Py310),
ast::PythonVersion::PY311 => Ok(Self::Py311),
ast::PythonVersion::PY312 => Ok(Self::Py312),
ast::PythonVersion::PY313 => Ok(Self::Py313),
_ => Err(format!("unrecognized python version {value}")),
}
}
}
impl From<PythonVersion> for ast::PythonVersion {
fn from(value: PythonVersion) -> Self {
let (major, minor) = value.as_tuple();
Self { major, minor }
}
}
impl From<PythonVersion> for pep440_rs::Version {
fn from(version: PythonVersion) -> Self {
let (major, minor) = version.as_tuple();
Self::new([u64::from(major), u64::from(minor)])
@ -63,15 +74,6 @@ impl From<PythonVersion> for Pep440Version {
}
impl PythonVersion {
/// Return the latest supported Python version.
pub const fn latest() -> Self {
Self::Py313
}
pub const fn minimal_supported() -> Self {
Self::Py37
}
pub const fn as_tuple(&self) -> (u8, u8) {
match self {
Self::Py37 => (3, 7),
@ -83,53 +85,6 @@ impl PythonVersion {
Self::Py313 => (3, 13),
}
}
pub const fn major(&self) -> u8 {
self.as_tuple().0
}
pub const fn minor(&self) -> u8 {
self.as_tuple().1
}
/// Infer the minimum supported [`PythonVersion`] from a `requires-python` specifier.
pub fn get_minimum_supported_version(requires_version: &VersionSpecifiers) -> Option<Self> {
/// 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)
}
/// Return `true` if the current version supports [PEP 701].
///
/// [PEP 701]: https://peps.python.org/pep-0701/
pub fn supports_pep701(self) -> bool {
self >= Self::Py312
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, CacheKey, is_macro::Is)]
@ -679,3 +634,11 @@ impl Deref for CompiledPerFileIgnoreList {
&self.ignores
}
}
#[cfg(test)]
mod tests {
#[test]
fn default_python_version_works() {
super::PythonVersion::default();
}
}

View file

@ -6,6 +6,7 @@ pub use generated::*;
pub use int::*;
pub use nodes::*;
pub use operator_precedence::*;
pub use python_version::*;
pub mod comparable;
pub mod docstrings;
@ -19,7 +20,7 @@ mod node;
mod nodes;
pub mod operator_precedence;
pub mod parenthesize;
pub mod python_version;
mod python_version;
pub mod relocate;
pub mod script;
pub mod statement_visitor;

View file

@ -4,6 +4,7 @@ use std::fmt;
///
/// N.B. This does not necessarily represent a Python version that we actually support.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[cfg_attr(feature = "cache", derive(ruff_macros::CacheKey))]
pub struct PythonVersion {
pub major: u8,
pub minor: u8,
@ -43,9 +44,24 @@ impl PythonVersion {
.into_iter()
}
pub const fn latest() -> Self {
Self::PY313
}
pub const fn as_tuple(self) -> (u8, u8) {
(self.major, self.minor)
}
pub fn free_threaded_build_available(self) -> bool {
self >= PythonVersion::PY313
}
/// 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
}
}
impl Default for PythonVersion {

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py38"}
{"target_version": "3.8"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py311"}
{"target_version": "3.11"}

View file

@ -1 +1 @@
{"target_version": "py38"}
{"target_version": "3.8"}

View file

@ -1 +1 @@
{"preview": "enabled", "target_version": "py310"}
{"preview": "enabled", "target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"target_version": "py310"}
{"target_version": "3.10"}

View file

@ -1 +1 @@
{"preview": "enabled", "target_version": "py310"}
{"preview": "enabled", "target_version": "3.10"}

Some files were not shown because too many files have changed in this diff Show more