Implement `ruff linter` subcommand

The subcommand lists all supported upstream linters and their prefixes:

    $ ruff linter
       F Pyflakes
     E/W pycodestyle
     C90 mccabe
       I isort
       N pep8-naming
       D pydocstyle
      UP pyupgrade
     YTT flake8-2020
    # etc...

Just like with the `rule` subcommand `--format json` is supported:

    $ ruff linter --format json
    [
      {
        "prefix": "F",
        "name": "Pyflakes"
      },
      {
        "prefix": "",
        "name": "pycodestyle",
        "categories": [
          {
            "prefix": "E",
            "name": "Error"
          },
          {
            "prefix": "W",
            "name": "Warning"
          }
        ]
      },
      # etc...
This commit is contained in:
Martin Fischer 2023-01-28 08:41:47 +01:00 committed by Charlie Marsh
parent b532fce792
commit d76a47d366
6 changed files with 74 additions and 4 deletions

View File

@ -384,6 +384,7 @@ Usage: ruff [OPTIONS] <COMMAND>
Commands:
check Run Ruff on the given files or directories (default)
rule Explain a rule
linter List all supported upstream linters
clean Clear any caches in the current directory and any subdirectories
help Print this message or the help of the given subcommand(s)

View File

@ -53,6 +53,7 @@ similar = { version = "2.2.1" }
textwrap = { version = "0.16.0" }
update-informer = { version = "0.6.0", default-features = false, features = ["pypi"], optional = true }
walkdir = { version = "2.3.2" }
strum = "0.24.1"
[dev-dependencies]
assert_cmd = { version = "2.0.4" }

View File

@ -41,6 +41,12 @@ pub enum Command {
#[arg(long, value_enum, default_value = "text")]
format: HelpFormat,
},
/// List all supported upstream linters
Linter {
/// Output format
#[arg(long, value_enum, default_value = "text")]
format: HelpFormat,
},
/// Clear any caches in the current directory and any subdirectories.
#[clap(alias = "--clean")]
Clean,

View File

@ -27,6 +27,8 @@ use crate::cache;
use crate::diagnostics::{lint_path, lint_stdin, Diagnostics};
use crate::iterators::par_iter;
pub mod linter;
/// Run the linter over a collection of files.
pub fn run(
files: &[PathBuf],

View File

@ -0,0 +1,59 @@
use itertools::Itertools;
use serde::Serialize;
use strum::IntoEnumIterator;
use ruff::registry::{Linter, LinterCategory, RuleNamespace};
use crate::args::HelpFormat;
pub fn linter(format: HelpFormat) {
match format {
HelpFormat::Text => {
for linter in Linter::iter() {
let prefix = match linter.common_prefix() {
"" => linter
.categories()
.unwrap()
.iter()
.map(|LinterCategory(prefix, ..)| prefix)
.join("/"),
prefix => prefix.to_string(),
};
println!("{:>4} {}", prefix, linter.name());
}
}
HelpFormat::Json => {
let linters: Vec<_> = Linter::iter()
.map(|linter_info| LinterInfo {
prefix: linter_info.common_prefix(),
name: linter_info.name(),
categories: linter_info.categories().map(|cats| {
cats.iter()
.map(|LinterCategory(prefix, name, ..)| LinterCategoryInfo {
prefix,
name,
})
.collect()
}),
})
.collect();
println!("{}", serde_json::to_string_pretty(&linters).unwrap());
}
}
}
#[derive(Serialize)]
struct LinterInfo {
prefix: &'static str,
name: &'static str,
#[serde(skip_serializing_if = "Option::is_none")]
categories: Option<Vec<LinterCategoryInfo>>,
}
#[derive(Serialize)]
struct LinterCategoryInfo {
prefix: &'static str,
name: &'static str,
}

View File

@ -78,6 +78,7 @@ quoting the executed command, along with the relevant file contents and `pyproje
match command {
Command::Rule { rule, format } => commands::rule(rule, format)?,
Command::Linter { format } => commands::linter::linter(format),
Command::Clean => commands::clean(log_level)?,
Command::GenerateShellCompletion { shell } => {
shell.generate(&mut Args::command(), &mut io::stdout());