Implement Invalid rule provided as rule RUF102 with --fix (#17138)

<!--
Thank you for contributing to Ruff! To help us out with reviewing,
please consider the following:

- Does this pull request include a summary of the change? (See below.)
- Does this pull request include a descriptive title?
- Does this pull request include references to any relevant issues?
-->

Closes #17084

## Summary
This PR adds a new rule (RUF102) to detect and fix invalid rule codes in
`noqa` comments.
Invalid rule codes in `noqa` directives serve no purpose and may
indicate outdated code suppressions.

This extends the previous behaviour originating from
`crates/ruff_linter/src/noqa.rs` which would only emit a warnigs.
With this rule a `--fix` is available.

The rule:
1. Analyzes all `noqa` directives to identify invalid rule codes
2. Provides autofix functionality to:
   - Remove the entire comment if all codes are invalid
   - Remove only the invalid codes when mixed with valid codes
3. Preserves original comment formatting and whitespace where possible

Example cases:
- `# noqa: XYZ111` → Remove entire comment (keep empty line)
- `# noqa: XYZ222, XYZ333` → Remove entire comment (keep empty line)
-  `# noqa: F401, INVALID123` → Keep only valid codes (`# noqa: F401`)

## Test Plan
- Added tests in
`crates/ruff_linter/resources/test/fixtures/ruff/RUF102.py` covering
different example cases.

<!-- How was it tested? -->

## Notes 
- This does not handle cases where parsing fails. E.g. `# noqa:
NON_EXISTENT, ANOTHER_INVALID` causes a `LexicalError` and the
diagnostic is not propagated and we cannot handle the diagnostic. I am
also unsure what proper `fix` handling would be and making the user
aware we don't understand the codes is probably the best bet.
- The rule is added to the Preview rule group as it's a new addition

## Questions
- Should we remove the warnings, now that we have a rule?
- Is the current fix behavior appropriate for all cases, particularly
the handling of whitespace and line deletions?
- I'm new to the codebase; let me know if there are rule utilities which
could have used but didn't.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
Max Mynter 2025-04-04 10:05:59 +02:00 committed by GitHub
parent a4ba10ff0a
commit 98b95c9c38
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 605 additions and 0 deletions

View file

@ -0,0 +1,18 @@
# Invalid code
import os # noqa: INVALID123
# External code
import re # noqa: V123
# Valid noqa
import sys # noqa: E402
from functools import cache # Preceeding comment # noqa: F401, INVALID456
from itertools import product # Preceeding comment # noqa: INVALID789
# Succeeding comment
import math # noqa: INVALID000 # Succeeding comment
# Mixed valid and invalid
from typing import List # noqa: F401, INVALID123
# Test for multiple invalid
from collections import defaultdict # noqa: INVALID100, INVALID200, F401
# Test for preserving valid codes when fixing
from itertools import chain # noqa: E402, INVALID300, F401
# Test for mixed code types
import json # noqa: E402, INVALID400, V100

View file

@ -227,6 +227,13 @@ pub(crate) fn check_noqa(
); );
} }
if settings.rules.enabled(Rule::InvalidRuleCode)
&& !per_file_ignores.contains(Rule::InvalidRuleCode)
&& !exemption.enumerates(Rule::InvalidRuleCode)
{
ruff::rules::invalid_noqa_code(diagnostics, &noqa_directives, locator, &settings.external);
}
ignored_diagnostics.sort_unstable(); ignored_diagnostics.sort_unstable();
ignored_diagnostics ignored_diagnostics
} }

View file

@ -1016,6 +1016,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "059") => (RuleGroup::Preview, rules::ruff::rules::UnusedUnpackedVariable), (Ruff, "059") => (RuleGroup::Preview, rules::ruff::rules::UnusedUnpackedVariable),
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA), (Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),
(Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA), (Ruff, "101") => (RuleGroup::Stable, rules::ruff::rules::RedirectedNOQA),
(Ruff, "102") => (RuleGroup::Preview, rules::ruff::rules::InvalidRuleCode),
(Ruff, "200") => (RuleGroup::Stable, rules::ruff::rules::InvalidPyprojectToml), (Ruff, "200") => (RuleGroup::Stable, rules::ruff::rules::InvalidPyprojectToml),
#[cfg(any(feature = "test-rules", test))] #[cfg(any(feature = "test-rules", test))]

View file

@ -99,6 +99,7 @@ mod tests {
#[test_case(Rule::UnusedUnpackedVariable, Path::new("RUF059_3.py"))] #[test_case(Rule::UnusedUnpackedVariable, Path::new("RUF059_3.py"))]
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101_0.py"))] #[test_case(Rule::RedirectedNOQA, Path::new("RUF101_0.py"))]
#[test_case(Rule::RedirectedNOQA, Path::new("RUF101_1.py"))] #[test_case(Rule::RedirectedNOQA, Path::new("RUF101_1.py"))]
#[test_case(Rule::InvalidRuleCode, Path::new("RUF102.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> { fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy()); let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path( let diagnostics = test_path(
@ -314,6 +315,20 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn invalid_rule_code_external_rules() -> Result<()> {
let diagnostics = test_path(
Path::new("ruff/RUF102.py"),
&settings::LinterSettings {
external: vec!["V".to_string()],
..settings::LinterSettings::for_rule(Rule::InvalidRuleCode)
},
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test] #[test]
fn ruff_per_file_ignores() -> Result<()> { fn ruff_per_file_ignores() -> Result<()> {
let diagnostics = test_path( let diagnostics = test_path(

View file

@ -0,0 +1,160 @@
use crate::noqa::{Code, Directive};
use crate::registry::Rule;
use crate::Locator;
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_text_size::{Ranged, TextLen, TextRange, TextSize};
use crate::noqa::{Codes, NoqaDirectives};
/// ## What it does
/// Checks for `noqa` codes that are invalid.
///
/// ## Why is this bad?
/// Invalid rule codes serve no purpose and may indicate outdated code suppressions.
///
/// ## Example
/// ```python
/// import os # noqa: XYZ999
/// ```
///
/// Use instead:
/// ```python
/// import os
/// ```
///
/// Or if there are still valid codes needed:
/// ```python
/// import os # noqa: E402
/// ```
///
/// ## Options
/// - `lint.external`
#[derive(ViolationMetadata)]
pub(crate) struct InvalidRuleCode {
pub(crate) rule_code: String,
}
impl AlwaysFixableViolation for InvalidRuleCode {
#[derive_message_formats]
fn message(&self) -> String {
format!("Invalid rule code in `# noqa`: {}", self.rule_code)
}
fn fix_title(&self) -> String {
"Remove the rule code".to_string()
}
}
/// RUF102 for invalid noqa codes
pub(crate) fn invalid_noqa_code(
diagnostics: &mut Vec<Diagnostic>,
noqa_directives: &NoqaDirectives,
locator: &Locator,
external: &[String],
) {
for line in noqa_directives.lines() {
let Directive::Codes(directive) = &line.directive else {
continue;
};
let all_valid = directive.iter().all(|code| code_is_valid(code, external));
if all_valid {
continue;
}
let (valid_codes, invalid_codes): (Vec<_>, Vec<_>) = directive
.iter()
.partition(|&code| code_is_valid(code, external));
if valid_codes.is_empty() {
diagnostics.push(all_codes_invalid_diagnostic(directive, invalid_codes));
} else {
diagnostics.extend(invalid_codes.into_iter().map(|invalid_code| {
some_codes_are_invalid_diagnostic(directive, invalid_code, locator)
}));
}
}
}
fn code_is_valid(code: &Code, external: &[String]) -> bool {
let code_str = code.as_str();
Rule::from_code(code_str).is_ok() || external.iter().any(|ext| code_str.starts_with(ext))
}
fn all_codes_invalid_diagnostic(
directive: &Codes<'_>,
invalid_codes: Vec<&Code<'_>>,
) -> Diagnostic {
Diagnostic::new(
InvalidRuleCode {
rule_code: invalid_codes
.into_iter()
.map(Code::as_str)
.collect::<Vec<_>>()
.join(", "),
},
directive.range(),
)
.with_fix(Fix::safe_edit(Edit::range_deletion(directive.range())))
}
fn some_codes_are_invalid_diagnostic(
codes: &Codes,
invalid_code: &Code,
locator: &Locator,
) -> Diagnostic {
let diagnostic = Diagnostic::new(
InvalidRuleCode {
rule_code: invalid_code.to_string(),
},
invalid_code.range(),
);
diagnostic.with_fix(Fix::safe_edit(remove_invalid_noqa(
codes,
invalid_code,
locator,
)))
}
fn remove_invalid_noqa(codes: &Codes, invalid_code: &Code, locator: &Locator) -> Edit {
// Is this the first code after the `:` that needs to get deleted
// For the first element, delete from after the `:` to the next comma (including)
// For any other element, delete from the previous comma (including) to the next comma (excluding)
let mut first = false;
// Find the index of the previous comma or colon.
let start = locator
.slice(TextRange::new(codes.start(), invalid_code.start()))
.rmatch_indices([',', ':'])
.next()
.map(|(offset, text)| {
let offset = codes.start() + TextSize::try_from(offset).unwrap();
if text == ":" {
first = true;
// Don't include the colon in the deletion range, or the noqa comment becomes invalid
offset + ':'.text_len()
} else {
offset
}
})
.unwrap_or(invalid_code.start());
// Find the index of the trailing comma (if any)
let end = locator
.slice(TextRange::new(invalid_code.end(), codes.end()))
.find(',')
.map(|offset| {
let offset = invalid_code.end() + TextSize::try_from(offset).unwrap();
if first {
offset + ','.text_len()
} else {
offset
}
})
.unwrap_or(invalid_code.end());
Edit::range_deletion(TextRange::new(start, end))
}

View file

@ -19,6 +19,7 @@ pub(crate) use invalid_assert_message_literal_argument::*;
pub(crate) use invalid_formatter_suppression_comment::*; pub(crate) use invalid_formatter_suppression_comment::*;
pub(crate) use invalid_index_type::*; pub(crate) use invalid_index_type::*;
pub(crate) use invalid_pyproject_toml::*; pub(crate) use invalid_pyproject_toml::*;
pub(crate) use invalid_rule_code::*;
pub(crate) use map_int_version_parsing::*; pub(crate) use map_int_version_parsing::*;
pub(crate) use missing_fstring_syntax::*; pub(crate) use missing_fstring_syntax::*;
pub(crate) use mutable_class_default::*; pub(crate) use mutable_class_default::*;
@ -78,6 +79,7 @@ mod invalid_assert_message_literal_argument;
mod invalid_formatter_suppression_comment; mod invalid_formatter_suppression_comment;
mod invalid_index_type; mod invalid_index_type;
mod invalid_pyproject_toml; mod invalid_pyproject_toml;
mod invalid_rule_code;
mod map_int_version_parsing; mod map_int_version_parsing;
mod missing_fstring_syntax; mod missing_fstring_syntax;
mod mutable_class_default; mod mutable_class_default;

View file

@ -0,0 +1,219 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
---
RUF102.py:2:12: RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
1 | # Invalid code
2 | import os # noqa: INVALID123
| ^^^^^^^^^^^^^^^^^^ RUF102
3 | # External code
4 | import re # noqa: V123
|
= help: Remove the rule code
Safe fix
1 1 | # Invalid code
2 |-import os # noqa: INVALID123
2 |+import os
3 3 | # External code
4 4 | import re # noqa: V123
5 5 | # Valid noqa
RUF102.py:4:12: RUF102 [*] Invalid rule code in `# noqa`: V123
|
2 | import os # noqa: INVALID123
3 | # External code
4 | import re # noqa: V123
| ^^^^^^^^^^^^ RUF102
5 | # Valid noqa
6 | import sys # noqa: E402
|
= help: Remove the rule code
Safe fix
1 1 | # Invalid code
2 2 | import os # noqa: INVALID123
3 3 | # External code
4 |-import re # noqa: V123
4 |+import re
5 5 | # Valid noqa
6 6 | import sys # noqa: E402
7 7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
RUF102.py:7:65: RUF102 [*] Invalid rule code in `# noqa`: INVALID456
|
5 | # Valid noqa
6 | import sys # noqa: E402
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
| ^^^^^^^^^^ RUF102
8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 | # Succeeding comment
|
= help: Remove the rule code
Safe fix
4 4 | import re # noqa: V123
5 5 | # Valid noqa
6 6 | import sys # noqa: E402
7 |-from functools import cache # Preceeding comment # noqa: F401, INVALID456
7 |+from functools import cache # Preceeding comment # noqa: F401
8 8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 9 | # Succeeding comment
10 10 | import math # noqa: INVALID000 # Succeeding comment
RUF102.py:8:53: RUF102 [*] Invalid rule code in `# noqa`: INVALID789
|
6 | import sys # noqa: E402
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
8 | from itertools import product # Preceeding comment # noqa: INVALID789
| ^^^^^^^^^^^^^^^^^^ RUF102
9 | # Succeeding comment
10 | import math # noqa: INVALID000 # Succeeding comment
|
= help: Remove the rule code
Safe fix
5 5 | # Valid noqa
6 6 | import sys # noqa: E402
7 7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
8 |-from itertools import product # Preceeding comment # noqa: INVALID789
8 |+from itertools import product # Preceeding comment
9 9 | # Succeeding comment
10 10 | import math # noqa: INVALID000 # Succeeding comment
11 11 | # Mixed valid and invalid
RUF102.py:10:13: RUF102 [*] Invalid rule code in `# noqa`: INVALID000
|
8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 | # Succeeding comment
10 | import math # noqa: INVALID000 # Succeeding comment
| ^^^^^^^^^^^^^^^^^^ RUF102
11 | # Mixed valid and invalid
12 | from typing import List # noqa: F401, INVALID123
|
= help: Remove the rule code
Safe fix
7 7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
8 8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 9 | # Succeeding comment
10 |-import math # noqa: INVALID000 # Succeeding comment
10 |+import math # Succeeding comment
11 11 | # Mixed valid and invalid
12 12 | from typing import List # noqa: F401, INVALID123
13 13 | # Test for multiple invalid
RUF102.py:12:40: RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
10 | import math # noqa: INVALID000 # Succeeding comment
11 | # Mixed valid and invalid
12 | from typing import List # noqa: F401, INVALID123
| ^^^^^^^^^^ RUF102
13 | # Test for multiple invalid
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
|
= help: Remove the rule code
Safe fix
9 9 | # Succeeding comment
10 10 | import math # noqa: INVALID000 # Succeeding comment
11 11 | # Mixed valid and invalid
12 |-from typing import List # noqa: F401, INVALID123
12 |+from typing import List # noqa: F401
13 13 | # Test for multiple invalid
14 14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
15 15 | # Test for preserving valid codes when fixing
RUF102.py:14:46: RUF102 [*] Invalid rule code in `# noqa`: INVALID100
|
12 | from typing import List # noqa: F401, INVALID123
13 | # Test for multiple invalid
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
| ^^^^^^^^^^ RUF102
15 | # Test for preserving valid codes when fixing
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
= help: Remove the rule code
Safe fix
11 11 | # Mixed valid and invalid
12 12 | from typing import List # noqa: F401, INVALID123
13 13 | # Test for multiple invalid
14 |-from collections import defaultdict # noqa: INVALID100, INVALID200, F401
14 |+from collections import defaultdict # noqa: INVALID200, F401
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
RUF102.py:14:58: RUF102 [*] Invalid rule code in `# noqa`: INVALID200
|
12 | from typing import List # noqa: F401, INVALID123
13 | # Test for multiple invalid
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
| ^^^^^^^^^^ RUF102
15 | # Test for preserving valid codes when fixing
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
= help: Remove the rule code
Safe fix
11 11 | # Mixed valid and invalid
12 12 | from typing import List # noqa: F401, INVALID123
13 13 | # Test for multiple invalid
14 |-from collections import defaultdict # noqa: INVALID100, INVALID200, F401
14 |+from collections import defaultdict # noqa: INVALID100, F401
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
RUF102.py:16:44: RUF102 [*] Invalid rule code in `# noqa`: INVALID300
|
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
15 | # Test for preserving valid codes when fixing
16 | from itertools import chain # noqa: E402, INVALID300, F401
| ^^^^^^^^^^ RUF102
17 | # Test for mixed code types
18 | import json # noqa: E402, INVALID400, V100
|
= help: Remove the rule code
Safe fix
13 13 | # Test for multiple invalid
14 14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
15 15 | # Test for preserving valid codes when fixing
16 |-from itertools import chain # noqa: E402, INVALID300, F401
16 |+from itertools import chain # noqa: E402, F401
17 17 | # Test for mixed code types
18 18 | import json # noqa: E402, INVALID400, V100
RUF102.py:18:28: RUF102 [*] Invalid rule code in `# noqa`: INVALID400
|
16 | from itertools import chain # noqa: E402, INVALID300, F401
17 | # Test for mixed code types
18 | import json # noqa: E402, INVALID400, V100
| ^^^^^^^^^^ RUF102
|
= help: Remove the rule code
Safe fix
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
18 |-import json # noqa: E402, INVALID400, V100
18 |+import json # noqa: E402, V100
RUF102.py:18:40: RUF102 [*] Invalid rule code in `# noqa`: V100
|
16 | from itertools import chain # noqa: E402, INVALID300, F401
17 | # Test for mixed code types
18 | import json # noqa: E402, INVALID400, V100
| ^^^^ RUF102
|
= help: Remove the rule code
Safe fix
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
18 |-import json # noqa: E402, INVALID400, V100
18 |+import json # noqa: E402, INVALID400

View file

@ -0,0 +1,182 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
---
RUF102.py:2:12: RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
1 | # Invalid code
2 | import os # noqa: INVALID123
| ^^^^^^^^^^^^^^^^^^ RUF102
3 | # External code
4 | import re # noqa: V123
|
= help: Remove the rule code
Safe fix
1 1 | # Invalid code
2 |-import os # noqa: INVALID123
2 |+import os
3 3 | # External code
4 4 | import re # noqa: V123
5 5 | # Valid noqa
RUF102.py:7:65: RUF102 [*] Invalid rule code in `# noqa`: INVALID456
|
5 | # Valid noqa
6 | import sys # noqa: E402
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
| ^^^^^^^^^^ RUF102
8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 | # Succeeding comment
|
= help: Remove the rule code
Safe fix
4 4 | import re # noqa: V123
5 5 | # Valid noqa
6 6 | import sys # noqa: E402
7 |-from functools import cache # Preceeding comment # noqa: F401, INVALID456
7 |+from functools import cache # Preceeding comment # noqa: F401
8 8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 9 | # Succeeding comment
10 10 | import math # noqa: INVALID000 # Succeeding comment
RUF102.py:8:53: RUF102 [*] Invalid rule code in `# noqa`: INVALID789
|
6 | import sys # noqa: E402
7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
8 | from itertools import product # Preceeding comment # noqa: INVALID789
| ^^^^^^^^^^^^^^^^^^ RUF102
9 | # Succeeding comment
10 | import math # noqa: INVALID000 # Succeeding comment
|
= help: Remove the rule code
Safe fix
5 5 | # Valid noqa
6 6 | import sys # noqa: E402
7 7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
8 |-from itertools import product # Preceeding comment # noqa: INVALID789
8 |+from itertools import product # Preceeding comment
9 9 | # Succeeding comment
10 10 | import math # noqa: INVALID000 # Succeeding comment
11 11 | # Mixed valid and invalid
RUF102.py:10:13: RUF102 [*] Invalid rule code in `# noqa`: INVALID000
|
8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 | # Succeeding comment
10 | import math # noqa: INVALID000 # Succeeding comment
| ^^^^^^^^^^^^^^^^^^ RUF102
11 | # Mixed valid and invalid
12 | from typing import List # noqa: F401, INVALID123
|
= help: Remove the rule code
Safe fix
7 7 | from functools import cache # Preceeding comment # noqa: F401, INVALID456
8 8 | from itertools import product # Preceeding comment # noqa: INVALID789
9 9 | # Succeeding comment
10 |-import math # noqa: INVALID000 # Succeeding comment
10 |+import math # Succeeding comment
11 11 | # Mixed valid and invalid
12 12 | from typing import List # noqa: F401, INVALID123
13 13 | # Test for multiple invalid
RUF102.py:12:40: RUF102 [*] Invalid rule code in `# noqa`: INVALID123
|
10 | import math # noqa: INVALID000 # Succeeding comment
11 | # Mixed valid and invalid
12 | from typing import List # noqa: F401, INVALID123
| ^^^^^^^^^^ RUF102
13 | # Test for multiple invalid
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
|
= help: Remove the rule code
Safe fix
9 9 | # Succeeding comment
10 10 | import math # noqa: INVALID000 # Succeeding comment
11 11 | # Mixed valid and invalid
12 |-from typing import List # noqa: F401, INVALID123
12 |+from typing import List # noqa: F401
13 13 | # Test for multiple invalid
14 14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
15 15 | # Test for preserving valid codes when fixing
RUF102.py:14:46: RUF102 [*] Invalid rule code in `# noqa`: INVALID100
|
12 | from typing import List # noqa: F401, INVALID123
13 | # Test for multiple invalid
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
| ^^^^^^^^^^ RUF102
15 | # Test for preserving valid codes when fixing
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
= help: Remove the rule code
Safe fix
11 11 | # Mixed valid and invalid
12 12 | from typing import List # noqa: F401, INVALID123
13 13 | # Test for multiple invalid
14 |-from collections import defaultdict # noqa: INVALID100, INVALID200, F401
14 |+from collections import defaultdict # noqa: INVALID200, F401
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
RUF102.py:14:58: RUF102 [*] Invalid rule code in `# noqa`: INVALID200
|
12 | from typing import List # noqa: F401, INVALID123
13 | # Test for multiple invalid
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
| ^^^^^^^^^^ RUF102
15 | # Test for preserving valid codes when fixing
16 | from itertools import chain # noqa: E402, INVALID300, F401
|
= help: Remove the rule code
Safe fix
11 11 | # Mixed valid and invalid
12 12 | from typing import List # noqa: F401, INVALID123
13 13 | # Test for multiple invalid
14 |-from collections import defaultdict # noqa: INVALID100, INVALID200, F401
14 |+from collections import defaultdict # noqa: INVALID100, F401
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
RUF102.py:16:44: RUF102 [*] Invalid rule code in `# noqa`: INVALID300
|
14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
15 | # Test for preserving valid codes when fixing
16 | from itertools import chain # noqa: E402, INVALID300, F401
| ^^^^^^^^^^ RUF102
17 | # Test for mixed code types
18 | import json # noqa: E402, INVALID400, V100
|
= help: Remove the rule code
Safe fix
13 13 | # Test for multiple invalid
14 14 | from collections import defaultdict # noqa: INVALID100, INVALID200, F401
15 15 | # Test for preserving valid codes when fixing
16 |-from itertools import chain # noqa: E402, INVALID300, F401
16 |+from itertools import chain # noqa: E402, F401
17 17 | # Test for mixed code types
18 18 | import json # noqa: E402, INVALID400, V100
RUF102.py:18:28: RUF102 [*] Invalid rule code in `# noqa`: INVALID400
|
16 | from itertools import chain # noqa: E402, INVALID300, F401
17 | # Test for mixed code types
18 | import json # noqa: E402, INVALID400, V100
| ^^^^^^^^^^ RUF102
|
= help: Remove the rule code
Safe fix
15 15 | # Test for preserving valid codes when fixing
16 16 | from itertools import chain # noqa: E402, INVALID300, F401
17 17 | # Test for mixed code types
18 |-import json # noqa: E402, INVALID400, V100
18 |+import json # noqa: E402, V100

1
ruff.schema.json generated
View file

@ -4028,6 +4028,7 @@
"RUF10", "RUF10",
"RUF100", "RUF100",
"RUF101", "RUF101",
"RUF102",
"RUF2", "RUF2",
"RUF20", "RUF20",
"RUF200", "RUF200",