diff --git a/.github/workflows/build-docker.yml b/.github/workflows/build-docker.yml
index 17c241e7def6cd..e6a6c9b008a884 100644
--- a/.github/workflows/build-docker.yml
+++ b/.github/workflows/build-docker.yml
@@ -163,7 +163,7 @@ jobs:
# Mapping of base image followed by a comma followed by one or more base tags (comma separated)
# Note, org.opencontainers.image.version label will use the first base tag (use the most specific tag first)
image-mapping:
- - alpine:3.20,alpine3.20,alpine
+ - alpine:3.21,alpine3.21,alpine
- debian:bookworm-slim,bookworm-slim,debian-slim
- buildpack-deps:bookworm,bookworm,debian
steps:
diff --git a/crates/ruff/tests/lint.rs b/crates/ruff/tests/lint.rs
index c826cd861c2757..702723d54b8f34 100644
--- a/crates/ruff/tests/lint.rs
+++ b/crates/ruff/tests/lint.rs
@@ -2470,7 +2470,7 @@ fn create_a005_module_structure(tempdir: &TempDir) -> Result<()> {
Ok(())
}
-/// Test A005 with `builtins-strict-checking = true`
+/// Test A005 with `strict-checking = true`
#[test]
fn a005_module_shadowing_strict() -> Result<()> {
let tempdir = TempDir::new()?;
@@ -2482,7 +2482,7 @@ fn a005_module_shadowing_strict() -> Result<()> {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.arg("--config")
- .arg(r#"lint.flake8-builtins.builtins-strict-checking = true"#)
+ .arg(r#"lint.flake8-builtins.strict-checking = true"#)
.args(["--select", "A005"])
.current_dir(tempdir.path()),
@r"
@@ -2504,7 +2504,7 @@ fn a005_module_shadowing_strict() -> Result<()> {
Ok(())
}
-/// Test A005 with `builtins-strict-checking = false`
+/// Test A005 with `strict-checking = false`
#[test]
fn a005_module_shadowing_non_strict() -> Result<()> {
let tempdir = TempDir::new()?;
@@ -2516,7 +2516,7 @@ fn a005_module_shadowing_non_strict() -> Result<()> {
assert_cmd_snapshot!(Command::new(get_cargo_bin(BIN_NAME))
.args(STDIN_BASE_OPTIONS)
.arg("--config")
- .arg(r#"lint.flake8-builtins.builtins-strict-checking = false"#)
+ .arg(r#"lint.flake8-builtins.strict-checking = false"#)
.args(["--select", "A005"])
.current_dir(tempdir.path()),
@r"
@@ -2535,7 +2535,7 @@ fn a005_module_shadowing_non_strict() -> Result<()> {
Ok(())
}
-/// Test A005 with `builtins-strict-checking` unset
+/// Test A005 with `strict-checking` unset
/// TODO(brent) This should currently match the strict version, but after the next minor
/// release it will match the non-strict version directly above
#[test]
@@ -2556,11 +2556,7 @@ fn a005_module_shadowing_strict_default() -> Result<()> {
----- stdout -----
abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
collections/__init__.py:1:1: A005 Module `collections` shadows a Python standard-library module
- collections/abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
- foobar/abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
- foobar/collections/__init__.py:1:1: A005 Module `collections` shadows a Python standard-library module
- foobar/collections/abc/__init__.py:1:1: A005 Module `abc` shadows a Python standard-library module
- Found 6 errors.
+ Found 2 errors.
----- stderr -----
");
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 a4669d8b15c284..7fe041a00d69b7 100644
--- a/crates/ruff/tests/snapshots/show_settings__display_default_settings.snap
+++ b/crates/ruff/tests/snapshots/show_settings__display_default_settings.snap
@@ -226,10 +226,12 @@ linter.flake8_bandit.hardcoded_tmp_directory = [
/dev/shm,
]
linter.flake8_bandit.check_typed_exception = false
+linter.flake8_bandit.extend_markup_names = []
+linter.flake8_bandit.allowed_markup_calls = []
linter.flake8_bugbear.extend_immutable_calls = []
-linter.flake8_builtins.builtins_allowed_modules = []
-linter.flake8_builtins.builtins_ignorelist = []
-linter.flake8_builtins.builtins_strict_checking = true
+linter.flake8_builtins.allowed_modules = []
+linter.flake8_builtins.ignorelist = []
+linter.flake8_builtins.strict_checking = false
linter.flake8_comprehensions.allow_dict_calls_with_keyword_arguments = false
linter.flake8_copyright.notice_rgx = (?i)Copyright\s+((?:\(C\)|©)\s+)?\d{4}((-|,\s)\d{4})*
linter.flake8_copyright.author = none
@@ -369,8 +371,6 @@ linter.pylint.max_public_methods = 20
linter.pylint.max_locals = 15
linter.pyupgrade.keep_runtime_typing = false
linter.ruff.parenthesize_tuple_in_subscript = false
-linter.ruff.extend_markup_names = []
-linter.ruff.allowed_markup_calls = []
# Formatter Settings
formatter.exclude = []
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704.py
similarity index 62%
rename from crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py
rename to crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704.py
index 35cf7c8b8ad91c..7748a0ac40c236 100644
--- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704.py
@@ -2,17 +2,17 @@
from markupsafe import Markup, escape
content = ""
-Markup(f"unsafe {content}") # RUF035
-flask.Markup("unsafe {}".format(content)) # RUF035
+Markup(f"unsafe {content}") # S704
+flask.Markup("unsafe {}".format(content)) # S704
Markup("safe {}").format(content)
flask.Markup(b"safe {}", encoding='utf-8').format(content)
escape(content)
-Markup(content) # RUF035
-flask.Markup("unsafe %s" % content) # RUF035
+Markup(content) # S704
+flask.Markup("unsafe %s" % content) # S704
Markup(object="safe")
Markup(object="unsafe {}".format(content)) # Not currently detected
# NOTE: We may be able to get rid of these false positives with red-knot
# if it includes comprehensive constant expression detection/evaluation.
-Markup("*" * 8) # RUF035 (false positive)
-flask.Markup("hello {}".format("world")) # RUF035 (false positive)
+Markup("*" * 8) # S704 (false positive)
+flask.Markup("hello {}".format("world")) # S704 (false positive)
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035_extend_markup_names.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_extend_markup_names.py
similarity index 60%
rename from crates/ruff_linter/resources/test/fixtures/ruff/RUF035_extend_markup_names.py
rename to crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_extend_markup_names.py
index 2412badcbbc891..61612d4d02c134 100644
--- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035_extend_markup_names.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_extend_markup_names.py
@@ -2,5 +2,5 @@
from webhelpers.html import literal
content = ""
-Markup(f"unsafe {content}") # RUF035
-literal(f"unsafe {content}") # RUF035
+Markup(f"unsafe {content}") # S704
+literal(f"unsafe {content}") # S704
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035_skip_early_out.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_skip_early_out.py
similarity index 87%
rename from crates/ruff_linter/resources/test/fixtures/ruff/RUF035_skip_early_out.py
rename to crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_skip_early_out.py
index ce01813fee89b5..6bedf7441134f9 100644
--- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035_skip_early_out.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_skip_early_out.py
@@ -4,4 +4,4 @@
# additional markup names to be skipped if we don't import either
# markupsafe or flask first.
content = ""
-literal(f"unsafe {content}") # RUF035
+literal(f"unsafe {content}") # S704
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035_whitelisted_markup_calls.py b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_whitelisted_markup_calls.py
similarity index 88%
rename from crates/ruff_linter/resources/test/fixtures/ruff/RUF035_whitelisted_markup_calls.py
rename to crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_whitelisted_markup_calls.py
index 424306a2e7726d..146517a1a1d013 100644
--- a/crates/ruff_linter/resources/test/fixtures/ruff/RUF035_whitelisted_markup_calls.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_bandit/S704_whitelisted_markup_calls.py
@@ -6,4 +6,4 @@
# indirect assignments are currently not supported
cleaned = clean(content)
-Markup(cleaned) # RUF035
+Markup(cleaned) # S704
diff --git a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py
index dc5ce7c75e60ef..1030f6aaf54d40 100644
--- a/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py
+++ b/crates/ruff_linter/resources/test/fixtures/flake8_type_checking/TC005.py
@@ -4,13 +4,6 @@
pass # TC005
-if False:
- pass # TC005
-
-if 0:
- pass # TC005
-
-
def example():
if TYPE_CHECKING:
pass # TC005
@@ -32,13 +25,6 @@ class Test:
x: List
-if False:
- x: List
-
-if 0:
- x: List
-
-
from typing_extensions import TYPE_CHECKING
if TYPE_CHECKING:
diff --git a/crates/ruff_linter/resources/test/fixtures/ruff/noqa.py b/crates/ruff_linter/resources/test/fixtures/ruff/noqa.py
index 30e59400c6f2f3..f91ab752ac6d25 100644
--- a/crates/ruff_linter/resources/test/fixtures/ruff/noqa.py
+++ b/crates/ruff_linter/resources/test/fixtures/ruff/noqa.py
@@ -19,5 +19,6 @@ def f():
def f():
- # Only `E741` should be ignored by the `noqa`.
+ # Neither of these are ignored and warning is
+ # logged to user
I = 1 # noqa: E741.F841
diff --git a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs
index 011902eb34911e..4d276f656f7fcf 100644
--- a/crates/ruff_linter/src/checkers/ast/analyze/expression.rs
+++ b/crates/ruff_linter/src/checkers/ast/analyze/expression.rs
@@ -428,7 +428,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
flake8_2020::rules::name_or_attribute(checker, expr);
}
if checker.enabled(Rule::DatetimeMinMax) {
- flake8_datetimez::rules::datetime_max_min(checker, expr);
+ flake8_datetimez::rules::datetime_min_max(checker, expr);
}
if checker.enabled(Rule::BannedApi) {
flake8_tidy_imports::rules::banned_attribute_access(checker, expr);
@@ -1129,7 +1129,7 @@ pub(crate) fn expression(expr: &Expr, checker: &Checker) {
refurb::rules::int_on_sliced_str(checker, call);
}
if checker.enabled(Rule::UnsafeMarkupUse) {
- ruff::rules::unsafe_markup_call(checker, call);
+ flake8_bandit::rules::unsafe_markup_call(checker, call);
}
if checker.enabled(Rule::MapIntVersionParsing) {
ruff::rules::map_int_version_parsing(checker, call);
diff --git a/crates/ruff_linter/src/checkers/ast/mod.rs b/crates/ruff_linter/src/checkers/ast/mod.rs
index c4f98433bdd17a..fc72c1d1a3871d 100644
--- a/crates/ruff_linter/src/checkers/ast/mod.rs
+++ b/crates/ruff_linter/src/checkers/ast/mod.rs
@@ -246,11 +246,7 @@ impl<'a> Checker<'a> {
notebook_index: Option<&'a NotebookIndex>,
target_version: PythonVersion,
) -> Checker<'a> {
- let mut semantic = SemanticModel::new(&settings.typing_modules, path, module);
- if settings.preview.is_enabled() {
- // Set the feature flag to test `TYPE_CHECKING` semantic changes
- semantic.flags |= SemanticModelFlags::NEW_TYPE_CHECKING_BLOCK_DETECTION;
- }
+ let semantic = SemanticModel::new(&settings.typing_modules, path, module);
Self {
parsed,
parsed_type_annotation: None,
@@ -293,7 +289,14 @@ impl<'a> Checker<'a> {
if !self.noqa.is_enabled() {
return false;
}
- noqa::rule_is_ignored(code, offset, self.noqa_line_for, self.locator)
+
+ noqa::rule_is_ignored(
+ code,
+ offset,
+ self.noqa_line_for,
+ self.comment_ranges(),
+ self.locator,
+ )
}
/// Create a [`Generator`] to generate source code based on the current AST state.
diff --git a/crates/ruff_linter/src/checkers/noqa.rs b/crates/ruff_linter/src/checkers/noqa.rs
index c48ab99ad57e14..4d3015eadda81a 100644
--- a/crates/ruff_linter/src/checkers/noqa.rs
+++ b/crates/ruff_linter/src/checkers/noqa.rs
@@ -38,7 +38,8 @@ pub(crate) fn check_noqa(
let exemption = FileExemption::from(&file_noqa_directives);
// Extract all `noqa` directives.
- let mut noqa_directives = NoqaDirectives::from_commented_ranges(comment_ranges, path, locator);
+ let mut noqa_directives =
+ NoqaDirectives::from_commented_ranges(comment_ranges, &settings.external, path, locator);
// Indices of diagnostics that were ignored by a `noqa` directive.
let mut ignored_diagnostics = vec![];
diff --git a/crates/ruff_linter/src/codes.rs b/crates/ruff_linter/src/codes.rs
index c0e541fe573215..4a7e49b70d5a0d 100644
--- a/crates/ruff_linter/src/codes.rs
+++ b/crates/ruff_linter/src/codes.rs
@@ -192,7 +192,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "C0208") => (RuleGroup::Stable, rules::pylint::rules::IterationOverSet),
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
(Pylint, "C0415") => (RuleGroup::Preview, rules::pylint::rules::ImportOutsideTopLevel),
- (Pylint, "C1802") => (RuleGroup::Preview, rules::pylint::rules::LenTest),
+ (Pylint, "C1802") => (RuleGroup::Stable, rules::pylint::rules::LenTest),
(Pylint, "C1901") => (RuleGroup::Preview, rules::pylint::rules::CompareToEmptyString),
(Pylint, "C2401") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiName),
(Pylint, "C2403") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiImportName),
@@ -288,7 +288,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "W0642") => (RuleGroup::Stable, rules::pylint::rules::SelfOrClsAssignment),
(Pylint, "W0711") => (RuleGroup::Stable, rules::pylint::rules::BinaryOpException),
(Pylint, "W1501") => (RuleGroup::Stable, rules::pylint::rules::BadOpenMode),
- (Pylint, "W1507") => (RuleGroup::Preview, rules::pylint::rules::ShallowCopyEnviron),
+ (Pylint, "W1507") => (RuleGroup::Stable, rules::pylint::rules::ShallowCopyEnviron),
(Pylint, "W1508") => (RuleGroup::Stable, rules::pylint::rules::InvalidEnvvarDefault),
(Pylint, "W1509") => (RuleGroup::Stable, rules::pylint::rules::SubprocessPopenPreexecFn),
(Pylint, "W1510") => (RuleGroup::Stable, rules::pylint::rules::SubprocessRunWithoutCheck),
@@ -362,7 +362,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bugbear, "904") => (RuleGroup::Stable, rules::flake8_bugbear::rules::RaiseWithoutFromInsideExcept),
(Flake8Bugbear, "905") => (RuleGroup::Stable, rules::flake8_bugbear::rules::ZipWithoutExplicitStrict),
(Flake8Bugbear, "909") => (RuleGroup::Preview, rules::flake8_bugbear::rules::LoopIteratorMutation),
- (Flake8Bugbear, "911") => (RuleGroup::Preview, rules::flake8_bugbear::rules::BatchedWithoutExplicitStrict),
+ (Flake8Bugbear, "911") => (RuleGroup::Stable, rules::flake8_bugbear::rules::BatchedWithoutExplicitStrict),
// flake8-blind-except
(Flake8BlindExcept, "001") => (RuleGroup::Stable, rules::flake8_blind_except::rules::BlindExcept),
@@ -386,7 +386,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Comprehensions, "17") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryMap),
(Flake8Comprehensions, "18") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinDictCall),
(Flake8Comprehensions, "19") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryComprehensionInCall),
- (Flake8Comprehensions, "20") => (RuleGroup::Preview, rules::flake8_comprehensions::rules::UnnecessaryDictComprehensionForIterable),
+ (Flake8Comprehensions, "20") => (RuleGroup::Stable, rules::flake8_comprehensions::rules::UnnecessaryDictComprehensionForIterable),
// flake8-debugger
(Flake8Debugger, "0") => (RuleGroup::Stable, rules::flake8_debugger::rules::Debugger),
@@ -489,7 +489,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Simplify, "223") => (RuleGroup::Stable, rules::flake8_simplify::rules::ExprAndFalse),
(Flake8Simplify, "300") => (RuleGroup::Stable, rules::flake8_simplify::rules::YodaConditions),
(Flake8Simplify, "401") => (RuleGroup::Stable, rules::flake8_simplify::rules::IfElseBlockInsteadOfDictGet),
- (Flake8Simplify, "905") => (RuleGroup::Preview, rules::flake8_simplify::rules::SplitStaticString),
+ (Flake8Simplify, "905") => (RuleGroup::Stable, rules::flake8_simplify::rules::SplitStaticString),
(Flake8Simplify, "910") => (RuleGroup::Stable, rules::flake8_simplify::rules::DictGetWithNoneDefault),
(Flake8Simplify, "911") => (RuleGroup::Stable, rules::flake8_simplify::rules::ZipDictKeysAndValues),
@@ -532,13 +532,13 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pyupgrade, "035") => (RuleGroup::Stable, rules::pyupgrade::rules::DeprecatedImport),
(Pyupgrade, "036") => (RuleGroup::Stable, rules::pyupgrade::rules::OutdatedVersionBlock),
(Pyupgrade, "037") => (RuleGroup::Stable, rules::pyupgrade::rules::QuotedAnnotation),
- (Pyupgrade, "038") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP604Isinstance),
+ (Pyupgrade, "038") => (RuleGroup::Deprecated, rules::pyupgrade::rules::NonPEP604Isinstance),
(Pyupgrade, "039") => (RuleGroup::Stable, rules::pyupgrade::rules::UnnecessaryClassParentheses),
(Pyupgrade, "040") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP695TypeAlias),
(Pyupgrade, "041") => (RuleGroup::Stable, rules::pyupgrade::rules::TimeoutErrorAlias),
(Pyupgrade, "042") => (RuleGroup::Preview, rules::pyupgrade::rules::ReplaceStrEnum),
(Pyupgrade, "043") => (RuleGroup::Stable, rules::pyupgrade::rules::UnnecessaryDefaultTypeArgs),
- (Pyupgrade, "044") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP646Unpack),
+ (Pyupgrade, "044") => (RuleGroup::Stable, rules::pyupgrade::rules::NonPEP646Unpack),
(Pyupgrade, "045") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP604AnnotationOptional),
(Pyupgrade, "046") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericClass),
(Pyupgrade, "047") => (RuleGroup::Preview, rules::pyupgrade::rules::NonPEP695GenericFunction),
@@ -649,7 +649,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bandit, "317") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLSaxUsage),
(Flake8Bandit, "318") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLMiniDOMUsage),
(Flake8Bandit, "319") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLPullDOMUsage),
- (Flake8Bandit, "320") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousXMLETreeUsage),
+ (Flake8Bandit, "320") => (RuleGroup::Deprecated, rules::flake8_bandit::rules::SuspiciousXMLETreeUsage),
(Flake8Bandit, "321") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousFTPLibUsage),
(Flake8Bandit, "323") => (RuleGroup::Stable, rules::flake8_bandit::rules::SuspiciousUnverifiedContextUsage),
(Flake8Bandit, "324") => (RuleGroup::Stable, rules::flake8_bandit::rules::HashlibInsecureHashFunction),
@@ -690,6 +690,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bandit, "612") => (RuleGroup::Stable, rules::flake8_bandit::rules::LoggingConfigInsecureListen),
(Flake8Bandit, "701") => (RuleGroup::Stable, rules::flake8_bandit::rules::Jinja2AutoescapeFalse),
(Flake8Bandit, "702") => (RuleGroup::Stable, rules::flake8_bandit::rules::MakoTemplates),
+ (Flake8Bandit, "704") => (RuleGroup::Stable, rules::flake8_bandit::rules::UnsafeMarkupUse),
// flake8-boolean-trap
(Flake8BooleanTrap, "001") => (RuleGroup::Stable, rules::flake8_boolean_trap::rules::BooleanTypeHintPositionalArgument),
@@ -718,7 +719,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Datetimez, "007") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDatetimeStrptimeWithoutZone),
(Flake8Datetimez, "011") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDateToday),
(Flake8Datetimez, "012") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDateFromtimestamp),
- (Flake8Datetimez, "901") => (RuleGroup::Preview, rules::flake8_datetimez::rules::DatetimeMinMax),
+ (Flake8Datetimez, "901") => (RuleGroup::Stable, rules::flake8_datetimez::rules::DatetimeMinMax),
// pygrep-hooks
(PygrepHooks, "001") => (RuleGroup::Removed, rules::pygrep_hooks::rules::Eval),
@@ -870,8 +871,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8TypeChecking, "003") => (RuleGroup::Stable, rules::flake8_type_checking::rules::TypingOnlyStandardLibraryImport),
(Flake8TypeChecking, "004") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeImportInTypeCheckingBlock),
(Flake8TypeChecking, "005") => (RuleGroup::Stable, rules::flake8_type_checking::rules::EmptyTypeCheckingBlock),
- (Flake8TypeChecking, "006") => (RuleGroup::Preview, rules::flake8_type_checking::rules::RuntimeCastValue),
- (Flake8TypeChecking, "007") => (RuleGroup::Preview, rules::flake8_type_checking::rules::UnquotedTypeAlias),
+ (Flake8TypeChecking, "006") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeCastValue),
+ (Flake8TypeChecking, "007") => (RuleGroup::Stable, rules::flake8_type_checking::rules::UnquotedTypeAlias),
(Flake8TypeChecking, "008") => (RuleGroup::Preview, rules::flake8_type_checking::rules::QuotedTypeAlias),
(Flake8TypeChecking, "010") => (RuleGroup::Stable, rules::flake8_type_checking::rules::RuntimeStringUnion),
@@ -921,8 +922,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8UsePathlib, "205") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::OsPathGetctime),
(Flake8UsePathlib, "206") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::OsSepSplit),
(Flake8UsePathlib, "207") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::Glob),
- (Flake8UsePathlib, "208") => (RuleGroup::Preview, rules::flake8_use_pathlib::violations::OsListdir),
- (Flake8UsePathlib, "210") => (RuleGroup::Preview, rules::flake8_use_pathlib::rules::InvalidPathlibWithSuffix),
+ (Flake8UsePathlib, "208") => (RuleGroup::Stable, rules::flake8_use_pathlib::violations::OsListdir),
+ (Flake8UsePathlib, "210") => (RuleGroup::Stable, rules::flake8_use_pathlib::rules::InvalidPathlibWithSuffix),
// flake8-logging-format
(Flake8LoggingFormat, "001") => (RuleGroup::Stable, rules::flake8_logging_format::violations::LoggingStringFormat),
@@ -949,7 +950,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
// fastapi
(FastApi, "001") => (RuleGroup::Stable, rules::fastapi::rules::FastApiRedundantResponseModel),
(FastApi, "002") => (RuleGroup::Stable, rules::fastapi::rules::FastApiNonAnnotatedDependency),
- (FastApi, "003") => (RuleGroup::Preview, rules::fastapi::rules::FastApiUnusedPathParameter),
+ (FastApi, "003") => (RuleGroup::Stable, rules::fastapi::rules::FastApiUnusedPathParameter),
// pydoclint
(Pydoclint, "201") => (RuleGroup::Preview, rules::pydoclint::rules::DocstringMissingReturns),
@@ -991,20 +992,20 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "032") => (RuleGroup::Stable, rules::ruff::rules::DecimalFromFloatLiteral),
(Ruff, "033") => (RuleGroup::Stable, rules::ruff::rules::PostInitDefault),
(Ruff, "034") => (RuleGroup::Stable, rules::ruff::rules::UselessIfElse),
- (Ruff, "035") => (RuleGroup::Preview, rules::ruff::rules::UnsafeMarkupUse),
+ (Ruff, "035") => (RuleGroup::Removed, rules::ruff::rules::RuffUnsafeMarkupUse),
(Ruff, "036") => (RuleGroup::Preview, rules::ruff::rules::NoneNotAtEndOfUnion),
(Ruff, "037") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryEmptyIterableWithinDequeCall),
(Ruff, "038") => (RuleGroup::Preview, rules::ruff::rules::RedundantBoolLiteral),
(Ruff, "039") => (RuleGroup::Preview, rules::ruff::rules::UnrawRePattern),
- (Ruff, "040") => (RuleGroup::Preview, rules::ruff::rules::InvalidAssertMessageLiteralArgument),
- (Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral),
+ (Ruff, "040") => (RuleGroup::Stable, rules::ruff::rules::InvalidAssertMessageLiteralArgument),
+ (Ruff, "041") => (RuleGroup::Stable, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "043") => (RuleGroup::Preview, rules::ruff::rules::PytestRaisesAmbiguousPattern),
(Ruff, "045") => (RuleGroup::Preview, rules::ruff::rules::ImplicitClassVarInDataclass),
- (Ruff, "046") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryCastToInt),
+ (Ruff, "046") => (RuleGroup::Stable, rules::ruff::rules::UnnecessaryCastToInt),
(Ruff, "047") => (RuleGroup::Preview, rules::ruff::rules::NeedlessElse),
- (Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
+ (Ruff, "048") => (RuleGroup::Stable, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "049") => (RuleGroup::Preview, rules::ruff::rules::DataclassEnum),
- (Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
+ (Ruff, "051") => (RuleGroup::Stable, rules::ruff::rules::IfKeyInDictDel),
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
(Ruff, "053") => (RuleGroup::Preview, rules::ruff::rules::ClassWithMixedTypeVars),
(Ruff, "054") => (RuleGroup::Preview, rules::ruff::rules::IndentedFormFeed),
@@ -1135,7 +1136,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Logging, "007") => (RuleGroup::Stable, rules::flake8_logging::rules::ExceptionWithoutExcInfo),
(Flake8Logging, "009") => (RuleGroup::Stable, rules::flake8_logging::rules::UndocumentedWarn),
(Flake8Logging, "014") => (RuleGroup::Preview, rules::flake8_logging::rules::ExcInfoOutsideExceptHandler),
- (Flake8Logging, "015") => (RuleGroup::Preview, rules::flake8_logging::rules::RootLoggerCall),
+ (Flake8Logging, "015") => (RuleGroup::Stable, rules::flake8_logging::rules::RootLoggerCall),
_ => return None,
})
diff --git a/crates/ruff_linter/src/noqa.rs b/crates/ruff_linter/src/noqa.rs
index ac8d2cf5526759..57845b17a57fd2 100644
--- a/crates/ruff_linter/src/noqa.rs
+++ b/crates/ruff_linter/src/noqa.rs
@@ -10,7 +10,7 @@ use itertools::Itertools;
use log::warn;
use ruff_diagnostics::{Diagnostic, Edit};
-use ruff_python_trivia::{indentation_at_offset, CommentRanges};
+use ruff_python_trivia::{indentation_at_offset, CommentRanges, Cursor};
use ruff_source_file::{LineEnding, LineRanges};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
@@ -36,13 +36,13 @@ pub fn generate_noqa_edits(
) -> Vec