From 2e1799dd800c4698927c547e2bfc9fa8f85cbbe8 Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Sat, 5 Nov 2022 15:33:47 -0400 Subject: [PATCH] Automatically update README.md from generate_rules_table.rs (#606) --- README.md | 31 ++++++----- examples/generate_check_code_prefix.rs | 46 ++++++++-------- examples/generate_rules_table.rs | 73 ++++++++++++++++++++++---- 3 files changed, 104 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index 57a0a2865d..f9b400c322 100644 --- a/README.md +++ b/README.md @@ -295,9 +295,12 @@ By default, Ruff enables all `E` and `F` error codes, which correspond to those The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` command-line option. + + + ### Pyflakes -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | F401 | UnusedImport | `...` imported but unused | 🛠 | | F402 | ImportShadowedByLoopVar | Import `...` from line 1 shadowed by loop variable | | @@ -330,7 +333,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### pycodestyle (error) -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | E402 | ModuleImportNotAtTopOfFile | Module level import not at top of file | | | E501 | LineTooLong | Line too long (89 > 88 characters) | | @@ -349,14 +352,14 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### pycodestyle (warning) -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | W292 | NoNewLineAtEndOfFile | No newline at end of file | | | W605 | InvalidEscapeSequence | Invalid escape sequence: '\c' | | ### pydocstyle -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | D100 | PublicModule | Missing docstring in public module | | | D101 | PublicClass | Missing docstring in public class | | @@ -405,7 +408,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### pyupgrade -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | U001 | UselessMetaclassType | `__metaclass__ = type` is implied | 🛠 | | U002 | UnnecessaryAbspath | `abspath(__file__)` is unnecessary in Python 3.9 and later | 🛠 | @@ -418,7 +421,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### pep8-naming -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | N801 | InvalidClassName | Class name `...` should use CapWords convention | | | N802 | InvalidFunctionName | Function name `...` should be lowercase | | @@ -438,7 +441,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### flake8-comprehensions -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | C400 | UnnecessaryGeneratorList | Unnecessary generator (rewrite as a `list` comprehension) | 🛠 | | C401 | UnnecessaryGeneratorSet | Unnecessary generator (rewrite as a `set` comprehension) | 🛠 | @@ -459,7 +462,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### flake8-bugbear -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | B002 | UnaryPrefixIncrement | Python does not support the unary prefix increment. | | | B003 | AssignmentToOsEnviron | Assigning to `os.environ` doesn't clear the environment. | | @@ -477,7 +480,7 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### flake8-builtins -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | A001 | BuiltinVariableShadowing | Variable `...` is shadowing a python builtin | | | A002 | BuiltinArgumentShadowing | Argument `...` is shadowing a python builtin | | @@ -485,14 +488,14 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### flake8-print -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | T201 | PrintFound | `print` found | 🛠 | | T203 | PPrintFound | `pprint` found | 🛠 | ### flake8-quotes -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | Q000 | BadQuotesInlineString | Single quotes found but double quotes preferred | | | Q001 | BadQuotesMultilineString | Single quote multiline found but double quotes preferred | | @@ -501,17 +504,19 @@ The 🛠 emoji indicates that a rule is automatically fixable by the `--fix` com ### Ruff-specific rules -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | RUF001 | AmbiguousUnicodeCharacterString | String contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 | | RUF002 | AmbiguousUnicodeCharacterDocstring | Docstring contains ambiguous unicode character '𝐁' (did you mean 'B'?) | 🛠 | ### Meta rules -| Code | Name | Message | Fix | +| Coade | Name | Message | Fix | | ---- | ---- | ------- | --- | | M001 | UnusedNOQA | Unused `noqa` directive | 🛠 | + + ## Editor Integrations ### PyCharm diff --git a/examples/generate_check_code_prefix.rs b/examples/generate_check_code_prefix.rs index bed8132148..434a9c41f7 100644 --- a/examples/generate_check_code_prefix.rs +++ b/examples/generate_check_code_prefix.rs @@ -1,6 +1,5 @@ use std::collections::{BTreeMap, BTreeSet}; use std::fs::OpenOptions; -use std::io; use std::io::Write; use anyhow::Result; @@ -10,6 +9,8 @@ use itertools::Itertools; use ruff::checks::CheckCode; use strum::IntoEnumIterator; +const FILE: &str = "src/checks_gen.rs"; + #[derive(Parser)] #[command(author, version, about, long_about = None)] /// Generate the `CheckCodePrefix` enum. @@ -115,29 +116,28 @@ fn main() -> Result<()> { } gen.line("}"); - // Write the output to `src/checks_gen.rs`. - let mut writer = if cli.dry_run { - Box::new(io::stdout()) as Box - } else { - let f = OpenOptions::new() - .write(true) - .truncate(true) - .open("src/checks_gen.rs") - .expect("unable to open file"); - Box::new(f) as Box - }; + // Construct the output contents. + let mut output = String::new(); + output.push_str("//! File automatically generated by examples/generate_check_code_prefix.rs."); + output.push('\n'); + output.push('\n'); + output.push_str("use serde::{{Serialize, Deserialize}};"); + output.push('\n'); + output.push_str("use strum_macros::EnumString;"); + output.push('\n'); + output.push('\n'); + output.push_str("use crate::checks::CheckCode;"); + output.push('\n'); + output.push('\n'); + output.push_str(&format!("{}", scope.to_string())); - writeln!( - writer, - "//! File automatically generated by examples/generate_check_code_prefix.rs." - )?; - writeln!(writer)?; - writeln!(writer, "use serde::{{Serialize, Deserialize}};")?; - writeln!(writer, "use strum_macros::EnumString;")?; - writeln!(writer)?; - writeln!(writer, "use crate::checks::CheckCode;")?; - writeln!(writer)?; - writeln!(writer, "{}", scope.to_string())?; + // Write the output to `src/checks_gen.rs` (or stdout). + if cli.dry_run { + println!("{}", output); + } else { + let mut f = OpenOptions::new().write(true).truncate(true).open(FILE)?; + write!(f, "{}", output)?; + } Ok(()) } diff --git a/examples/generate_rules_table.rs b/examples/generate_rules_table.rs index f2c7bf8b52..cfafa2e3fb 100644 --- a/examples/generate_rules_table.rs +++ b/examples/generate_rules_table.rs @@ -1,28 +1,81 @@ -//! Generate a Markdown-compatible table of supported lint rules. +use std::fs; +use std::fs::OpenOptions; +use std::io::Write; +use anyhow::Result; +use clap::Parser; use ruff::checks::{CheckCategory, CheckCode}; use strum::IntoEnumIterator; -fn main() { - for check_category in CheckCategory::iter() { - println!("### {}", check_category.title()); - println!(); +const FILE: &str = "README.md"; +const BEGIN_PRAGMA: &str = ""; +const END_PRAGMA: &str = ""; + +#[derive(Parser)] +#[command(author, version, about, long_about = None)] +/// Generate a Markdown-compatible table of supported lint rules. +struct Cli { + /// Write the generated table to stdout (rather than to `README.md`). + #[arg(long)] + dry_run: bool, +} + +fn main() -> Result<()> { + let cli = Cli::parse(); + + // Generate the table string. + let mut output = String::new(); + for check_category in CheckCategory::iter() { + output.push_str(&format!("### {}", check_category.title())); + output.push('\n'); + output.push('\n'); + + output.push_str("| Coade | Name | Message | Fix |"); + output.push('\n'); + output.push_str("| ---- | ---- | ------- | --- |"); + output.push('\n'); - println!("| Code | Name | Message | Fix |"); - println!("| ---- | ---- | ------- | --- |"); for check_code in CheckCode::iter() { if check_code.category() == check_category { let check_kind = check_code.kind(); let fix_token = if check_kind.fixable() { "🛠" } else { "" }; - println!( + output.push_str(&format!( "| {} | {} | {} | {} |", check_kind.code().as_ref(), check_kind.as_ref(), check_kind.summary().replace("|", r"\|"), fix_token - ); + )); + output.push('\n'); } } - println!(); + output.push('\n'); } + + if cli.dry_run { + print!("{}", output); + } else { + // Read the existing file. + let existing = fs::read_to_string(FILE)?; + + // Extract the prefix. + let index = existing + .find(BEGIN_PRAGMA) + .expect("Unable to find begin pragma."); + let prefix = &existing[..index + BEGIN_PRAGMA.len()]; + + // Extract the suffix. + let index = existing + .find(END_PRAGMA) + .expect("Unable to find end pragma."); + let suffix = &existing[index..]; + + // Write the prefix, new contents, and suffix. + let mut f = OpenOptions::new().write(true).truncate(true).open(FILE)?; + write!(f, "{}\n\n", prefix)?; + write!(f, "{}", output)?; + write!(f, "{}", suffix)?; + } + + Ok(()) }