Add a check for long lines

This commit is contained in:
Charles Marsh 2022-08-13 17:58:19 -04:00
parent 4a67c8d44b
commit 943a0de62b
11 changed files with 77 additions and 28 deletions

2
Cargo.lock generated
View File

@ -1493,7 +1493,7 @@ dependencies = [
[[package]]
name = "rust-python-linter"
version = "0.0.8"
version = "0.0.9"
dependencies = [
"anyhow",
"bincode",

View File

@ -1,6 +1,6 @@
[package]
name = "rust-python-linter"
version = "0.0.8"
version = "0.0.9"
edition = "2021"
[lib]

View File

@ -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.
"""

View File

@ -85,7 +85,7 @@ pub fn check_ast(python_ast: &Suite) -> Vec<Check> {
mod tests {
use rustpython_parser::ast::{Alias, Location, Stmt, StmtKind};
use crate::checker::Checker;
use crate::check_ast::Checker;
use crate::checks::Check;
use crate::checks::CheckKind::ImportStarUsage;
use crate::visitor::Visitor;

21
src/check_lines.rs Normal file
View File

@ -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()
}

View File

@ -6,6 +6,7 @@ pub enum CheckKind {
DuplicateArgumentName,
ImportStarUsage,
IfTuple,
LineTooLong,
}
impl CheckKind {
@ -15,6 +16,7 @@ impl CheckKind {
CheckKind::DuplicateArgumentName => "F831",
CheckKind::IfTuple => "F634",
CheckKind::ImportStarUsage => "F403",
CheckKind::LineTooLong => "E501",
}
}
@ -24,6 +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)",
}
}
}

View File

@ -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};
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(|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)
}

View File

@ -1,9 +1,9 @@
mod cache;
pub mod checker;
pub mod check_ast;
mod check_lines;
mod checks;
pub mod fs;
pub mod linter;
pub mod logging;
pub mod message;
mod parser;
mod visitor;

View File

@ -2,10 +2,12 @@ use std::path::Path;
use anyhow::Result;
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::{cache, parser};
use crate::{cache, fs};
pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
// Check the cache.
@ -14,10 +16,14 @@ pub fn check_path(path: &Path, mode: &cache::Mode) -> Result<Vec<Message>> {
return Ok(messages);
}
// Read the file from disk.
let contents = fs::read_file(path)?;
// Run the linter.
let python_ast = parser::parse(path)?;
let python_ast = parser::parse_program(&contents)?;
let messages: Vec<Message> = check_ast(&python_ast)
.into_iter()
.chain(check_lines(&contents))
.map(|check| Message {
kind: check.kind,
location: check.location,
@ -37,7 +43,7 @@ mod tests {
use rustpython_parser::ast::Location;
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::message::Message;
@ -116,4 +122,23 @@ mod tests {
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(())
}
}

View File

@ -33,12 +33,13 @@ impl fmt::Display for Message {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}{}{}{}{}\t{}\t{}",
"{}{}{}{}{}{} {} {}",
self.filename.white().bold(),
":".cyan(),
self.location.row(),
":".cyan(),
self.location.column(),
":".cyan(),
self.location.row(),
self.kind.code().red().bold(),
self.kind.body()
)

View File

@ -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())
}