Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Automatically update README.md from generate_rules_table.rs #606

Merged
merged 1 commit into from Nov 5, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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(())
}