From a9efdea113a4f676ef85d89ed2dc285f7087478d Mon Sep 17 00:00:00 2001 From: Brent Westbrook <36778786+ntBre@users.noreply.github.com> Date: Tue, 18 Feb 2025 12:03:13 -0500 Subject: [PATCH] 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 --- crates/red_knot/src/python_version.rs | 6 +- crates/red_knot/tests/file_watching.rs | 2 +- crates/red_knot_project/src/combine.rs | 2 +- crates/red_knot_project/src/metadata.rs | 2 +- .../red_knot_project/src/metadata/options.rs | 2 +- .../src/metadata/pyproject.rs | 2 +- crates/red_knot_python_semantic/src/db.rs | 2 +- .../src/module_resolver/path.rs | 2 +- .../src/module_resolver/resolver.rs | 4 +- .../src/module_resolver/testing.rs | 2 +- .../src/module_resolver/typeshed.rs | 2 +- .../red_knot_python_semantic/src/program.rs | 2 +- .../src/site_packages.rs | 2 +- crates/red_knot_python_semantic/src/types.rs | 4 +- crates/red_knot_test/src/config.rs | 2 +- crates/red_knot_test/src/db.rs | 2 +- crates/red_knot_wasm/src/lib.rs | 6 +- crates/ruff/src/args.rs | 9 +- ...ow_settings__display_default_settings.snap | 6 +- crates/ruff_benchmark/benches/red_knot.rs | 2 +- crates/ruff_graph/src/db.rs | 2 +- crates/ruff_graph/src/settings.rs | 5 +- .../src/checkers/ast/analyze/expression.rs | 42 +++--- .../src/checkers/ast/analyze/statement.rs | 18 +-- crates/ruff_linter/src/checkers/ast/mod.rs | 2 +- crates/ruff_linter/src/renamer.rs | 2 +- crates/ruff_linter/src/rules/fastapi/mod.rs | 2 +- .../rules/fastapi_non_annotated_dependency.rs | 6 +- .../src/rules/flake8_annotations/helpers.rs | 6 +- .../src/rules/flake8_annotations/mod.rs | 4 +- .../flake8_annotations/rules/definition.rs | 4 +- .../ruff_linter/src/rules/flake8_async/mod.rs | 4 +- .../rules/async_function_with_timeout.rs | 4 +- .../src/rules/flake8_bugbear/mod.rs | 8 +- .../rules/batched_without_explicit_strict.rs | 4 +- .../rules/class_as_data_structure.rs | 4 +- .../src/rules/flake8_builtins/helpers.rs | 4 +- .../src/rules/flake8_builtins/mod.rs | 4 +- .../rules/stdlib_module_shadowing.rs | 2 +- .../rules/flake8_future_annotations/mod.rs | 6 +- .../ruff_linter/src/rules/flake8_pyi/mod.rs | 5 +- .../rules/custom_type_var_for_self.rs | 4 +- .../rules/no_return_argument_annotation.rs | 4 +- .../flake8_pyi/rules/non_self_return_type.rs | 4 +- .../rules/pre_pep570_positional_argument.rs | 4 +- .../rules/redundant_none_literal.rs | 6 +- .../rules/flake8_pyi/rules/simple_defaults.rs | 4 +- .../src/rules/flake8_quotes/mod.rs | 6 +- .../rules/avoidable_escaped_quote.rs | 2 +- .../src/rules/flake8_type_checking/mod.rs | 3 +- .../rules/type_alias_quotes.rs | 4 +- .../rules/replaceable_by_pathlib.rs | 4 +- .../ruff_linter/src/rules/isort/categorize.rs | 4 +- crates/ruff_linter/src/rules/isort/mod.rs | 2 +- crates/ruff_linter/src/rules/perflint/mod.rs | 7 +- .../perflint/rules/try_except_in_loop.rs | 4 +- crates/ruff_linter/src/rules/pyflakes/mod.rs | 2 +- crates/ruff_linter/src/rules/pylint/mod.rs | 5 +- .../rules/pylint/rules/bad_str_strip_call.rs | 4 +- .../pylint/rules/unnecessary_dunder_call.rs | 4 +- .../rules/useless_exception_statement.rs | 4 +- crates/ruff_linter/src/rules/pyupgrade/mod.rs | 23 ++-- .../pyupgrade/rules/deprecated_import.rs | 42 +++--- .../pyupgrade/rules/outdated_version_block.rs | 24 ++-- .../rules/pep695/non_pep695_generic_class.rs | 4 +- .../pep695/non_pep695_generic_function.rs | 4 +- .../rules/pep695/non_pep695_type_alias.rs | 6 +- .../pyupgrade/rules/timeout_error_alias.rs | 6 +- .../pyupgrade/rules/use_pep585_annotation.rs | 6 +- .../pyupgrade/rules/use_pep604_annotation.rs | 5 +- .../pyupgrade/rules/use_pep646_unpack.rs | 6 +- .../ruff_linter/src/rules/refurb/helpers.rs | 4 +- crates/ruff_linter/src/rules/refurb/mod.rs | 5 +- .../src/rules/refurb/rules/bit_count.rs | 5 +- .../refurb/rules/fromisoformat_replace_z.rs | 5 +- .../rules/slice_to_remove_prefix_or_suffix.rs | 8 +- crates/ruff_linter/src/rules/ruff/mod.rs | 9 +- .../ruff/rules/class_with_mixed_type_vars.rs | 4 +- .../src/rules/ruff/rules/implicit_optional.rs | 8 +- ...rectly_parenthesized_tuple_in_subscript.rs | 6 +- crates/ruff_linter/src/settings/mod.rs | 7 +- crates/ruff_linter/src/settings/types.rs | 123 ++++++------------ crates/ruff_python_ast/src/lib.rs | 3 +- crates/ruff_python_ast/src/python_version.rs | 16 +++ .../backslash_before_indent.options.json | 2 +- .../cases/context_managers_38.options.json | 2 +- ...ntext_managers_autodetect_310.options.json | 2 +- ...ntext_managers_autodetect_311.options.json | 2 +- ...ontext_managers_autodetect_38.options.json | 2 +- ...ef_return_type_trailing_comma.options.json | 2 +- .../keep_newline_after_match.options.json | 2 +- ...arenthesized_context_managers.options.json | 2 +- .../pattern_matching_complex.options.json | 2 +- .../pattern_matching_extras.options.json | 2 +- .../pattern_matching_generic.options.json | 2 +- .../cases/pattern_matching_long.options.json | 2 +- .../pattern_matching_simple.options.json | 2 +- .../cases/pattern_matching_style.options.json | 2 +- ...ttern_matching_trailing_comma.options.json | 2 +- ...pattern_matching_with_if_stmt.options.json | 2 +- ...ep604_union_types_line_breaks.options.json | 2 +- .../black/cases/pep_572_py310.options.json | 2 +- .../fixtures/black/cases/pep_646.options.json | 2 +- .../fixtures/black/cases/pep_654.options.json | 2 +- .../black/cases/pep_654_style.options.json | 2 +- .../fixtures/black/cases/pep_701.options.json | 2 +- ...typed_star_arg_type_var_tuple.options.json | 2 +- .../black/cases/py310_pep572.options.json | 2 +- ...edundant_parens_in_case_guard.options.json | 2 +- .../cases/starred_for_target.options.json | 2 +- .../black/cases/type_aliases.options.json | 2 +- .../cases/type_param_defaults.options.json | 2 +- .../black/cases/type_params.options.json | 2 +- .../test/fixtures/import_black_tests.py | 3 +- ..._concatenated_string_preserve.options.json | 2 +- .../fixtures/ruff/statement/with.options.json | 4 +- .../ruff/statement/with_39.options.json | 2 +- crates/ruff_python_formatter/src/lib.rs | 2 +- crates/ruff_python_formatter/src/options.rs | 59 +-------- .../src/statement/stmt_with.rs | 4 +- .../ruff_python_formatter/tests/fixtures.rs | 13 +- ...@blank_line_before_class_docstring.py.snap | 3 +- .../tests/snapshots/format@docstring.py.snap | 11 +- .../format@docstring_code_examples.py.snap | 21 ++- ...ormat@docstring_code_examples_crlf.py.snap | 3 +- ...g_code_examples_dynamic_line_width.py.snap | 9 +- .../format@docstring_tab_indentation.py.snap | 5 +- .../format@expression__bytes.py.snap | 5 +- .../format@expression__fstring.py.snap | 4 +- ...format@expression__fstring_preview.py.snap | 3 +- ...licit_concatenated_string_preserve.py.snap | 4 +- .../format@expression__string.py.snap | 5 +- ...rmat@fmt_on_off__fmt_off_docstring.py.snap | 5 +- .../format@fmt_on_off__indent.py.snap | 7 +- ...at@fmt_on_off__mixed_space_and_tab.py.snap | 7 +- .../format@notebook_docstring.py.snap | 5 +- .../tests/snapshots/format@preview.py.snap | 5 +- .../snapshots/format@quote_style.py.snap | 7 +- ...ormatting__docstring_code_examples.py.snap | 5 +- .../format@range_formatting__indent.py.snap | 7 +- .../format@range_formatting__stub.pyi.snap | 2 +- .../format@skip_magic_trailing_comma.py.snap | 5 +- .../snapshots/format@statement__with.py.snap | 4 +- .../format@statement__with_39.py.snap | 3 +- ...lank_line_after_nested_stub_class.pyi.snap | 3 +- ..._line_after_nested_stub_class_eof.pyi.snap | 3 +- .../tests/snapshots/format@tab_width.py.snap | 7 +- crates/ruff_wasm/src/lib.rs | 2 +- crates/ruff_workspace/src/configuration.rs | 17 +-- crates/ruff_workspace/src/options.rs | 26 ---- crates/ruff_workspace/src/pyproject.rs | 38 +++++- crates/ruff_workspace/src/settings.rs | 4 +- .../red_knot_check_invalid_syntax.rs | 2 +- 153 files changed, 456 insertions(+), 539 deletions(-) diff --git a/crates/red_knot/src/python_version.rs b/crates/red_knot/src/python_version.rs index bacf6ac290..09ce15f526 100644 --- a/crates/red_knot/src/python_version.rs +++ b/crates/red_knot/src/python_version.rs @@ -40,7 +40,7 @@ impl std::fmt::Display for PythonVersion { } } -impl From for ruff_python_ast::python_version::PythonVersion { +impl From 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() ); } } diff --git a/crates/red_knot/tests/file_watching.rs b/crates/red_knot/tests/file_watching.rs index 3091c83dce..24eed08e09 100644 --- a/crates/red_knot/tests/file_watching.rs +++ b/crates/red_knot/tests/file_watching.rs @@ -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, diff --git a/crates/red_knot_project/src/combine.rs b/crates/red_knot_project/src/combine.rs index 4dacbbb220..df55cb7f4e 100644 --- a/crates/red_knot_project/src/combine.rs +++ b/crates/red_knot_project/src/combine.rs @@ -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`. /// diff --git a/crates/red_knot_project/src/metadata.rs b/crates/red_knot_project/src/metadata.rs index 4d3b54cdd6..363c5fba47 100644 --- a/crates/red_knot_project/src/metadata.rs +++ b/crates/red_knot_project/src/metadata.rs @@ -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}; diff --git a/crates/red_knot_project/src/metadata/options.rs b/crates/red_knot_project/src/metadata/options.rs index 222b95c336..6d7eb32271 100644 --- a/crates/red_knot_project/src/metadata/options.rs +++ b/crates/red_knot_project/src/metadata/options.rs @@ -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; diff --git a/crates/red_knot_project/src/metadata/pyproject.rs b/crates/red_knot_project/src/metadata/pyproject.rs index d5dcf5aa99..691fe2d095 100644 --- a/crates/red_knot_project/src/metadata/pyproject.rs +++ b/crates/red_knot_project/src/metadata/pyproject.rs @@ -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; diff --git a/crates/red_knot_python_semantic/src/db.rs b/crates/red_knot_python_semantic/src/db.rs index 822a8a5125..d84a3648ec 100644 --- a/crates/red_knot_python_semantic/src/db.rs +++ b/crates/red_knot_python_semantic/src/db.rs @@ -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)] diff --git a/crates/red_knot_python_semantic/src/module_resolver/path.rs b/crates/red_knot_python_semantic/src/module_resolver/path.rs index da8ce2690c..f4ec2f8613 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/path.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/path.rs @@ -631,7 +631,7 @@ impl PartialEq 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}; diff --git a/crates/red_knot_python_semantic/src/module_resolver/resolver.rs b/crates/red_knot_python_semantic/src/module_resolver/resolver.rs index 720cb14d9b..94cf649a6d 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/resolver.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/resolver.rs @@ -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; diff --git a/crates/red_knot_python_semantic/src/module_resolver/testing.rs b/crates/red_knot_python_semantic/src/module_resolver/testing.rs index c54c8f34b4..6a13179621 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/testing.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/testing.rs @@ -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}; diff --git a/crates/red_knot_python_semantic/src/module_resolver/typeshed.rs b/crates/red_knot_python_semantic/src/module_resolver/typeshed.rs index a52f3d1449..de46fa93f0 100644 --- a/crates/red_knot_python_semantic/src/module_resolver/typeshed.rs +++ b/crates/red_knot_python_semantic/src/module_resolver/typeshed.rs @@ -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; diff --git a/crates/red_knot_python_semantic/src/program.rs b/crates/red_knot_python_semantic/src/program.rs index 3ae8860f59..94bb1349a0 100644 --- a/crates/red_knot_python_semantic/src/program.rs +++ b/crates/red_knot_python_semantic/src/program.rs @@ -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; diff --git a/crates/red_knot_python_semantic/src/site_packages.rs b/crates/red_knot_python_semantic/src/site_packages.rs index 265de68837..b2a8ce32f6 100644 --- a/crates/red_knot_python_semantic/src/site_packages.rs +++ b/crates/red_knot_python_semantic/src/site_packages.rs @@ -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 = Result; diff --git a/crates/red_knot_python_semantic/src/types.rs b/crates/red_knot_python_semantic/src/types.rs index b05fda4306..7f23500832 100644 --- a/crates/red_knot_python_semantic/src/types.rs +++ b/crates/red_knot_python_semantic/src/types.rs @@ -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 diff --git a/crates/red_knot_test/src/config.rs b/crates/red_knot_test/src/config.rs index a2e6816f30..ab24b4b843 100644 --- a/crates/red_knot_test/src/config.rs +++ b/crates/red_knot_test/src/config.rs @@ -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)] diff --git a/crates/red_knot_test/src/db.rs b/crates/red_knot_test/src/db.rs index 7736599e91..673511b150 100644 --- a/crates/red_knot_test/src/db.rs +++ b/crates/red_knot_test/src/db.rs @@ -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)] diff --git a/crates/red_knot_wasm/src/lib.rs b/crates/red_knot_wasm/src/lib.rs index 440bffd333..c93c22da5c 100644 --- a/crates/red_knot_wasm/src/lib.rs +++ b/crates/red_knot_wasm/src/lib.rs @@ -198,7 +198,7 @@ pub enum PythonVersion { Py313, } -impl From for ruff_python_ast::python_version::PythonVersion { +impl From 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() ); } } diff --git a/crates/ruff/src/args.rs b/crates/ruff/src/args.rs index 19c4f766d1..6c37948f32 100644 --- a/crates/ruff/src/args.rs +++ b/crates/ruff/src/args.rs @@ -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, respect_gitignore: Option, select: Option>, - target_version: Option, + target_version: Option, unfixable: Option>, // TODO(charlie): Captured in pyproject.toml as a default, but not part of `Settings`. cache_dir: Option, diff --git a/crates/ruff/tests/snapshots/show_settings__display_default_settings.snap b/crates/ruff/tests/snapshots/show_settings__display_default_settings.snap index b44e9e23c5..e0bb260b9e 100644 --- a/crates/ruff/tests/snapshots/show_settings__display_default_settings.snap +++ b/crates/ruff/tests/snapshots/show_settings__display_default_settings.snap @@ -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 = {} diff --git a/crates/ruff_benchmark/benches/red_knot.rs b/crates/ruff_benchmark/benches/red_knot.rs index fb9bcade73..11ec12577c 100644 --- a/crates/ruff_benchmark/benches/red_knot.rs +++ b/crates/ruff_benchmark/benches/red_knot.rs @@ -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 { diff --git a/crates/ruff_graph/src/db.rs b/crates/ruff_graph/src/db.rs index 16d6d3675a..e768c6282a 100644 --- a/crates/ruff_graph/src/db.rs +++ b/crates/ruff_graph/src/db.rs @@ -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 = std::sync::LazyLock::new(|| { let mut builder = VendoredFileSystemBuilder::new(CompressionMethod::Stored); diff --git a/crates/ruff_graph/src/settings.rs b/crates/ruff_graph/src/settings.rs index a91e24f2e3..f7174c8592 100644 --- a/crates/ruff_graph/src/settings.rs +++ b/crates/ruff_graph/src/settings.rs @@ -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, diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs index 77df89261c..7795d8c1ac 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs @@ -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() diff --git a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs index 0d75fb127a..4b5594e47f 100644 --- a/crates/ruff_linter/src/checkers/ast/analyze/statement.rs +++ b/crates/ruff_linter/src/checkers/ast/analyze/statement.rs @@ -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); } } diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs index 1bd965aab6..f34bc44029 100644 --- a/crates/ruff_linter/src/checkers/ast/mod.rs +++ b/crates/ruff_linter/src/checkers/ast/mod.rs @@ -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 { diff --git a/crates/ruff_linter/src/renamer.rs b/crates/ruff_linter/src/renamer.rs index 2ea03f3774..1b6c5835ec 100644 --- a/crates/ruff_linter/src/renamer.rs +++ b/crates/ruff_linter/src/renamer.rs @@ -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; diff --git a/crates/ruff_linter/src/rules/fastapi/mod.rs b/crates/ruff_linter/src/rules/fastapi/mod.rs index c29360cecc..91e77e6a5c 100644 --- a/crates/ruff_linter/src/rules/fastapi/mod.rs +++ b/crates/ruff_linter/src/rules/fastapi/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/fastapi/rules/fastapi_non_annotated_dependency.rs b/crates/ruff_linter/src/rules/fastapi/rules/fastapi_non_annotated_dependency.rs index 3a908c3b44..b393816140 100644 --- a/crates/ruff_linter/src/rules/fastapi/rules/fastapi_non_annotated_dependency.rs +++ b/crates/ruff_linter/src/rules/fastapi/rules/fastapi_non_annotated_dependency.rs @@ -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 { - 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" diff --git a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs index 1cea0f6135..25efc7aa14 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/helpers.rs @@ -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() diff --git a/crates/ruff_linter/src/rules/flake8_annotations/mod.rs b/crates/ruff_linter/src/rules/flake8_annotations/mod.rs index 57d866ec2c..6662976857 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/mod.rs @@ -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, diff --git a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs index 8a3667771e..692ed478d9 100644 --- a/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs +++ b/crates/ruff_linter/src/rules/flake8_annotations/rules/definition.rs @@ -523,7 +523,7 @@ fn check_dynamically_typed( 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( } } } 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(), diff --git a/crates/ruff_linter/src/rules/flake8_async/mod.rs b/crates/ruff_linter/src/rules/flake8_async/mod.rs index 19b6551a88..e01c3ee49e 100644 --- a/crates/ruff_linter/src/rules/flake8_async/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_async/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/flake8_async/rules/async_function_with_timeout.rs b/crates/ruff_linter/src/rules/flake8_async/rules/async_function_with_timeout.rs index 79c34e75ab..b588cf9e21 100644 --- a/crates/ruff_linter/src/rules/flake8_async/rules/async_function_with_timeout.rs +++ b/crates/ruff_linter/src/rules/flake8_async/rules/async_function_with_timeout.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs b/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs index 6d1b628831..d7dd402402 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/mod.rs @@ -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( diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/batched_without_explicit_strict.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/batched_without_explicit_strict.rs index a3de409969..8b12f6e9ee 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/batched_without_explicit_strict.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/batched_without_explicit_strict.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/flake8_bugbear/rules/class_as_data_structure.rs b/crates/ruff_linter/src/rules/flake8_bugbear/rules/class_as_data_structure.rs index 29ac873cfd..774a25b6da 100644 --- a/crates/ruff_linter/src/rules/flake8_bugbear/rules/class_as_data_structure.rs +++ b/crates/ruff_linter/src/rules/flake8_bugbear/rules/class_as_data_structure.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/flake8_builtins/helpers.rs b/crates/ruff_linter/src/rules/flake8_builtins/helpers.rs index 68a032b05d..fb11f22f01 100644 --- a/crates/ruff_linter/src/rules/flake8_builtins/helpers.rs +++ b/crates/ruff_linter/src/rules/flake8_builtins/helpers.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/flake8_builtins/mod.rs b/crates/ruff_linter/src/rules/flake8_builtins/mod.rs index 983df23b47..f0ba88562a 100644 --- a/crates/ruff_linter/src/rules/flake8_builtins/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_builtins/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/flake8_builtins/rules/stdlib_module_shadowing.rs b/crates/ruff_linter/src/rules/flake8_builtins/rules/stdlib_module_shadowing.rs index 0745d51e4f..a74d4c948d 100644 --- a/crates/ruff_linter/src/rules/flake8_builtins/rules/stdlib_module_shadowing.rs +++ b/crates/ruff_linter/src/rules/flake8_builtins/rules/stdlib_module_shadowing.rs @@ -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) } diff --git a/crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs b/crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs index d9b7c6bd60..8202840f0e 100644 --- a/crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_future_annotations/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/flake8_pyi/mod.rs b/crates/ruff_linter/src/rules/flake8_pyi/mod.rs index 6d11956018..cd3e572d10 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs index 413b6fd819..a3de847437 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/custom_type_var_for_self.rs @@ -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" diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs index e1a3dbbfe4..993419a49f 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/no_return_argument_annotation.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs index ae1b520b55..4364a9d4f9 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/non_self_return_type.rs @@ -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" diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/pre_pep570_positional_argument.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/pre_pep570_positional_argument.rs index 69c02d489b..c1427deec6 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/pre_pep570_positional_argument.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/pre_pep570_positional_argument.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_none_literal.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_none_literal.rs index 36bb60e9ca..b9e279e5e8 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_none_literal.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/redundant_none_literal.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs b/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs index 5eb431cb23..2a3ab2f6f0 100644 --- a/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs +++ b/crates/ruff_linter/src/rules/flake8_pyi/rules/simple_defaults.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/flake8_quotes/mod.rs b/crates/ruff_linter/src/rules/flake8_quotes/mod.rs index 9025b10e67..a684391bcd 100644 --- a/crates/ruff_linter/src/rules/flake8_quotes/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_quotes/mod.rs @@ -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); diff --git a/crates/ruff_linter/src/rules/flake8_quotes/rules/avoidable_escaped_quote.rs b/crates/ruff_linter/src/rules/flake8_quotes/rules/avoidable_escaped_quote.rs index a76469f0b3..55df17fd4f 100644 --- a/crates/ruff_linter/src/rules/flake8_quotes/rules/avoidable_escaped_quote.rs +++ b/crates/ruff_linter/src/rules/flake8_quotes/rules/avoidable_escaped_quote.rs @@ -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![], } } diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs b/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs index e23e2d9a9a..18db7f9ff7 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/flake8_type_checking/rules/type_alias_quotes.rs b/crates/ruff_linter/src/rules/flake8_type_checking/rules/type_alias_quotes.rs index 2a43e9724a..c8f80c500a 100644 --- a/crates/ruff_linter/src/rules/flake8_type_checking/rules/type_alias_quotes.rs +++ b/crates/ruff_linter/src/rules/flake8_type_checking/rules/type_alias_quotes.rs @@ -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) diff --git a/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs b/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs index 41582bbf78..feb7437d2f 100644 --- a/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs +++ b/crates/ruff_linter/src/rules/flake8_use_pathlib/rules/replaceable_by_pathlib.rs @@ -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, diff --git a/crates/ruff_linter/src/rules/isort/categorize.rs b/crates/ruff_linter/src/rules/isort/categorize.rs index 0b85b54146..cb607b39df 100644 --- a/crates/ruff_linter/src/rules/isort/categorize.rs +++ b/crates/ruff_linter/src/rules/isort/categorize.rs @@ -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, diff --git a/crates/ruff_linter/src/rules/isort/mod.rs b/crates/ruff_linter/src/rules/isort/mod.rs index 2db901583f..40e0d6f9da 100644 --- a/crates/ruff_linter/src/rules/isort/mod.rs +++ b/crates/ruff_linter/src/rules/isort/mod.rs @@ -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; diff --git a/crates/ruff_linter/src/rules/perflint/mod.rs b/crates/ruff_linter/src/rules/perflint/mod.rs index 55477f8d1f..f6d5bc5e34 100644 --- a/crates/ruff_linter/src/rules/perflint/mod.rs +++ b/crates/ruff_linter/src/rules/perflint/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs b/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs index d611c5f28d..1ef5dd258f 100644 --- a/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs +++ b/crates/ruff_linter/src/rules/perflint/rules/try_except_in_loop.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/pyflakes/mod.rs b/crates/ruff_linter/src/rules/pyflakes/mod.rs index 70e520fff8..0108e640ed 100644 --- a/crates/ruff_linter/src/rules/pyflakes/mod.rs +++ b/crates/ruff_linter/src/rules/pyflakes/mod.rs @@ -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) }, ); diff --git a/crates/ruff_linter/src/rules/pylint/mod.rs b/crates/ruff_linter/src/rules/pylint/mod.rs index 6f484b72cb..8cbb73b032 100644 --- a/crates/ruff_linter/src/rules/pylint/mod.rs +++ b/crates/ruff_linter/src/rules/pylint/mod.rs @@ -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(()) diff --git a/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs b/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs index 9ed65dc8eb..9dfe324a75 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/bad_str_strip_call.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs index b5ac652bed..573e6b5c04 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/unnecessary_dunder_call.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/pylint/rules/useless_exception_statement.rs b/crates/ruff_linter/src/rules/pylint/rules/useless_exception_statement.rs index 2e2d7db477..a5261851ca 100644 --- a/crates/ruff_linter/src/rules/pylint/rules/useless_exception_statement.rs +++ b/crates/ruff_linter/src/rules/pylint/rules/useless_exception_statement.rs @@ -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)) }) } diff --git a/crates/ruff_linter/src/rules/pyupgrade/mod.rs b/crates/ruff_linter/src/rules/pyupgrade/mod.rs index 2fd5a2a80e..aeb6944140 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/mod.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/mod.rs @@ -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) }, )?; diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_import.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_import.rs index a11eb3a19e..9c83e3cede 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_import.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/deprecated_import.rs @@ -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 { 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); } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/outdated_version_block.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/outdated_version_block.rs index 8bf187a6cc..6b031396f6 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/outdated_version_block.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/outdated_version_block.rs @@ -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], diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_class.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_class.rs index 3ed1f805b6..ae11deb9ea 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_class.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_class.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_function.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_function.rs index 1a5ed053e8..197eeae77f 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_function.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_generic_function.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_type_alias.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_type_alias.rs index e3a1cb96c1..d7dd9c8d04 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_type_alias.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/pep695/non_pep695_type_alias.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs index a1387cb7c5..159f1a1c3a 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/timeout_error_alias.rs @@ -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"]) diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs index cc4c89bfe9..754bc5a31d 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep585_annotation.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs index 5a370cce3f..3242f2f24f 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep604_annotation.rs @@ -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 diff --git a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep646_unpack.rs b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep646_unpack.rs index d9d14e9d29..c2e59836ba 100644 --- a/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep646_unpack.rs +++ b/crates/ruff_linter/src/rules/pyupgrade/rules/use_pep646_unpack.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/refurb/helpers.rs b/crates/ruff_linter/src/rules/refurb/helpers.rs index fb6aa77eba..d81558e588 100644 --- a/crates/ruff_linter/src/rules/refurb/helpers.rs +++ b/crates/ruff_linter/src/rules/refurb/helpers.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/refurb/mod.rs b/crates/ruff_linter/src/rules/refurb/mod.rs index 7b9f39e03a..964fa0100d 100644 --- a/crates/ruff_linter/src/rules/refurb/mod.rs +++ b/crates/ruff_linter/src/rules/refurb/mod.rs @@ -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(()) diff --git a/crates/ruff_linter/src/rules/refurb/rules/bit_count.rs b/crates/ruff_linter/src/rules/refurb/rules/bit_count.rs index c855081c5b..ba1f51412a 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/bit_count.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/bit_count.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/refurb/rules/fromisoformat_replace_z.rs b/crates/ruff_linter/src/rules/refurb/rules/fromisoformat_replace_z.rs index 6d44c03486..6779a482a6 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/fromisoformat_replace_z.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/fromisoformat_replace_z.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/refurb/rules/slice_to_remove_prefix_or_suffix.rs b/crates/ruff_linter/src/rules/refurb/rules/slice_to_remove_prefix_or_suffix.rs index 31eff56c4c..c475bc75d1 100644 --- a/crates/ruff_linter/src/rules/refurb/rules/slice_to_remove_prefix_or_suffix.rs +++ b/crates/ruff_linter/src/rules/refurb/rules/slice_to_remove_prefix_or_suffix.rs @@ -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) { diff --git a/crates/ruff_linter/src/rules/ruff/mod.rs b/crates/ruff_linter/src/rules/ruff/mod.rs index 8422a3fb95..df6e363d69 100644 --- a/crates/ruff_linter/src/rules/ruff/mod.rs +++ b/crates/ruff_linter/src/rules/ruff/mod.rs @@ -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(()) diff --git a/crates/ruff_linter/src/rules/ruff/rules/class_with_mixed_type_vars.rs b/crates/ruff_linter/src/rules/ruff/rules/class_with_mixed_type_vars.rs index 306514e187..846ff0b109 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/class_with_mixed_type_vars.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/class_with_mixed_type_vars.rs @@ -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; } diff --git a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs index 0a843ade1d..6c10ae503e 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/implicit_optional.rs @@ -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 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; }; diff --git a/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs b/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs index 9764a8155c..01f2dd9d0c 100644 --- a/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs +++ b/crates/ruff_linter/src/rules/ruff/rules/incorrectly_parenthesized_tuple_in_subscript.rs @@ -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) { diff --git a/crates/ruff_linter/src/settings/mod.rs b/crates/ruff_linter/src/settings/mod.rs index 047c768813..01f9f7220f 100644 --- a/crates/ruff_linter/src/settings/mod.rs +++ b/crates/ruff_linter/src/settings/mod.rs @@ -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, diff --git a/crates/ruff_linter/src/settings/types.rs b/crates/ruff_linter/src/settings/types.rs index be53584c8c..007a4a4e2b 100644 --- a/crates/ruff_linter/src/settings/types.rs +++ b/crates/ruff_linter/src/settings/types.rs @@ -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 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 for PythonVersion { + type Error = String; + + fn try_from(value: ast::PythonVersion) -> Result { + 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 for ast::PythonVersion { + fn from(value: PythonVersion) -> Self { + let (major, minor) = value.as_tuple(); + Self { major, minor } + } +} + +impl From 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 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 { - /// Truncate a version to its major and minor components. - fn major_minor(version: &Version) -> Option { - 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(); + } +} diff --git a/crates/ruff_python_ast/src/lib.rs b/crates/ruff_python_ast/src/lib.rs index fa3e778fdb..7983ccee82 100644 --- a/crates/ruff_python_ast/src/lib.rs +++ b/crates/ruff_python_ast/src/lib.rs @@ -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; diff --git a/crates/ruff_python_ast/src/python_version.rs b/crates/ruff_python_ast/src/python_version.rs index 66745f8a48..cdbb9c8f3d 100644 --- a/crates/ruff_python_ast/src/python_version.rs +++ b/crates/ruff_python_ast/src/python_version.rs @@ -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 { diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/backslash_before_indent.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/backslash_before_indent.options.json index 60044b9854..54724b66c5 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/backslash_before_indent.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/backslash_before_indent.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_38.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_38.options.json index 56ae457e60..fa1bf06046 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_38.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_38.options.json @@ -1 +1 @@ -{"target_version": "py38"} \ No newline at end of file +{"target_version": "3.8"} diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_310.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_310.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_310.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_310.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_311.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_311.options.json index c723d00e42..dcb1b48257 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_311.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_311.options.json @@ -1 +1 @@ -{"target_version": "py311"} \ No newline at end of file +{"target_version": "3.11"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_38.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_38.options.json index 56ae457e60..01777c6d8f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_38.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/context_managers_autodetect_38.options.json @@ -1 +1 @@ -{"target_version": "py38"} \ No newline at end of file +{"target_version": "3.8"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json index 0aaaa152bc..1266ed1e66 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/funcdef_return_type_trailing_comma.options.json @@ -1 +1 @@ -{"preview": "enabled", "target_version": "py310"} \ No newline at end of file +{"preview": "enabled", "target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/keep_newline_after_match.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/keep_newline_after_match.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/keep_newline_after_match.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/keep_newline_after_match.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/parenthesized_context_managers.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_complex.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_extras.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_generic.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_long.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_long.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_long.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_long.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_simple.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_style.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_trailing_comma.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_trailing_comma.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_trailing_comma.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_trailing_comma.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_with_if_stmt.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_with_if_stmt.options.json index 0aaaa152bc..1266ed1e66 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_with_if_stmt.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pattern_matching_with_if_stmt.options.json @@ -1 +1 @@ -{"preview": "enabled", "target_version": "py310"} \ No newline at end of file +{"preview": "enabled", "target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep604_union_types_line_breaks.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_572_py310.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.options.json index c723d00e42..dcb1b48257 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_646.options.json @@ -1 +1 @@ -{"target_version": "py311"} \ No newline at end of file +{"target_version": "3.11"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.options.json index c723d00e42..dcb1b48257 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654.options.json @@ -1 +1 @@ -{"target_version": "py311"} \ No newline at end of file +{"target_version": "3.11"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.options.json index c723d00e42..dcb1b48257 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_654_style.options.json @@ -1 +1 @@ -{"target_version": "py311"} \ No newline at end of file +{"target_version": "3.11"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_701.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_701.options.json index cf266d3540..4295ffe1df 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_701.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/pep_701.options.json @@ -1 +1 @@ -{"target_version": "py312"} \ No newline at end of file +{"target_version": "3.12"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep646_typed_star_arg_type_var_tuple.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep646_typed_star_arg_type_var_tuple.options.json index f1b92cd916..938747847c 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep646_typed_star_arg_type_var_tuple.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_pep646_typed_star_arg_type_var_tuple.options.json @@ -1 +1 @@ -{"preview": "enabled", "target_version": "py311"} \ No newline at end of file +{"preview": "enabled", "target_version": "3.11"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/py310_pep572.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_redundant_parens_in_case_guard.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_redundant_parens_in_case_guard.options.json index 185c73ab05..172715c6e4 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_redundant_parens_in_case_guard.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_redundant_parens_in_case_guard.options.json @@ -1 +1 @@ -{"preview": "enabled", "line_width": 79, "target_version": "py310"} \ No newline at end of file +{"preview": "enabled", "line_width": 79, "target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.options.json index 60044b9854..717b73130f 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/starred_for_target.options.json @@ -1 +1 @@ -{"target_version": "py310"} \ No newline at end of file +{"target_version": "3.10"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_aliases.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_aliases.options.json index cf266d3540..4295ffe1df 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_aliases.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_aliases.options.json @@ -1 +1 @@ -{"target_version": "py312"} \ No newline at end of file +{"target_version": "3.12"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_param_defaults.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_param_defaults.options.json index b9b2345df9..f93c020fc9 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_param_defaults.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_param_defaults.options.json @@ -1 +1 @@ -{"target_version": "py313"} \ No newline at end of file +{"target_version": "3.13"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.options.json b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.options.json index cf266d3540..4295ffe1df 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/black/cases/type_params.options.json @@ -1 +1 @@ -{"target_version": "py312"} \ No newline at end of file +{"target_version": "3.12"} \ No newline at end of file diff --git a/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py b/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py index c55810a169..a9cbb2cc6d 100755 --- a/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/import_black_tests.py @@ -58,8 +58,7 @@ def import_fixture(fixture: Path, fixture_set: str): if "--minimum-version=" in flags: [_, version] = flags.split("--minimum-version=", 1) version = version.split(" ", 1)[0] - # Convert 3.10 to py310 - black_options["target_version"] = f"py{version.strip().replace('.', '')}" + black_options["target_version"] = version.strip() if "--skip-magic-trailing-comma" in flags: black_options["magic_trailing_comma"] = "ignore" diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_preserve.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_preserve.options.json index 17f4b10dbc..e6adddbe26 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_preserve.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_preserve.options.json @@ -4,6 +4,6 @@ }, { "quote_style": "preserve", - "target_version": "py312" + "target_version": "3.12" } ] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.options.json index 2eeb9813ab..c44e865141 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with.options.json @@ -1,9 +1,9 @@ [ { - "target_version": "py38" + "target_version": "3.8" }, { - "target_version": "py39", + "target_version": "3.9", "preview": "enabled" } ] diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with_39.options.json b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with_39.options.json index 3621449825..d929350237 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with_39.options.json +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with_39.options.json @@ -1,6 +1,6 @@ [ { - "target_version": "py39", + "target_version": "3.9", "preview": "enabled" } ] diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index a4498a3a87..86c4236648 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -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}; diff --git a/crates/ruff_python_formatter/src/options.rs b/crates/ruff_python_formatter/src/options.rs index b268bbd59d..1357d53590 100644 --- a/crates/ruff_python_formatter/src/options.rs +++ b/crates/ruff_python_formatter/src/options.rs @@ -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 - } -} diff --git a/crates/ruff_python_formatter/src/statement/stmt_with.rs b/crates/ruff_python_formatter/src/statement/stmt_with.rs index 493be1e517..5098251850 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_with.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_with.rs @@ -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 diff --git a/crates/ruff_python_formatter/tests/fixtures.rs b/crates/ruff_python_formatter/tests/fixtures.rs index f10b15cd71..9b94b19c78 100644 --- a/crates/ruff_python_formatter/tests/fixtures.rs +++ b/crates/ruff_python_formatter/tests/fixtures.rs @@ -26,8 +26,9 @@ fn black_compatibility() { let options: PyFormatOptions = if let Ok(options_file) = fs::File::open(&options_path) { let reader = BufReader::new(options_file); - serde_json::from_reader(reader) - .unwrap_or_else(|_| panic!("Option file {options_path:?} to be a valid Json file")) + serde_json::from_reader(reader).unwrap_or_else(|_| { + panic!("Expected option file {options_path:?} to be a valid Json file") + }) } else { PyFormatOptions::from_extension(input_path) }; @@ -180,10 +181,12 @@ fn format() { let mut snapshot = format!("## Input\n{}", CodeFrame::new("python", &content)); let options_path = input_path.with_extension("options.json"); - if let Ok(options_file) = fs::File::open(options_path) { + if let Ok(options_file) = fs::File::open(&options_path) { let reader = BufReader::new(options_file); let options: Vec = - serde_json::from_reader(reader).expect("Options to be a valid Json file"); + serde_json::from_reader(reader).unwrap_or_else(|_| { + panic!("Expected option file {options_path:?} to be a valid Json file") + }); writeln!(snapshot, "## Outputs").unwrap(); @@ -473,7 +476,7 @@ magic-trailing-comma = {magic_trailing_comma:?} docstring-code = {docstring_code:?} docstring-code-line-width = {docstring_code_line_width:?} preview = {preview:?} -target_version = {target_version:?} +target_version = {target_version} source_type = {source_type:?}"#, indent_style = self.0.indent_style(), indent_width = self.0.indent_width().value(), diff --git a/crates/ruff_python_formatter/tests/snapshots/format@blank_line_before_class_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@blank_line_before_class_docstring.py.snap index 935a8ef83c..58cfb7e492 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@blank_line_before_class_docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@blank_line_before_class_docstring.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/blank_line_before_class_docstring.py -snapshot_kind: text --- ## Input ```python @@ -57,7 +56,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap index 411f4d8eba..9ca83e81de 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring.py -snapshot_kind: text --- ## Input ```python @@ -176,7 +175,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -352,7 +351,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -528,7 +527,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -704,7 +703,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -880,7 +879,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap index f6c50122e6..024d662e0a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples.py -snapshot_kind: text --- ## Input ```python @@ -1369,7 +1368,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -2741,7 +2740,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -4113,7 +4112,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -5485,7 +5484,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -6857,7 +6856,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -8222,7 +8221,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -9587,7 +9586,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -10961,7 +10960,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -12326,7 +12325,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = 60 preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -13700,7 +13699,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap index a0fc4e1569..9b1dc4ba52 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_crlf.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_crlf.py -snapshot_kind: text --- ## Input ```python @@ -28,7 +27,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap index ad87c9b969..7112865500 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_code_examples_dynamic_line_width.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_code_examples_dynamic_line_width.py -snapshot_kind: text --- ## Input ```python @@ -309,7 +308,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -880,7 +879,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -1426,7 +1425,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -1997,7 +1996,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@docstring_tab_indentation.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@docstring_tab_indentation.py.snap index 944e17a431..a7e5f5d84f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@docstring_tab_indentation.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@docstring_tab_indentation.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/docstring_tab_indentation.py -snapshot_kind: text --- ## Input ```python @@ -91,7 +90,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -185,7 +184,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap index 890767793c..0e9e65cf92 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__bytes.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/bytes.py -snapshot_kind: text --- ## Input ```python @@ -141,7 +140,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -297,7 +296,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap index fea634ff69..b357a01b9f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap @@ -751,7 +751,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -1551,7 +1551,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring_preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring_preview.py.snap index bfe565935c..508eda3e94 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring_preview.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring_preview.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/fstring_preview.py -snapshot_kind: text --- ## Input ```python @@ -39,7 +38,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_preserve.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_preserve.py.snap index 688efde6cd..a9d9f10827 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_preserve.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_preserve.py.snap @@ -40,7 +40,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -81,7 +81,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py312 +target_version = 3.12 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap index fa68fdbfcb..953b2c34cb 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/string.py -snapshot_kind: text --- ## Input ```python @@ -233,7 +232,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -483,7 +482,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap index b421cb853d..c7775aba83 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__fmt_off_docstring.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/fmt_off_docstring.py -snapshot_kind: text --- ## Input ```python @@ -38,7 +37,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -76,7 +75,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap index 8f0b24ff9b..8fd14d6634 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__indent.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/indent.py -snapshot_kind: text --- ## Input ```python @@ -19,7 +18,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -38,7 +37,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -57,7 +56,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap index 8599c14ac7..99bde1d1d6 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@fmt_on_off__mixed_space_and_tab.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/fmt_on_off/mixed_space_and_tab.py -snapshot_kind: text --- ## Input ```python @@ -34,7 +33,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -69,7 +68,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -104,7 +103,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@notebook_docstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@notebook_docstring.py.snap index 8cce047f7d..6018c9fc26 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@notebook_docstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@notebook_docstring.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/notebook_docstring.py -snapshot_kind: text --- ## Input ```python @@ -25,7 +24,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Ipynb ``` @@ -49,7 +48,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap index d7ccd4a5df..3557b8c478 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@preview.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/preview.py -snapshot_kind: text --- ## Input ```python @@ -85,7 +84,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -168,7 +167,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap index 9910d923ea..b79b0ead6e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@quote_style.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/quote_style.py -snapshot_kind: text --- ## Input ```python @@ -69,7 +68,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -143,7 +142,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -217,7 +216,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__docstring_code_examples.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__docstring_code_examples.py.snap index c2ed1d0674..0cb72a9fb4 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__docstring_code_examples.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__docstring_code_examples.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/range_formatting/docstring_code_examples.py -snapshot_kind: text --- ## Input ```python @@ -122,7 +121,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -274,7 +273,7 @@ magic-trailing-comma = Respect docstring-code = Enabled docstring-code-line-width = 88 preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__indent.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__indent.py.snap index 83aedb02a7..669f8f5eb5 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__indent.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__indent.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/range_formatting/indent.py -snapshot_kind: text --- ## Input ```python @@ -82,7 +81,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -161,7 +160,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -240,7 +239,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__stub.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__stub.pyi.snap index 4b2a7b6f4b..d2ec8f05d8 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__stub.pyi.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@range_formatting__stub.pyi.snap @@ -34,7 +34,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Stub ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap index 0d18ca41c9..12521c9433 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@skip_magic_trailing_comma.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/skip_magic_trailing_comma.py -snapshot_kind: text --- ## Input ```python @@ -52,7 +51,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -110,7 +109,7 @@ magic-trailing-comma = Ignore docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap index 3ee05f4763..d72ffe623a 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__with.py.snap @@ -387,7 +387,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py38 +target_version = 3.8 source_type = Python ``` @@ -889,7 +889,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__with_39.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__with_39.py.snap index 7d5d4dca17..f38e1658a2 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__with_39.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__with_39.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/with_39.py -snapshot_kind: text --- ## Input ```python @@ -111,7 +110,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class.pyi.snap index cbd5976f31..1d7b8c7636 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class.pyi.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class.pyi.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/stub_files/blank_line_after_nested_stub_class.pyi -snapshot_kind: text --- ## Input ```python @@ -202,7 +201,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Stub ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class_eof.pyi.snap b/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class_eof.pyi.snap index aecb66882c..55485257f3 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class_eof.pyi.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@stub_files__blank_line_after_nested_stub_class_eof.pyi.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/stub_files/blank_line_after_nested_stub_class_eof.pyi -snapshot_kind: text --- ## Input ```python @@ -36,7 +35,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Enabled -target_version = Py39 +target_version = 3.9 source_type = Stub ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap index 76744a4c58..ab1caa6805 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@tab_width.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/tab_width.py -snapshot_kind: text --- ## Input ```python @@ -27,7 +26,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -54,7 +53,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` @@ -84,7 +83,7 @@ magic-trailing-comma = Respect docstring-code = Disabled docstring-code-line-width = "dynamic" preview = Disabled -target_version = Py39 +target_version = 3.9 source_type = Python ``` diff --git a/crates/ruff_wasm/src/lib.rs b/crates/ruff_wasm/src/lib.rs index 69bb06f646..946bdc1520 100644 --- a/crates/ruff_wasm/src/lib.rs +++ b/crates/ruff_wasm/src/lib.rs @@ -1,6 +1,7 @@ use std::path::Path; use js_sys::Error; +use ruff_linter::settings::types::PythonVersion; use serde::{Deserialize, Serialize}; use wasm_bindgen::prelude::*; @@ -10,7 +11,6 @@ use ruff_linter::directives; use ruff_linter::line_width::{IndentWidth, LineLength}; use ruff_linter::linter::check_path; use ruff_linter::registry::AsRule; -use ruff_linter::settings::types::PythonVersion; use ruff_linter::settings::{flags, DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX}; use ruff_linter::source_kind::SourceKind; use ruff_linter::Locator; diff --git a/crates/ruff_workspace/src/configuration.rs b/crates/ruff_workspace/src/configuration.rs index b27a877bae..f0c8643164 100644 --- a/crates/ruff_workspace/src/configuration.rs +++ b/crates/ruff_workspace/src/configuration.rs @@ -30,13 +30,14 @@ use ruff_linter::settings::fix_safety_table::FixSafetyTable; use ruff_linter::settings::rule_table::RuleTable; use ruff_linter::settings::types::{ CompiledPerFileIgnoreList, ExtensionMapping, FilePattern, FilePatternSet, OutputFormat, - PerFileIgnore, PreviewMode, PythonVersion, RequiredVersion, UnsafeFixes, + PerFileIgnore, PreviewMode, RequiredVersion, UnsafeFixes, }; use ruff_linter::settings::{LinterSettings, DEFAULT_SELECTORS, DUMMY_VARIABLE_RGX, TASK_TAGS}; use ruff_linter::{ fs, warn_user_once, warn_user_once_by_id, warn_user_once_by_message, RuleSelector, RUFF_PKG_VERSION, }; +use ruff_python_ast as ast; use ruff_python_formatter::{ DocstringCode, DocstringCodeLineWidth, MagicTrailingComma, QuoteStyle, }; @@ -136,7 +137,7 @@ pub struct Configuration { pub builtins: Option>, pub namespace_packages: Option>, pub src: Option>, - pub target_version: Option, + pub target_version: Option, // Global formatting options pub line_length: Option, @@ -177,15 +178,7 @@ impl Configuration { exclude: FilePatternSet::try_from_iter(format.exclude.unwrap_or_default())?, extension: self.extension.clone().unwrap_or_default(), preview: format_preview, - target_version: match target_version { - PythonVersion::Py37 => ruff_python_formatter::PythonVersion::Py37, - PythonVersion::Py38 => ruff_python_formatter::PythonVersion::Py38, - PythonVersion::Py39 => ruff_python_formatter::PythonVersion::Py39, - PythonVersion::Py310 => ruff_python_formatter::PythonVersion::Py310, - PythonVersion::Py311 => ruff_python_formatter::PythonVersion::Py311, - PythonVersion::Py312 => ruff_python_formatter::PythonVersion::Py312, - PythonVersion::Py313 => ruff_python_formatter::PythonVersion::Py313, - }, + target_version, line_width: self .line_length .map_or(format_defaults.line_width, |length| { @@ -539,7 +532,7 @@ impl Configuration { .src .map(|src| resolve_src(&src, project_root)) .transpose()?, - target_version: options.target_version, + target_version: options.target_version.map(ast::PythonVersion::from), // `--extension` is a hidden command-line argument that isn't supported in configuration // files at present. extension: None, diff --git a/crates/ruff_workspace/src/options.rs b/crates/ruff_workspace/src/options.rs index abfedd2c35..88994f6ecc 100644 --- a/crates/ruff_workspace/src/options.rs +++ b/crates/ruff_workspace/src/options.rs @@ -3848,9 +3848,7 @@ impl From for LintOptions { mod tests { use crate::options::Flake8SelfOptions; use ruff_linter::rules::flake8_self; - use ruff_linter::settings::types::PythonVersion as LinterPythonVersion; use ruff_python_ast::name::Name; - use ruff_python_formatter::PythonVersion as FormatterPythonVersion; #[test] fn flake8_self_options() { @@ -3898,28 +3896,4 @@ mod tests { vec![Name::new_static("_foo"), Name::new_static("_bar")] ); } - - #[test] - fn formatter_and_linter_target_version_have_same_default() { - assert_eq!( - FormatterPythonVersion::default().as_tuple(), - LinterPythonVersion::default().as_tuple() - ); - } - - #[test] - fn formatter_and_linter_target_version_have_same_latest() { - assert_eq!( - FormatterPythonVersion::latest().as_tuple(), - LinterPythonVersion::latest().as_tuple() - ); - } - - #[test] - fn formatter_and_linter_target_version_have_same_minimal_supported() { - assert_eq!( - FormatterPythonVersion::minimal_supported().as_tuple(), - LinterPythonVersion::minimal_supported().as_tuple() - ); - } } diff --git a/crates/ruff_workspace/src/pyproject.rs b/crates/ruff_workspace/src/pyproject.rs index 6c3bc74c4b..75d11cf38f 100644 --- a/crates/ruff_workspace/src/pyproject.rs +++ b/crates/ruff_workspace/src/pyproject.rs @@ -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>(path: P) -> Result { 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>(path: P) -> Result { } } +/// Infer the minimum supported [`PythonVersion`] from a `requires-python` specifier. +fn get_minimum_supported_version(requires_version: &VersionSpecifiers) -> Option { + /// Truncate a version to its major and minor components. + fn major_minor(version: &Version) -> Option { + 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; diff --git a/crates/ruff_workspace/src/settings.rs b/crates/ruff_workspace/src/settings.rs index 451d9d8a10..0ef15d4407 100644 --- a/crates/ruff_workspace/src/settings.rs +++ b/crates/ruff_workspace/src/settings.rs @@ -164,7 +164,7 @@ pub struct FormatterSettings { pub exclude: FilePatternSet, pub extension: ExtensionMapping, pub preview: PreviewMode, - pub target_version: ruff_python_formatter::PythonVersion, + pub target_version: ruff_python_ast::PythonVersion, pub line_width: LineWidth, @@ -247,7 +247,7 @@ impl fmt::Display for FormatterSettings { namespace = "formatter", fields = [ self.exclude, - self.target_version | debug, + self.target_version, self.preview, self.line_width, self.line_ending, diff --git a/fuzz/fuzz_targets/red_knot_check_invalid_syntax.rs b/fuzz/fuzz_targets/red_knot_check_invalid_syntax.rs index 55a4d761b6..35de7cdba5 100644 --- a/fuzz/fuzz_targets/red_knot_check_invalid_syntax.rs +++ b/fuzz/fuzz_targets/red_knot_check_invalid_syntax.rs @@ -17,7 +17,7 @@ use ruff_db::files::{system_path_to_file, File, Files}; 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; use ruff_python_parser::{parse_unchecked, Mode}; /// Database that can be used for testing.