diff --git a/crates/ruff_linter/src/linter.rs b/crates/ruff_linter/src/linter.rs index 00d07892dc..1fd72b16d8 100644 --- a/crates/ruff_linter/src/linter.rs +++ b/crates/ruff_linter/src/linter.rs @@ -30,14 +30,14 @@ use crate::fix::{fix_file, FixResult}; use crate::message::Message; use crate::noqa::add_noqa; use crate::package::PackageRoot; -use crate::preview::is_unsupported_syntax_enabled; +use crate::preview::{is_py314_support_enabled, is_unsupported_syntax_enabled}; use crate::registry::{AsRule, Rule, RuleSet}; #[cfg(any(feature = "test-rules", test))] use crate::rules::ruff::rules::test_rules::{self, TestRule, TEST_RULES}; use crate::settings::types::UnsafeFixes; use crate::settings::{flags, LinterSettings}; use crate::source_kind::SourceKind; -use crate::{directives, fs, Locator}; +use crate::{directives, fs, warn_user_once, Locator}; pub struct LinterResult { /// A collection of diagnostic messages generated by the linter. @@ -450,6 +450,11 @@ pub fn lint_only( source: ParseSource, ) -> LinterResult { let target_version = settings.resolve_target_version(path); + + if matches!(target_version, PythonVersion::PY314) && !is_py314_support_enabled(settings) { + warn_user_once!("Support for Python 3.14 is under development and may be unstable. Enable `preview` to remove this warning."); + } + let parsed = source.into_parsed(source_kind, source_type, target_version); // Map row and column locations to byte slices (lazily). @@ -559,6 +564,10 @@ pub fn lint_fix<'a>( let target_version = settings.resolve_target_version(path); + if matches!(target_version, PythonVersion::PY314) && !is_py314_support_enabled(settings) { + warn_user_once!("Support for Python 3.14 is under development and may be unstable. Enable `preview` to remove this warning."); + } + // Continuously fix until the source code stabilizes. loop { // Parse once. diff --git a/crates/ruff_linter/src/preview.rs b/crates/ruff_linter/src/preview.rs index 9973eada40..0edf643f12 100644 --- a/crates/ruff_linter/src/preview.rs +++ b/crates/ruff_linter/src/preview.rs @@ -18,6 +18,10 @@ pub(crate) const fn is_unsupported_syntax_enabled(settings: &LinterSettings) -> settings.preview.is_enabled() } +pub(crate) const fn is_py314_support_enabled(settings: &LinterSettings) -> bool { + settings.preview.is_enabled() +} + // Rule-specific behavior // https://github.com/astral-sh/ruff/pull/17136 diff --git a/crates/ruff_linter/src/settings/types.rs b/crates/ruff_linter/src/settings/types.rs index 7087d9856d..9a6fd859e0 100644 --- a/crates/ruff_linter/src/settings/types.rs +++ b/crates/ruff_linter/src/settings/types.rs @@ -34,6 +34,7 @@ pub enum PythonVersion { Py311, Py312, Py313, + Py314, } impl Default for PythonVersion { @@ -55,6 +56,7 @@ impl TryFrom for PythonVersion { ast::PythonVersion::PY311 => Ok(Self::Py311), ast::PythonVersion::PY312 => Ok(Self::Py312), ast::PythonVersion::PY313 => Ok(Self::Py313), + ast::PythonVersion::PY314 => Ok(Self::Py314), _ => Err(format!("unrecognized python version {value}")), } } @@ -84,6 +86,7 @@ impl PythonVersion { Self::Py311 => (3, 11), Self::Py312 => (3, 12), Self::Py313 => (3, 13), + Self::Py314 => (3, 14), } } } diff --git a/crates/ruff_python_ast/src/python_version.rs b/crates/ruff_python_ast/src/python_version.rs index e5d1406ded..20906a2510 100644 --- a/crates/ruff_python_ast/src/python_version.rs +++ b/crates/ruff_python_ast/src/python_version.rs @@ -30,6 +30,10 @@ impl PythonVersion { major: 3, minor: 13, }; + pub const PY314: PythonVersion = PythonVersion { + major: 3, + minor: 14, + }; pub fn iter() -> impl Iterator { [ @@ -40,6 +44,7 @@ impl PythonVersion { PythonVersion::PY311, PythonVersion::PY312, PythonVersion::PY313, + PythonVersion::PY314, ] .into_iter() } @@ -49,6 +54,7 @@ impl PythonVersion { Self::PY37 } + // TODO: change this to 314 when it is released pub const fn latest() -> Self { Self::PY313 } diff --git a/docs/configuration.md b/docs/configuration.md index 953a4baf59..ade0b0ced3 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -608,7 +608,7 @@ Options: RUFF_OUTPUT_FILE=] --target-version The minimum Python version that should be supported [possible values: - py37, py38, py39, py310, py311, py312, py313] + py37, py38, py39, py310, py311, py312, py313, py314] --preview Enable preview mode; checks will include unstable rules and fixes. Use `--no-preview` to disable @@ -723,7 +723,7 @@ Options: notebooks, use `--extension ipy:ipynb` --target-version The minimum Python version that should be supported [possible values: - py37, py38, py39, py310, py311, py312, py313] + py37, py38, py39, py310, py311, py312, py313, py314] --preview Enable preview mode; enables unstable formatting. Use `--no-preview` to disable diff --git a/knot.schema.json b/knot.schema.json index 7349373c0e..28a09099c6 100644 --- a/knot.schema.json +++ b/knot.schema.json @@ -210,6 +210,10 @@ { "description": "Python 3.13", "const": "3.13" + }, + { + "description": "Python 3.14", + "const": "3.14" } ] }, diff --git a/ruff.schema.json b/ruff.schema.json index 096df71618..446ce35e58 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -2848,7 +2848,8 @@ "py310", "py311", "py312", - "py313" + "py313", + "py314" ] }, "Quote": {