mirror of https://github.com/astral-sh/ruff
Avoid re-reading + iterating over lines for ignores (#48)
This commit is contained in:
parent
ae27793b86
commit
7ed5b3d3a2
|
|
@ -188,25 +188,6 @@ version = "1.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autoincrement"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "dc81b6ad0c9122715c741113fb97ba283f723b1dd86e186dd7df00a2b6877bfe"
|
|
||||||
dependencies = [
|
|
||||||
"autoincrement_derive",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autoincrement_derive"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "1259ce9b9a586a3f5ada3d236800ad0aa446b0d4c3dbac4158084a1dd704a228"
|
|
||||||
dependencies = [
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.10.1"
|
version = "0.10.1"
|
||||||
|
|
@ -1657,7 +1638,6 @@ name = "ruff"
|
||||||
version = "0.0.19"
|
version = "0.0.19"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"autoincrement",
|
|
||||||
"bincode",
|
"bincode",
|
||||||
"cacache",
|
"cacache",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ name = "ruff"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { version = "1.0.60" }
|
anyhow = { version = "1.0.60" }
|
||||||
autoincrement = "1.0.1"
|
|
||||||
bincode = { version = "1.3.3" }
|
bincode = { version = "1.3.3" }
|
||||||
cacache = { version = "10.0.1" }
|
cacache = { version = "10.0.1" }
|
||||||
chrono = { version = "0.4.21" }
|
chrono = { version = "0.4.21" }
|
||||||
|
|
|
||||||
|
|
@ -3,24 +3,36 @@ use rustpython_parser::ast::Location;
|
||||||
use crate::checks::{Check, CheckKind};
|
use crate::checks::{Check, CheckKind};
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
|
|
||||||
pub fn check_lines(contents: &str, settings: &Settings) -> Vec<Check> {
|
pub fn check_lines(checks: &mut Vec<Check>, contents: &str, settings: &Settings) {
|
||||||
contents
|
let enforce_line_too_ling = settings.select.contains(CheckKind::LineTooLong.code());
|
||||||
.lines()
|
|
||||||
.enumerate()
|
let mut line_checks = vec![];
|
||||||
.filter_map(|(row, line)| {
|
let mut ignored = vec![];
|
||||||
if settings.select.contains(CheckKind::LineTooLong.code())
|
for (row, line) in contents.lines().enumerate() {
|
||||||
&& line.len() > settings.line_length
|
// Remove any ignored checks.
|
||||||
{
|
// TODO(charlie): Only validate checks for the current line.
|
||||||
let chunks: Vec<&str> = line.split_whitespace().collect();
|
for (index, check) in checks.iter().enumerate() {
|
||||||
if !(chunks.len() == 1 || (chunks.len() == 2 && chunks[0] == "#")) {
|
if check.location.row() == row + 1 && check.is_inline_ignored(line) {
|
||||||
return Some(Check {
|
ignored.push(index);
|
||||||
kind: CheckKind::LineTooLong,
|
}
|
||||||
location: Location::new(row + 1, settings.line_length + 1),
|
}
|
||||||
});
|
|
||||||
|
// Enforce line length.
|
||||||
|
if enforce_line_too_ling && line.len() > settings.line_length {
|
||||||
|
let chunks: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if !(chunks.len() == 1 || (chunks.len() == 2 && chunks[0] == "#")) {
|
||||||
|
let check = Check {
|
||||||
|
kind: CheckKind::LineTooLong,
|
||||||
|
location: Location::new(row + 1, settings.line_length + 1),
|
||||||
|
};
|
||||||
|
if !check.is_inline_ignored(line) {
|
||||||
|
line_checks.push(check);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
None
|
}
|
||||||
})
|
for index in ignored.iter().rev() {
|
||||||
.collect()
|
checks.remove(*index);
|
||||||
|
}
|
||||||
|
checks.extend(line_checks);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use regex::Regex;
|
||||||
use rustpython_parser::ast::Location;
|
use rustpython_parser::ast::Location;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
|
@ -135,3 +136,28 @@ pub struct Check {
|
||||||
pub kind: CheckKind,
|
pub kind: CheckKind,
|
||||||
pub location: Location,
|
pub location: Location,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Check {
|
||||||
|
pub fn is_inline_ignored(&self, line: &str) -> bool {
|
||||||
|
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().as_str() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
None => true,
|
||||||
|
},
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
12
src/fs.rs
12
src/fs.rs
|
|
@ -1,5 +1,5 @@
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader, Read};
|
use std::io::{BufReader, Read};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
@ -22,16 +22,6 @@ pub fn iter_python_files(path: &PathBuf) -> impl Iterator<Item = DirEntry> {
|
||||||
.filter(|entry| entry.path().to_string_lossy().ends_with(".py"))
|
.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> {
|
pub fn read_file(path: &Path) -> Result<String> {
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
let mut buf_reader = BufReader::new(file);
|
let mut buf_reader = BufReader::new(file);
|
||||||
|
|
|
||||||
|
|
@ -36,13 +36,7 @@ pub fn check_path(path: &Path, settings: &Settings, mode: &cache::Mode) -> Resul
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the lines-based checks.
|
// Run the lines-based checks.
|
||||||
if settings
|
check_lines(&mut checks, &contents, settings);
|
||||||
.select
|
|
||||||
.iter()
|
|
||||||
.any(|check_code| matches!(check_code.lint_source(), LintSource::Lines))
|
|
||||||
{
|
|
||||||
checks.extend(check_lines(&contents, settings));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to messages.
|
// Convert to messages.
|
||||||
let messages: Vec<Message> = checks
|
let messages: Vec<Message> = checks
|
||||||
|
|
@ -52,7 +46,6 @@ pub fn check_path(path: &Path, settings: &Settings, mode: &cache::Mode) -> Resul
|
||||||
location: check.location,
|
location: check.location,
|
||||||
filename: path.to_string_lossy().to_string(),
|
filename: path.to_string_lossy().to_string(),
|
||||||
})
|
})
|
||||||
.filter(|message| !message.is_inline_ignored())
|
|
||||||
.collect();
|
.collect();
|
||||||
cache::set(path, settings, &messages, mode);
|
cache::set(path, settings, &messages, mode);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use regex::Regex;
|
|
||||||
use rustpython_parser::ast::Location;
|
use rustpython_parser::ast::Location;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::checks::CheckKind;
|
use crate::checks::CheckKind;
|
||||||
use crate::fs;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(remote = "Location")]
|
#[serde(remote = "Location")]
|
||||||
|
|
@ -32,38 +29,6 @@ pub struct Message {
|
||||||
pub filename: String,
|
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().as_str() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
None => true,
|
|
||||||
},
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for Message {
|
impl fmt::Display for Message {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue