Skip to content

Commit

Permalink
Automatically update README.md from generate_rules_table.rs (#606)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh committed Nov 5, 2022
1 parent c48c766 commit 2e1799d
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 45 deletions.
31 changes: 18 additions & 13 deletions README.md
Expand Up @@ -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.
<!-- Sections automatically generated by examples/generate_rules_table.rs. -->
<!-- Begin auto-generated sections. -->
### Pyflakes
| Code | Name | Message | Fix |
| Coade | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| F401 | UnusedImport | `...` imported but unused | 🛠 |
| F402 | ImportShadowedByLoopVar | Import `...` from line 1 shadowed by loop variable | |
Expand Down Expand Up @@ -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) | |
Expand All @@ -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 | |
Expand Down Expand Up @@ -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 | 🛠 |
Expand All @@ -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 | |
Expand All @@ -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) | 🛠 |
Expand All @@ -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. | |
Expand All @@ -477,22 +480,22 @@ 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 | |
| A003 | BuiltinAttributeShadowing | Class attribute `...` is shadowing a python builtin | |
### 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 | |
Expand All @@ -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 | 🛠 |
<!-- End auto-generated sections. -->
## Editor Integrations
### PyCharm
Expand Down
46 changes: 23 additions & 23 deletions 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;
Expand All @@ -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.
Expand Down Expand Up @@ -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<dyn Write>
} else {
let f = OpenOptions::new()
.write(true)
.truncate(true)
.open("src/checks_gen.rs")
.expect("unable to open file");
Box::new(f) as Box<dyn Write>
};
// 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(())
}
71 changes: 62 additions & 9 deletions 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() {
const FILE: &str = "README.md";
const BEGIN_PRAGMA: &str = "<!-- Begin auto-generated sections. -->";
const END_PRAGMA: &str = "<!-- End auto-generated sections. -->";

#[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() {
println!("### {}", check_category.title());
println!();
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(())
}

0 comments on commit 2e1799d

Please sign in to comment.