mirror of https://github.com/astral-sh/ruff
Add a check for long lines
This commit is contained in:
parent
4a67c8d44b
commit
943a0de62b
|
|
@ -1493,7 +1493,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rust-python-linter"
|
name = "rust-python-linter"
|
||||||
version = "0.0.8"
|
version = "0.0.9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bincode",
|
"bincode",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rust-python-linter"
|
name = "rust-python-linter"
|
||||||
version = "0.0.8"
|
version = "0.0.9"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
"""Lorem ipsum dolor sit amet.
|
||||||
|
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
|
||||||
|
"""
|
||||||
|
|
@ -85,7 +85,7 @@ pub fn check_ast(python_ast: &Suite) -> Vec<Check> {
|
||||||
mod tests {
|
mod tests {
|
||||||
use rustpython_parser::ast::{Alias, Location, Stmt, StmtKind};
|
use rustpython_parser::ast::{Alias, Location, Stmt, StmtKind};
|
||||||
|
|
||||||
use crate::checker::Checker;
|
use crate::check_ast::Checker;
|
||||||
use crate::checks::Check;
|
use crate::checks::Check;
|
||||||
use crate::checks::CheckKind::ImportStarUsage;
|
use crate::checks::CheckKind::ImportStarUsage;
|
||||||
use crate::visitor::Visitor;
|
use crate::visitor::Visitor;
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
use rustpython_parser::ast::Location;
|
||||||
|
|
||||||
|
use crate::checks::Check;
|
||||||
|
use crate::checks::CheckKind::LineTooLong;
|
||||||
|
|
||||||
|
pub fn check_lines(contents: &str) -> Vec<Check> {
|
||||||
|
contents
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(row, line)| {
|
||||||
|
if line.len() > 79 {
|
||||||
|
Some(Check {
|
||||||
|
kind: LineTooLong,
|
||||||
|
location: Location::new(row + 1, 79 + 1),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ pub enum CheckKind {
|
||||||
DuplicateArgumentName,
|
DuplicateArgumentName,
|
||||||
ImportStarUsage,
|
ImportStarUsage,
|
||||||
IfTuple,
|
IfTuple,
|
||||||
|
LineTooLong,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CheckKind {
|
impl CheckKind {
|
||||||
|
|
@ -15,6 +16,7 @@ impl CheckKind {
|
||||||
CheckKind::DuplicateArgumentName => "F831",
|
CheckKind::DuplicateArgumentName => "F831",
|
||||||
CheckKind::IfTuple => "F634",
|
CheckKind::IfTuple => "F634",
|
||||||
CheckKind::ImportStarUsage => "F403",
|
CheckKind::ImportStarUsage => "F403",
|
||||||
|
CheckKind::LineTooLong => "E501",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -24,6 +26,7 @@ impl CheckKind {
|
||||||
CheckKind::DuplicateArgumentName => "Duplicate argument name in function definition",
|
CheckKind::DuplicateArgumentName => "Duplicate argument name in function definition",
|
||||||
CheckKind::IfTuple => "If test is a tuple, which is always `True`",
|
CheckKind::IfTuple => "If test is a tuple, which is always `True`",
|
||||||
CheckKind::ImportStarUsage => "Unable to detect undefined names",
|
CheckKind::ImportStarUsage => "Unable to detect undefined names",
|
||||||
|
CheckKind::LineTooLong => "Line too long (> 79 characters)",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/fs.rs
14
src/fs.rs
|
|
@ -1,5 +1,7 @@
|
||||||
use std::path::PathBuf;
|
use anyhow::Result;
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufReader, Read};
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use walkdir::{DirEntry, WalkDir};
|
use walkdir::{DirEntry, WalkDir};
|
||||||
|
|
||||||
fn is_not_hidden(entry: &DirEntry) -> bool {
|
fn is_not_hidden(entry: &DirEntry) -> bool {
|
||||||
|
|
@ -18,3 +20,11 @@ pub fn iter_python_files(path: &PathBuf) -> impl Iterator<Item = DirEntry> {
|
||||||
.filter_map(|entry| entry.ok())
|
.filter_map(|entry| entry.ok())
|
||||||
.filter(|entry| entry.path().to_string_lossy().ends_with(".py"))
|
.filter(|entry| entry.path().to_string_lossy().ends_with(".py"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn read_file(path: &Path) -> Result<String> {
|
||||||
|
let file = File::open(path)?;
|
||||||
|
let mut buf_reader = BufReader::new(file);
|
||||||
|
let mut contents = String::new();
|
||||||
|
buf_reader.read_to_string(&mut contents)?;
|
||||||
|
Ok(contents)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
mod cache;
|
mod cache;
|
||||||
pub mod checker;
|
pub mod check_ast;
|
||||||
|
mod check_lines;
|
||||||
mod checks;
|
mod checks;
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
pub mod linter;
|
pub mod linter;
|
||||||
pub mod logging;
|
pub mod logging;
|
||||||
pub mod message;
|
pub mod message;
|
||||||
mod parser;
|
|
||||||
mod visitor;
|
mod visitor;
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,12 @@ use std::path::Path;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
|
use rustpython_parser::parser;
|
||||||
|
|
||||||
use crate::checker::check_ast;
|
use crate::check_ast::check_ast;
|
||||||
|
use crate::check_lines::check_lines;
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
use crate::{cache, parser};
|
use crate::{cache, fs};
|
||||||
|
|
||||||
pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
|
pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
|
||||||
// Check the cache.
|
// Check the cache.
|
||||||
|
|
@ -14,10 +16,14 @@ pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
|
||||||
return Ok(messages);
|
return Ok(messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Read the file from disk.
|
||||||
|
let contents = fs::read_file(path)?;
|
||||||
|
|
||||||
// Run the linter.
|
// Run the linter.
|
||||||
let python_ast = parser::parse(path)?;
|
let python_ast = parser::parse_program(&contents)?;
|
||||||
let messages: Vec<Message> = check_ast(&python_ast)
|
let messages: Vec<Message> = check_ast(&python_ast)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.chain(check_lines(&contents))
|
||||||
.map(|check| Message {
|
.map(|check| Message {
|
||||||
kind: check.kind,
|
kind: check.kind,
|
||||||
location: check.location,
|
location: check.location,
|
||||||
|
|
@ -37,7 +43,7 @@ mod tests {
|
||||||
use rustpython_parser::ast::Location;
|
use rustpython_parser::ast::Location;
|
||||||
|
|
||||||
use crate::cache;
|
use crate::cache;
|
||||||
use crate::checks::CheckKind::{DuplicateArgumentName, IfTuple, ImportStarUsage};
|
use crate::checks::CheckKind::{DuplicateArgumentName, IfTuple, ImportStarUsage, LineTooLong};
|
||||||
use crate::linter::check_path;
|
use crate::linter::check_path;
|
||||||
use crate::message::Message;
|
use crate::message::Message;
|
||||||
|
|
||||||
|
|
@ -116,4 +122,23 @@ mod tests {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn line_too_long() -> Result<()> {
|
||||||
|
let actual = check_path(
|
||||||
|
&Path::new("./resources/test/src/line_too_long.py"),
|
||||||
|
&cache::Mode::None,
|
||||||
|
)?;
|
||||||
|
let expected = vec![Message {
|
||||||
|
kind: LineTooLong,
|
||||||
|
location: Location::new(3, 80),
|
||||||
|
filename: "./resources/test/src/line_too_long.py".to_string(),
|
||||||
|
}];
|
||||||
|
assert_eq!(actual.len(), expected.len());
|
||||||
|
for i in 1..actual.len() {
|
||||||
|
assert_eq!(actual[i], expected[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,13 @@ 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!(
|
||||||
f,
|
f,
|
||||||
"{}{}{}{}{}\t{}\t{}",
|
"{}{}{}{}{}{} {} {}",
|
||||||
self.filename.white().bold(),
|
self.filename.white().bold(),
|
||||||
":".cyan(),
|
":".cyan(),
|
||||||
|
self.location.row(),
|
||||||
|
":".cyan(),
|
||||||
self.location.column(),
|
self.location.column(),
|
||||||
":".cyan(),
|
":".cyan(),
|
||||||
self.location.row(),
|
|
||||||
self.kind.code().red().bold(),
|
self.kind.code().red().bold(),
|
||||||
self.kind.body()
|
self.kind.body()
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
use std::fs::File;
|
|
||||||
use std::io::{BufReader, Read};
|
|
||||||
use std::path::Path;
|
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
use rustpython_parser::ast::Suite;
|
|
||||||
use rustpython_parser::parser;
|
|
||||||
|
|
||||||
pub fn parse(path: &Path) -> Result<Suite> {
|
|
||||||
let file = File::open(path)?;
|
|
||||||
let mut buf_reader = BufReader::new(file);
|
|
||||||
let mut contents = String::new();
|
|
||||||
buf_reader.read_to_string(&mut contents)?;
|
|
||||||
parser::parse_program(&contents).map_err(|e| e.into())
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue