Add support for pycodestyle E101 (#2038)

Rule described here: https://www.flake8rules.com/rules/E101.html

I tried to follow contributing guidelines closely, I've never worked with Rust before. Stumbled across Ruff a few days ago and would like to use it in our project, but we use a bunch of flake8 rules that are not yet implemented in ruff, so I decided to give it a go.
This commit is contained in:
Eric Roberts
2023-01-20 17:24:58 -05:00
committed by GitHub
parent 20a9252e92
commit 3939c2dbf7
9 changed files with 97 additions and 2 deletions

View File

@@ -596,6 +596,7 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/2.9.1/) on PyPI
#### Error (E)
| Code | Name | Message | Fix |
| ---- | ---- | ------- | --- |
| E101 | mixed-spaces-and-tabs | Indentation contains mixed spaces and tabs | |
| E401 | multiple-imports-on-one-line | Multiple imports on one line | |
| E402 | module-import-not-at-top-of-file | Module level import not at top of file | |
| E501 | line-too-long | Line too long ({length} > {limit} characters) | |

View File

@@ -0,0 +1,19 @@
def func_all_spaces():
# No error
print("spaces")
def func_tabs():
# No error
print("tabs")
def func_mixed_start_with_tab():
# E101
print("mixed starts with tab")
def func_mixed_start_with_space():
# E101
print("mixed starts with space")
def xyz():
# E101
print("xyz");

View File

@@ -1311,6 +1311,9 @@
"DTZ011",
"DTZ012",
"E",
"E1",
"E10",
"E101",
"E4",
"E40",
"E401",

View File

@@ -2,7 +2,7 @@
use crate::registry::{Diagnostic, Rule};
use crate::rules::pycodestyle::rules::{
doc_line_too_long, line_too_long, no_newline_at_end_of_file,
doc_line_too_long, line_too_long, mixed_spaces_and_tabs, no_newline_at_end_of_file,
};
use crate::rules::pygrep_hooks::rules::{blanket_noqa, blanket_type_ignore};
use crate::rules::pyupgrade::rules::unnecessary_coding_comment;
@@ -25,6 +25,7 @@ pub fn check_lines(
let enforce_unnecessary_coding_comment = settings
.rules
.enabled(&Rule::PEP3120UnnecessaryCodingComment);
let enforce_mixed_spaces_and_tabs = settings.rules.enabled(&Rule::MixedSpacesAndTabs);
let mut commented_lines_iter = commented_lines.iter().peekable();
let mut doc_lines_iter = doc_lines.iter().peekable();
@@ -72,6 +73,12 @@ pub fn check_lines(
}
}
if enforce_mixed_spaces_and_tabs {
if let Some(diagnostic) = mixed_spaces_and_tabs(index, line) {
diagnostics.push(diagnostic);
}
}
if enforce_line_too_long {
if let Some(diagnostic) = line_too_long(index, line, settings) {
diagnostics.push(diagnostic);

View File

@@ -14,6 +14,7 @@ use crate::{rules, violations};
ruff_macros::define_rule_mapping!(
// pycodestyle errors
E101 => violations::MixedSpacesAndTabs,
E401 => violations::MultipleImportsOnOneLine,
E402 => violations::ModuleImportNotAtTopOfFile,
E501 => violations::LineTooLong,
@@ -556,7 +557,8 @@ impl Rule {
| Rule::DocLineTooLong
| Rule::PEP3120UnnecessaryCodingComment
| Rule::BlanketTypeIgnore
| Rule::BlanketNOQA => &LintSource::Lines,
| Rule::BlanketNOQA
| Rule::MixedSpacesAndTabs => &LintSource::Lines,
Rule::AmbiguousUnicodeCharacterComment
| Rule::AmbiguousUnicodeCharacterDocstring
| Rule::AmbiguousUnicodeCharacterString

View File

@@ -36,6 +36,7 @@ mod tests {
#[test_case(Rule::NoNewLineAtEndOfFile, Path::new("W292_4.py"))]
#[test_case(Rule::InvalidEscapeSequence, Path::new("W605_0.py"))]
#[test_case(Rule::InvalidEscapeSequence, Path::new("W605_1.py"))]
#[test_case(Rule::MixedSpacesAndTabs, Path::new("E101.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.code(), path.to_string_lossy());
let diagnostics = test_path(

View File

@@ -78,6 +78,23 @@ pub fn line_too_long(lineno: usize, line: &str, settings: &Settings) -> Option<D
}
}
/// E101
pub fn mixed_spaces_and_tabs(lineno: usize, line: &str) -> Option<Diagnostic> {
let indent = leading_space(line);
if indent.contains(' ') && indent.contains('\t') {
Some(Diagnostic::new(
violations::MixedSpacesAndTabs,
Range::new(
Location::new(lineno + 1, 0),
Location::new(lineno + 1, indent.chars().count()),
),
))
} else {
None
}
}
/// W505
pub fn doc_line_too_long(lineno: usize, line: &str, settings: &Settings) -> Option<Diagnostic> {
let Some(limit) = settings.pycodestyle.max_doc_length else {

View File

@@ -0,0 +1,35 @@
---
source: src/rules/pycodestyle/mod.rs
expression: diagnostics
---
- kind:
MixedSpacesAndTabs: ~
location:
row: 11
column: 0
end_location:
row: 11
column: 3
fix: ~
parent: ~
- kind:
MixedSpacesAndTabs: ~
location:
row: 15
column: 0
end_location:
row: 15
column: 11
fix: ~
parent: ~
- kind:
MixedSpacesAndTabs: ~
location:
row: 19
column: 0
end_location:
row: 19
column: 4
fix: ~
parent: ~

View File

@@ -48,6 +48,16 @@ impl Violation for LineTooLong {
}
}
define_violation!(
pub struct MixedSpacesAndTabs;
);
impl Violation for MixedSpacesAndTabs {
#[derive_message_formats]
fn message(&self) -> String {
format!("Indentation contains mixed spaces and tabs")
}
}
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum EqCmpop {
Eq,