mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:53 +00:00
Add support for noqa pragmas (#11)
This commit is contained in:
parent
f01707b2ae
commit
3b1b53dacf
11 changed files with 105 additions and 15 deletions
27
Cargo.lock
generated
27
Cargo.lock
generated
|
@ -13,6 +13,15 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.4"
|
||||
|
@ -1482,6 +1491,23 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
|
@ -1507,6 +1533,7 @@ dependencies = [
|
|||
"notify",
|
||||
"pyo3",
|
||||
"rayon",
|
||||
"regex",
|
||||
"rustpython-parser",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
|
|
@ -18,9 +18,10 @@ colored = { version = "2.0.0" }
|
|||
fern = { version = "0.6.1" }
|
||||
log = { version = "0.4.17" }
|
||||
notify = { version = "4.0.17" }
|
||||
pyo3 = { version = "0.16.5", features = ["extension-module", "abi3-py37"] }
|
||||
rayon = { version = "1.5.3" }
|
||||
regex = { version = "1.6.0" }
|
||||
rustpython-parser = { git = "https://github.com/RustPython/RustPython.git", rev = "dff916d45c5d13074d21ad329a5ab68a6499426a" }
|
||||
serde = { version = "1.0.143", features = ["derive"] }
|
||||
serde_json = { version = "1.0.83" }
|
||||
walkdir = { version = "2.3.2" }
|
||||
pyo3 = { version = "0.16.5", features = ["extension-module", "abi3-py37"] }
|
||||
|
|
|
@ -1 +1,6 @@
|
|||
from if_tuple import *
|
||||
from if_tuple import * # noqa: E501
|
||||
|
||||
from if_tuple import * # noqa
|
||||
from if_tuple import * # noqa: F403
|
||||
from if_tuple import * # noqa: F403, E501
|
||||
|
|
|
@ -40,10 +40,10 @@ impl Visitor for Checker {
|
|||
fn visit_arguments(&mut self, arguments: &Arguments) {
|
||||
// Collect all the arguments into a single vector.
|
||||
let mut all_arguments: Vec<&Arg> = arguments
|
||||
.posonlyargs
|
||||
.args
|
||||
.iter()
|
||||
.chain(arguments.posonlyargs.iter())
|
||||
.chain(arguments.kwonlyargs.iter())
|
||||
.chain(arguments.args.iter())
|
||||
.collect();
|
||||
if let Some(arg) = &arguments.vararg {
|
||||
all_arguments.push(arg);
|
||||
|
|
|
@ -2,16 +2,17 @@ use rustpython_parser::ast::Location;
|
|||
|
||||
use crate::checks::Check;
|
||||
use crate::checks::CheckKind::LineTooLong;
|
||||
use crate::settings::MAX_LINE_LENGTH;
|
||||
|
||||
pub fn check_lines(contents: &str) -> Vec<Check> {
|
||||
contents
|
||||
.lines()
|
||||
.enumerate()
|
||||
.filter_map(|(row, line)| {
|
||||
if line.len() > 79 {
|
||||
if line.len() > *MAX_LINE_LENGTH {
|
||||
Some(Check {
|
||||
kind: LineTooLong,
|
||||
location: Location::new(row + 1, 79 + 1),
|
||||
location: Location::new(row + 1, MAX_LINE_LENGTH + 1),
|
||||
})
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -26,7 +26,7 @@ impl CheckKind {
|
|||
CheckKind::DuplicateArgumentName => "Duplicate argument name in function definition",
|
||||
CheckKind::IfTuple => "If test is a tuple, which is always `True`",
|
||||
CheckKind::ImportStarUsage => "Unable to detect undefined names",
|
||||
CheckKind::LineTooLong => "Line too long (> 79 characters)",
|
||||
CheckKind::LineTooLong => "Line too long",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
15
src/fs.rs
15
src/fs.rs
|
@ -1,7 +1,8 @@
|
|||
use anyhow::Result;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, Read};
|
||||
use std::io::{BufRead, BufReader, Read};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::Result;
|
||||
use walkdir::{DirEntry, WalkDir};
|
||||
|
||||
fn is_not_hidden(entry: &DirEntry) -> bool {
|
||||
|
@ -21,6 +22,16 @@ pub fn iter_python_files(path: &PathBuf) -> impl Iterator<Item = DirEntry> {
|
|||
.filter(|entry| entry.path().to_string_lossy().ends_with(".py"))
|
||||
}
|
||||
|
||||
pub fn read_line(path: &Path, row: &usize) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let buf_reader = BufReader::new(file);
|
||||
buf_reader
|
||||
.lines()
|
||||
.nth(*row - 1)
|
||||
.unwrap()
|
||||
.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
pub fn read_file(path: &Path) -> Result<String> {
|
||||
let file = File::open(path)?;
|
||||
let mut buf_reader = BufReader::new(file);
|
||||
|
|
|
@ -6,4 +6,5 @@ pub mod fs;
|
|||
pub mod linter;
|
||||
pub mod logging;
|
||||
pub mod message;
|
||||
mod settings;
|
||||
mod visitor;
|
||||
|
|
|
@ -29,6 +29,7 @@ pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
|
|||
location: check.location,
|
||||
filename: path.to_string_lossy().to_string(),
|
||||
})
|
||||
.filter(|message| !message.is_inline_ignored())
|
||||
.collect();
|
||||
cache::set(path, &messages, mode);
|
||||
|
||||
|
@ -61,7 +62,7 @@ mod tests {
|
|||
},
|
||||
Message {
|
||||
kind: DuplicateArgumentName,
|
||||
location: Location::new(5, 9),
|
||||
location: Location::new(5, 28),
|
||||
filename: "./resources/test/src/duplicate_argument_name.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
|
@ -110,11 +111,18 @@ mod tests {
|
|||
&Path::new("./resources/test/src/import_star_usage.py"),
|
||||
&cache::Mode::None,
|
||||
)?;
|
||||
let expected = vec![Message {
|
||||
kind: ImportStarUsage,
|
||||
location: Location::new(1, 1),
|
||||
filename: "./resources/test/src/import_star_usage.py".to_string(),
|
||||
}];
|
||||
let expected = vec![
|
||||
Message {
|
||||
kind: ImportStarUsage,
|
||||
location: Location::new(1, 1),
|
||||
filename: "./resources/test/src/import_star_usage.py".to_string(),
|
||||
},
|
||||
Message {
|
||||
kind: ImportStarUsage,
|
||||
location: Location::new(2, 1),
|
||||
filename: "./resources/test/src/import_star_usage.py".to_string(),
|
||||
},
|
||||
];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
for i in 1..actual.len() {
|
||||
assert_eq!(actual[i], expected[i]);
|
||||
|
@ -131,7 +139,7 @@ mod tests {
|
|||
)?;
|
||||
let expected = vec![Message {
|
||||
kind: LineTooLong,
|
||||
location: Location::new(3, 80),
|
||||
location: Location::new(3, 88),
|
||||
filename: "./resources/test/src/line_too_long.py".to_string(),
|
||||
}];
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
use std::fmt;
|
||||
use std::path::Path;
|
||||
|
||||
use colored::Colorize;
|
||||
use regex::Regex;
|
||||
use rustpython_parser::ast::Location;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::checks::CheckKind;
|
||||
use crate::fs;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(remote = "Location")]
|
||||
|
@ -29,6 +32,38 @@ pub struct Message {
|
|||
pub filename: String,
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub fn is_inline_ignored(&self) -> bool {
|
||||
match fs::read_line(Path::new(&self.filename), &self.location.row()) {
|
||||
Ok(line) => {
|
||||
// https://github.com/PyCQA/flake8/blob/799c71eeb61cf26c7c176aed43e22523e2a6d991/src/flake8/defaults.py#L26
|
||||
let re = Regex::new(r"(?i)# noqa(?::\s?(?P<codes>([A-Z]+[0-9]+(?:[,\s]+)?)+))?")
|
||||
.unwrap();
|
||||
match re.captures(&line) {
|
||||
Some(caps) => match caps.name("codes") {
|
||||
Some(codes) => {
|
||||
let re = Regex::new(r"[,\s]").unwrap();
|
||||
for code in re
|
||||
.split(codes.as_str())
|
||||
.map(|code| code.trim())
|
||||
.filter(|code| !code.is_empty())
|
||||
{
|
||||
if code == self.kind.code() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
None => true,
|
||||
},
|
||||
None => false,
|
||||
}
|
||||
}
|
||||
Err(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Message {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
|
|
1
src/settings.rs
Normal file
1
src/settings.rs
Normal file
|
@ -0,0 +1 @@
|
|||
pub static MAX_LINE_LENGTH: &usize = &88;
|
Loading…
Add table
Add a link
Reference in a new issue