Split up the table corresponding to the pylint rules (#1868)

This makes it easier to see which rules you're enabling when selecting
one of the pylint codes (like `PLC`). This also makes it clearer what
those abbreviations stand for. When I first saw the pylint section, I
was very confused by that, so other might be as well.

See it rendered here:
https://github.com/thomkeh/ruff/blob/patch-1/README.md#pylint-plc-ple-plr-plw
This commit is contained in:
Thomas MK 2023-01-14 14:07:02 +01:00 committed by GitHub
parent 3447dd3615
commit 9dc66b5a65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 112 additions and 63 deletions

View file

@ -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. For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI.
#### Error (E)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| E401 | MultipleImportsOnOneLine | Multiple imports on one line | | | 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: `...` | | | E743 | AmbiguousFunctionName | Ambiguous function name: `...` | |
| E902 | IOError | IOError: `...` | | | E902 | IOError | IOError: `...` | |
| E999 | SyntaxError | SyntaxError: `...` | | | E999 | SyntaxError | SyntaxError: `...` | |
#### Warning (W)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| W292 | NoNewLineAtEndOfFile | No newline at end of file | 🛠 | | W292 | NoNewLineAtEndOfFile | No newline at end of file | 🛠 |
| W505 | DocLineTooLong | Doc line too long (89 > 88 characters) | | | W505 | DocLineTooLong | Doc line too long (89 > 88 characters) | |
| W605 | InvalidEscapeSequence | Invalid escape sequence: '\c' | 🛠 | | 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 | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| SIM115 | OpenFileWithContextHandler | Use context handler for opening files | |
| SIM101 | DuplicateIsinstanceCall | Multiple `isinstance` calls for `...`, merge into a single call | 🛠 | | SIM101 | DuplicateIsinstanceCall | Multiple `isinstance` calls for `...`, merge into a single call | 🛠 |
| SIM102 | NestedIfStatements | Use a single `if` statement instead of nested `if` statements | | | SIM102 | NestedIfStatements | Use a single `if` statement instead of nested `if` statements | |
| SIM103 | ReturnBoolConditionDirectly | Return the condition `...` directly | 🛠 | | 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 | 🛠 | | 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 | 🛠 | | SIM111 | ConvertLoopToAll | Use `return all(x for x in y)` instead of `for` loop | 🛠 |
| SIM112 | UseCapitalEnvironmentVariables | Use capitalized environment variable `...` instead of `...` | 🛠 | | 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 | | | 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()` | 🛠 | | SIM118 | KeyInDict | Use `key in dict` instead of `key in dict.keys()` | 🛠 |
| SIM201 | NegateEqualOp | Use `left != right` instead of `not left == right` | 🛠 | | 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. For more, see [Pylint](https://pypi.org/project/pylint/2.15.7/) on PyPI.
#### Convention (PLC)
| Code | Name | Message | Fix | | Code | Name | Message | Fix |
| ---- | ---- | ------- | --- | | ---- | ---- | ------- | --- |
| PLC0414 | UselessImportAlias | Import alias does not rename original package | 🛠 | | PLC0414 | UselessImportAlias | Import alias does not rename original package | 🛠 |
| PLC2201 | MisplacedComparisonConstant | Comparison should be ... | 🛠 | | PLC2201 | MisplacedComparisonConstant | Comparison should be ... | 🛠 |
| PLC3002 | UnnecessaryDirectLambdaCall | Lambda expression called directly. Execute the expression inline instead. | | | PLC3002 | UnnecessaryDirectLambdaCall | Lambda expression called directly. Execute the expression inline instead. | |
#### Error (PLE)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| PLE0117 | NonlocalWithoutBinding | Nonlocal name `...` found without binding | | | PLE0117 | NonlocalWithoutBinding | Nonlocal name `...` found without binding | |
| PLE0118 | UsedPriorGlobalDeclaration | Name `...` is used prior to global declaration on line 1 | | | PLE0118 | UsedPriorGlobalDeclaration | Name `...` is used prior to global declaration on line 1 | |
| PLE1142 | AwaitOutsideAsync | `await` should be used within an async function | | | 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 | | | PLR0206 | PropertyWithParameters | Cannot have defined parameters for properties | |
| PLR0402 | ConsiderUsingFromImport | Use `from ... import ...` in lieu of alias | | | 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(..., (...))` | | | PLR1701 | ConsiderMergingIsinstance | Merge these isinstance calls: `isinstance(..., (...))` | |
| PLR1722 | UseSysExit | Use `sys.exit()` instead of `exit` | 🛠 | | PLR1722 | UseSysExit | Use `sys.exit()` instead of `exit` | 🛠 |
| PLR2004 | MagicValueComparison | Magic number used in comparison, consider replacing magic with a constant variable | | | 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 | | | 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 | | | PLW0602 | GlobalVariableNotAssigned | Using global for `...` but no assignment is done | |

View file

@ -180,7 +180,7 @@ fn test_ruff_black_compatibility() -> Result<()> {
// problem. Ruff would add a `# noqa: W292` after the first run, black introduces a // problem. Ruff would add a `# noqa: W292` after the first run, black introduces a
// newline, and ruff removes the `# noqa: W292` again. // newline, and ruff removes the `# noqa: W292` again.
.filter(|origin| *origin != RuleOrigin::Ruff) .filter(|origin| *origin != RuleOrigin::Ruff)
.map(|origin| origin.codes().iter().map(AsRef::as_ref).join(",")) .map(|origin| origin.prefixes().as_list(","))
.join(","); .join(",");
let ruff_args = [ let ruff_args = [
"-", "-",

View file

@ -2,8 +2,7 @@
use anyhow::Result; use anyhow::Result;
use clap::Args; use clap::Args;
use itertools::Itertools; use ruff::registry::{Prefixes, RuleCodePrefix, RuleOrigin};
use ruff::registry::{RuleCode, RuleOrigin};
use strum::IntoEnumIterator; use strum::IntoEnumIterator;
use crate::utils::replace_readme_section; use crate::utils::replace_readme_section;
@ -21,12 +20,33 @@ pub struct Cli {
pub(crate) dry_run: bool, 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<()> { pub fn main(cli: &Cli) -> Result<()> {
// Generate the table string. // Generate the table string.
let mut table_out = String::new(); let mut table_out = String::new();
let mut toc_out = String::new(); let mut toc_out = String::new();
for origin in RuleOrigin::iter() { 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_str(&format!("### {} ({codes_csv})", origin.title()));
table_out.push('\n'); table_out.push('\n');
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('\n');
} }
table_out.push_str("| Code | Name | Message | Fix |"); match prefixes {
table_out.push('\n'); Prefixes::Single(prefix) => generate_table(&mut table_out, &prefix),
table_out.push_str("| ---- | ---- | ------- | --- |"); Prefixes::Multiple(entries) => {
table_out.push('\n'); for (prefix, category) in entries {
table_out.push_str(&format!("#### {category} ({})", prefix.as_ref()));
for rule_code in RuleCode::iter() { table_out.push('\n');
if rule_code.origin() == origin { generate_table(&mut table_out, &prefix);
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');
} }
if cli.dry_run { if cli.dry_run {

View file

@ -2,6 +2,7 @@
use std::fmt; use std::fmt;
use itertools::Itertools;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use ruff_macros::RuleCodePrefix; use ruff_macros::RuleCodePrefix;
use rustc_hash::FxHashMap; 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 { impl RuleOrigin {
pub fn title(&self) -> &'static str { pub fn title(&self) -> &'static str {
match self { match self {
@ -607,46 +625,49 @@ impl RuleOrigin {
} }
} }
pub fn codes(&self) -> Vec<RuleCodePrefix> { pub fn prefixes(&self) -> Prefixes {
match self { match self {
RuleOrigin::Eradicate => vec![RuleCodePrefix::ERA], RuleOrigin::Eradicate => Prefixes::Single(RuleCodePrefix::ERA),
RuleOrigin::Flake82020 => vec![RuleCodePrefix::YTT], RuleOrigin::Flake82020 => Prefixes::Single(RuleCodePrefix::YTT),
RuleOrigin::Flake8Annotations => vec![RuleCodePrefix::ANN], RuleOrigin::Flake8Annotations => Prefixes::Single(RuleCodePrefix::ANN),
RuleOrigin::Flake8Bandit => vec![RuleCodePrefix::S], RuleOrigin::Flake8Bandit => Prefixes::Single(RuleCodePrefix::S),
RuleOrigin::Flake8BlindExcept => vec![RuleCodePrefix::BLE], RuleOrigin::Flake8BlindExcept => Prefixes::Single(RuleCodePrefix::BLE),
RuleOrigin::Flake8BooleanTrap => vec![RuleCodePrefix::FBT], RuleOrigin::Flake8BooleanTrap => Prefixes::Single(RuleCodePrefix::FBT),
RuleOrigin::Flake8Bugbear => vec![RuleCodePrefix::B], RuleOrigin::Flake8Bugbear => Prefixes::Single(RuleCodePrefix::B),
RuleOrigin::Flake8Builtins => vec![RuleCodePrefix::A], RuleOrigin::Flake8Builtins => Prefixes::Single(RuleCodePrefix::A),
RuleOrigin::Flake8Comprehensions => vec![RuleCodePrefix::C4], RuleOrigin::Flake8Comprehensions => Prefixes::Single(RuleCodePrefix::C4),
RuleOrigin::Flake8Datetimez => vec![RuleCodePrefix::DTZ], RuleOrigin::Flake8Datetimez => Prefixes::Single(RuleCodePrefix::DTZ),
RuleOrigin::Flake8Debugger => vec![RuleCodePrefix::T10], RuleOrigin::Flake8Debugger => Prefixes::Single(RuleCodePrefix::T10),
RuleOrigin::Flake8ErrMsg => vec![RuleCodePrefix::EM], RuleOrigin::Flake8ErrMsg => Prefixes::Single(RuleCodePrefix::EM),
RuleOrigin::Flake8ImplicitStrConcat => vec![RuleCodePrefix::ISC], RuleOrigin::Flake8ImplicitStrConcat => Prefixes::Single(RuleCodePrefix::ISC),
RuleOrigin::Flake8ImportConventions => vec![RuleCodePrefix::ICN], RuleOrigin::Flake8ImportConventions => Prefixes::Single(RuleCodePrefix::ICN),
RuleOrigin::Flake8Print => vec![RuleCodePrefix::T20], RuleOrigin::Flake8Print => Prefixes::Single(RuleCodePrefix::T20),
RuleOrigin::Flake8PytestStyle => vec![RuleCodePrefix::PT], RuleOrigin::Flake8PytestStyle => Prefixes::Single(RuleCodePrefix::PT),
RuleOrigin::Flake8Quotes => vec![RuleCodePrefix::Q], RuleOrigin::Flake8Quotes => Prefixes::Single(RuleCodePrefix::Q),
RuleOrigin::Flake8Return => vec![RuleCodePrefix::RET], RuleOrigin::Flake8Return => Prefixes::Single(RuleCodePrefix::RET),
RuleOrigin::Flake8Simplify => vec![RuleCodePrefix::SIM], RuleOrigin::Flake8Simplify => Prefixes::Single(RuleCodePrefix::SIM),
RuleOrigin::Flake8TidyImports => vec![RuleCodePrefix::TID], RuleOrigin::Flake8TidyImports => Prefixes::Single(RuleCodePrefix::TID),
RuleOrigin::Flake8UnusedArguments => vec![RuleCodePrefix::ARG], RuleOrigin::Flake8UnusedArguments => Prefixes::Single(RuleCodePrefix::ARG),
RuleOrigin::Isort => vec![RuleCodePrefix::I], RuleOrigin::Isort => Prefixes::Single(RuleCodePrefix::I),
RuleOrigin::McCabe => vec![RuleCodePrefix::C90], RuleOrigin::McCabe => Prefixes::Single(RuleCodePrefix::C90),
RuleOrigin::PEP8Naming => vec![RuleCodePrefix::N], RuleOrigin::PEP8Naming => Prefixes::Single(RuleCodePrefix::N),
RuleOrigin::PandasVet => vec![RuleCodePrefix::PD], RuleOrigin::PandasVet => Prefixes::Single(RuleCodePrefix::PD),
RuleOrigin::Pycodestyle => vec![RuleCodePrefix::E, RuleCodePrefix::W], RuleOrigin::Pycodestyle => Prefixes::Multiple(vec![
RuleOrigin::Pydocstyle => vec![RuleCodePrefix::D], (RuleCodePrefix::E, "Error"),
RuleOrigin::Pyflakes => vec![RuleCodePrefix::F], (RuleCodePrefix::W, "Warning"),
RuleOrigin::PygrepHooks => vec![RuleCodePrefix::PGH], ]),
RuleOrigin::Pylint => vec![ RuleOrigin::Pydocstyle => Prefixes::Single(RuleCodePrefix::D),
RuleCodePrefix::PLC, RuleOrigin::Pyflakes => Prefixes::Single(RuleCodePrefix::F),
RuleCodePrefix::PLE, RuleOrigin::PygrepHooks => Prefixes::Single(RuleCodePrefix::PGH),
RuleCodePrefix::PLR, RuleOrigin::Pylint => Prefixes::Multiple(vec![
RuleCodePrefix::PLW, (RuleCodePrefix::PLC, "Convention"),
], (RuleCodePrefix::PLE, "Error"),
RuleOrigin::Pyupgrade => vec![RuleCodePrefix::UP], (RuleCodePrefix::PLR, "Refactor"),
RuleOrigin::Flake8Pie => vec![RuleCodePrefix::PIE], (RuleCodePrefix::PLW, "Warning"),
RuleOrigin::Ruff => vec![RuleCodePrefix::RUF], ]),
RuleOrigin::Pyupgrade => Prefixes::Single(RuleCodePrefix::UP),
RuleOrigin::Flake8Pie => Prefixes::Single(RuleCodePrefix::PIE),
RuleOrigin::Ruff => Prefixes::Single(RuleCodePrefix::RUF),
} }
} }