diff --git a/README.md b/README.md index 6c7099cc9c..cfaaa61fd2 100644 --- a/README.md +++ b/README.md @@ -581,6 +581,7 @@ For more, see [Pyflakes](https://pypi.org/project/pyflakes/2.5.0/) on PyPI. For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI. +#### Error (E) | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | E401 | MultipleImportsOnOneLine | Multiple imports on one line | | @@ -598,6 +599,10 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI | E743 | AmbiguousFunctionName | Ambiguous function name: `...` | | | E902 | IOError | IOError: `...` | | | E999 | SyntaxError | SyntaxError: `...` | | + +#### Warning (W) +| Code | Name | Message | Fix | +| ---- | ---- | ------- | --- | | W292 | NoNewLineAtEndOfFile | No newline at end of file | 🛠 | | W505 | DocLineTooLong | Doc line too long (89 > 88 characters) | | | W605 | InvalidEscapeSequence | Invalid escape sequence: '\c' | 🛠 | @@ -979,7 +984,6 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/ | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | -| SIM115 | OpenFileWithContextHandler | Use context handler for opening files | | | SIM101 | DuplicateIsinstanceCall | Multiple `isinstance` calls for `...`, merge into a single call | 🛠 | | SIM102 | NestedIfStatements | Use a single `if` statement instead of nested `if` statements | | | SIM103 | ReturnBoolConditionDirectly | Return the condition `...` directly | 🛠 | @@ -990,6 +994,7 @@ For more, see [flake8-simplify](https://pypi.org/project/flake8-simplify/0.19.3/ | SIM110 | ConvertLoopToAny | Use `return any(x for x in y)` instead of `for` loop | 🛠 | | SIM111 | ConvertLoopToAll | Use `return all(x for x in y)` instead of `for` loop | 🛠 | | SIM112 | UseCapitalEnvironmentVariables | Use capitalized environment variable `...` instead of `...` | 🛠 | +| SIM115 | OpenFileWithContextHandler | Use context handler for opening files | | | SIM117 | MultipleWithStatements | Use a single `with` statement with multiple contexts instead of nested `with` statements | | | SIM118 | KeyInDict | Use `key in dict` instead of `key in dict.keys()` | 🛠 | | SIM201 | NegateEqualOp | Use `left != right` instead of `not left == right` | 🛠 | @@ -1084,20 +1089,33 @@ For more, see [pygrep-hooks](https://github.com/pre-commit/pygrep-hooks) on GitH For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI. +#### Convention (PLC) | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | PLC0414 | UselessImportAlias | Import alias does not rename original package | 🛠 | | PLC2201 | MisplacedComparisonConstant | Comparison should be ... | 🛠 | | PLC3002 | UnnecessaryDirectLambdaCall | Lambda expression called directly. Execute the expression inline instead. | | + +#### Error (PLE) +| Code | Name | Message | Fix | +| ---- | ---- | ------- | --- | | PLE0117 | NonlocalWithoutBinding | Nonlocal name `...` found without binding | | | PLE0118 | UsedPriorGlobalDeclaration | Name `...` is used prior to global declaration on line 1 | | | PLE1142 | AwaitOutsideAsync | `await` should be used within an async function | | + +#### Refactor (PLR) +| Code | Name | Message | Fix | +| ---- | ---- | ------- | --- | +| PLR0133 | ConstantComparison | Two constants compared in a comparison, consider replacing `0 == 0` | | | PLR0206 | PropertyWithParameters | Cannot have defined parameters for properties | | | PLR0402 | ConsiderUsingFromImport | Use `from ... import ...` in lieu of alias | | -| PLR0133 | ConstantComparison | Two constants compared in a comparison, consider replacing `0 == 0` | | | PLR1701 | ConsiderMergingIsinstance | Merge these isinstance calls: `isinstance(..., (...))` | | | PLR1722 | UseSysExit | Use `sys.exit()` instead of `exit` | 🛠 | | PLR2004 | MagicValueComparison | Magic number used in comparison, consider replacing magic with a constant variable | | + +#### Warning (PLW) +| Code | Name | Message | Fix | +| ---- | ---- | ------- | --- | | PLW0120 | UselessElseOnLoop | Else clause on loop without a break statement, remove the else and de-indent all the code inside it | | | PLW0602 | GlobalVariableNotAssigned | Using global for `...` but no assignment is done | | diff --git a/ruff_cli/tests/black_compatibility_test.rs b/ruff_cli/tests/black_compatibility_test.rs index d366a80c67..7e3cb6ffc3 100644 --- a/ruff_cli/tests/black_compatibility_test.rs +++ b/ruff_cli/tests/black_compatibility_test.rs @@ -180,7 +180,7 @@ fn test_ruff_black_compatibility() -> Result<()> { // problem. Ruff would add a `# noqa: W292` after the first run, black introduces a // newline, and ruff removes the `# noqa: W292` again. .filter(|origin| *origin != RuleOrigin::Ruff) - .map(|origin| origin.codes().iter().map(AsRef::as_ref).join(",")) + .map(|origin| origin.prefixes().as_list(",")) .join(","); let ruff_args = [ "-", diff --git a/ruff_dev/src/generate_rules_table.rs b/ruff_dev/src/generate_rules_table.rs index d0b3cd04a7..dad9f59106 100644 --- a/ruff_dev/src/generate_rules_table.rs +++ b/ruff_dev/src/generate_rules_table.rs @@ -2,8 +2,7 @@ use anyhow::Result; use clap::Args; -use itertools::Itertools; -use ruff::registry::{RuleCode, RuleOrigin}; +use ruff::registry::{Prefixes, RuleCodePrefix, RuleOrigin}; use strum::IntoEnumIterator; use crate::utils::replace_readme_section; @@ -21,12 +20,33 @@ pub struct Cli { pub(crate) dry_run: bool, } +fn generate_table(table_out: &mut String, prefix: &RuleCodePrefix) { + table_out.push_str("| Code | Name | Message | Fix |"); + table_out.push('\n'); + table_out.push_str("| ---- | ---- | ------- | --- |"); + table_out.push('\n'); + for rule_code in prefix.codes() { + let kind = rule_code.kind(); + let fix_token = if kind.fixable() { "🛠" } else { "" }; + table_out.push_str(&format!( + "| {} | {} | {} | {} |", + kind.code().as_ref(), + kind.as_ref(), + kind.summary().replace('|', r"\|"), + fix_token + )); + table_out.push('\n'); + } + table_out.push('\n'); +} + pub fn main(cli: &Cli) -> Result<()> { // Generate the table string. let mut table_out = String::new(); let mut toc_out = String::new(); for origin in RuleOrigin::iter() { - let codes_csv: String = origin.codes().iter().map(AsRef::as_ref).join(", "); + let prefixes = origin.prefixes(); + let codes_csv: String = prefixes.as_list(", "); table_out.push_str(&format!("### {} ({codes_csv})", origin.title())); table_out.push('\n'); table_out.push('\n'); @@ -50,26 +70,16 @@ pub fn main(cli: &Cli) -> Result<()> { table_out.push('\n'); } - table_out.push_str("| Code | Name | Message | Fix |"); - table_out.push('\n'); - table_out.push_str("| ---- | ---- | ------- | --- |"); - table_out.push('\n'); - - for rule_code in RuleCode::iter() { - if rule_code.origin() == origin { - let kind = rule_code.kind(); - let fix_token = if kind.fixable() { "🛠" } else { "" }; - table_out.push_str(&format!( - "| {} | {} | {} | {} |", - kind.code().as_ref(), - kind.as_ref(), - kind.summary().replace('|', r"\|"), - fix_token - )); - table_out.push('\n'); + match prefixes { + Prefixes::Single(prefix) => generate_table(&mut table_out, &prefix), + Prefixes::Multiple(entries) => { + for (prefix, category) in entries { + table_out.push_str(&format!("#### {category} ({})", prefix.as_ref())); + table_out.push('\n'); + generate_table(&mut table_out, &prefix); + } } } - table_out.push('\n'); } if cli.dry_run { diff --git a/src/registry.rs b/src/registry.rs index 04afdbc1ec..864581f542 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -2,6 +2,7 @@ use std::fmt; +use itertools::Itertools; use once_cell::sync::Lazy; use ruff_macros::RuleCodePrefix; use rustc_hash::FxHashMap; @@ -568,6 +569,23 @@ impl fmt::Display for Platform { } } +pub enum Prefixes { + Single(RuleCodePrefix), + Multiple(Vec<(RuleCodePrefix, &'static str)>), +} + +impl Prefixes { + pub fn as_list(&self, separator: &str) -> String { + match self { + Prefixes::Single(prefix) => prefix.as_ref().to_string(), + Prefixes::Multiple(entries) => entries + .iter() + .map(|(prefix, _)| prefix.as_ref()) + .join(separator), + } + } +} + impl RuleOrigin { pub fn title(&self) -> &'static str { match self { @@ -607,46 +625,49 @@ impl RuleOrigin { } } - pub fn codes(&self) -> Vec { + pub fn prefixes(&self) -> Prefixes { match self { - RuleOrigin::Eradicate => vec![RuleCodePrefix::ERA], - RuleOrigin::Flake82020 => vec![RuleCodePrefix::YTT], - RuleOrigin::Flake8Annotations => vec![RuleCodePrefix::ANN], - RuleOrigin::Flake8Bandit => vec![RuleCodePrefix::S], - RuleOrigin::Flake8BlindExcept => vec![RuleCodePrefix::BLE], - RuleOrigin::Flake8BooleanTrap => vec![RuleCodePrefix::FBT], - RuleOrigin::Flake8Bugbear => vec![RuleCodePrefix::B], - RuleOrigin::Flake8Builtins => vec![RuleCodePrefix::A], - RuleOrigin::Flake8Comprehensions => vec![RuleCodePrefix::C4], - RuleOrigin::Flake8Datetimez => vec![RuleCodePrefix::DTZ], - RuleOrigin::Flake8Debugger => vec![RuleCodePrefix::T10], - RuleOrigin::Flake8ErrMsg => vec![RuleCodePrefix::EM], - RuleOrigin::Flake8ImplicitStrConcat => vec![RuleCodePrefix::ISC], - RuleOrigin::Flake8ImportConventions => vec![RuleCodePrefix::ICN], - RuleOrigin::Flake8Print => vec![RuleCodePrefix::T20], - RuleOrigin::Flake8PytestStyle => vec![RuleCodePrefix::PT], - RuleOrigin::Flake8Quotes => vec![RuleCodePrefix::Q], - RuleOrigin::Flake8Return => vec![RuleCodePrefix::RET], - RuleOrigin::Flake8Simplify => vec![RuleCodePrefix::SIM], - RuleOrigin::Flake8TidyImports => vec![RuleCodePrefix::TID], - RuleOrigin::Flake8UnusedArguments => vec![RuleCodePrefix::ARG], - RuleOrigin::Isort => vec![RuleCodePrefix::I], - RuleOrigin::McCabe => vec![RuleCodePrefix::C90], - RuleOrigin::PEP8Naming => vec![RuleCodePrefix::N], - RuleOrigin::PandasVet => vec![RuleCodePrefix::PD], - RuleOrigin::Pycodestyle => vec![RuleCodePrefix::E, RuleCodePrefix::W], - RuleOrigin::Pydocstyle => vec![RuleCodePrefix::D], - RuleOrigin::Pyflakes => vec![RuleCodePrefix::F], - RuleOrigin::PygrepHooks => vec![RuleCodePrefix::PGH], - RuleOrigin::Pylint => vec![ - RuleCodePrefix::PLC, - RuleCodePrefix::PLE, - RuleCodePrefix::PLR, - RuleCodePrefix::PLW, - ], - RuleOrigin::Pyupgrade => vec![RuleCodePrefix::UP], - RuleOrigin::Flake8Pie => vec![RuleCodePrefix::PIE], - RuleOrigin::Ruff => vec![RuleCodePrefix::RUF], + RuleOrigin::Eradicate => Prefixes::Single(RuleCodePrefix::ERA), + RuleOrigin::Flake82020 => Prefixes::Single(RuleCodePrefix::YTT), + RuleOrigin::Flake8Annotations => Prefixes::Single(RuleCodePrefix::ANN), + RuleOrigin::Flake8Bandit => Prefixes::Single(RuleCodePrefix::S), + RuleOrigin::Flake8BlindExcept => Prefixes::Single(RuleCodePrefix::BLE), + RuleOrigin::Flake8BooleanTrap => Prefixes::Single(RuleCodePrefix::FBT), + RuleOrigin::Flake8Bugbear => Prefixes::Single(RuleCodePrefix::B), + RuleOrigin::Flake8Builtins => Prefixes::Single(RuleCodePrefix::A), + RuleOrigin::Flake8Comprehensions => Prefixes::Single(RuleCodePrefix::C4), + RuleOrigin::Flake8Datetimez => Prefixes::Single(RuleCodePrefix::DTZ), + RuleOrigin::Flake8Debugger => Prefixes::Single(RuleCodePrefix::T10), + RuleOrigin::Flake8ErrMsg => Prefixes::Single(RuleCodePrefix::EM), + RuleOrigin::Flake8ImplicitStrConcat => Prefixes::Single(RuleCodePrefix::ISC), + RuleOrigin::Flake8ImportConventions => Prefixes::Single(RuleCodePrefix::ICN), + RuleOrigin::Flake8Print => Prefixes::Single(RuleCodePrefix::T20), + RuleOrigin::Flake8PytestStyle => Prefixes::Single(RuleCodePrefix::PT), + RuleOrigin::Flake8Quotes => Prefixes::Single(RuleCodePrefix::Q), + RuleOrigin::Flake8Return => Prefixes::Single(RuleCodePrefix::RET), + RuleOrigin::Flake8Simplify => Prefixes::Single(RuleCodePrefix::SIM), + RuleOrigin::Flake8TidyImports => Prefixes::Single(RuleCodePrefix::TID), + RuleOrigin::Flake8UnusedArguments => Prefixes::Single(RuleCodePrefix::ARG), + RuleOrigin::Isort => Prefixes::Single(RuleCodePrefix::I), + RuleOrigin::McCabe => Prefixes::Single(RuleCodePrefix::C90), + RuleOrigin::PEP8Naming => Prefixes::Single(RuleCodePrefix::N), + RuleOrigin::PandasVet => Prefixes::Single(RuleCodePrefix::PD), + RuleOrigin::Pycodestyle => Prefixes::Multiple(vec![ + (RuleCodePrefix::E, "Error"), + (RuleCodePrefix::W, "Warning"), + ]), + RuleOrigin::Pydocstyle => Prefixes::Single(RuleCodePrefix::D), + RuleOrigin::Pyflakes => Prefixes::Single(RuleCodePrefix::F), + RuleOrigin::PygrepHooks => Prefixes::Single(RuleCodePrefix::PGH), + RuleOrigin::Pylint => Prefixes::Multiple(vec![ + (RuleCodePrefix::PLC, "Convention"), + (RuleCodePrefix::PLE, "Error"), + (RuleCodePrefix::PLR, "Refactor"), + (RuleCodePrefix::PLW, "Warning"), + ]), + RuleOrigin::Pyupgrade => Prefixes::Single(RuleCodePrefix::UP), + RuleOrigin::Flake8Pie => Prefixes::Single(RuleCodePrefix::PIE), + RuleOrigin::Ruff => Prefixes::Single(RuleCodePrefix::RUF), } }