From 916fe4c892f5efa38169d037ca49c2895e56dd6a Mon Sep 17 00:00:00 2001 From: Charlie Marsh Date: Tue, 31 Jan 2023 18:16:37 -0500 Subject: [PATCH] Implement pycodestyle's logical line detection --- Cargo.lock | 7 + Cargo.toml | 1 + README.md | 4 + resources/test/fixtures/pycodestyle/E22.py | 171 ++++++++++++ ruff.schema.json | 6 + src/checkers/logical_lines.rs | 248 ++++++++++++++++++ src/checkers/mod.rs | 3 +- src/checkers/{lines.rs => physical_lines.rs} | 8 +- src/linter.rs | 16 +- src/registry.rs | 13 +- src/rules/pycodestyle/mod.rs | 4 + src/rules/pycodestyle/rules/mod.rs | 5 + .../rules/space_around_operator.rs | 72 +++++ ...ules__pycodestyle__tests__E221_E22.py.snap | 85 ++++++ ...ules__pycodestyle__tests__E222_E22.py.snap | 55 ++++ ...ules__pycodestyle__tests__E223_E22.py.snap | 15 ++ ...ules__pycodestyle__tests__E224_E22.py.snap | 15 ++ 17 files changed, 718 insertions(+), 10 deletions(-) create mode 100644 resources/test/fixtures/pycodestyle/E22.py create mode 100644 src/checkers/logical_lines.rs rename src/checkers/{lines.rs => physical_lines.rs} (97%) create mode 100644 src/rules/pycodestyle/rules/space_around_operator.rs create mode 100644 src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E221_E22.py.snap create mode 100644 src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E222_E22.py.snap create mode 100644 src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E223_E22.py.snap create mode 100644 src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E224_E22.py.snap diff --git a/Cargo.lock b/Cargo.lock index ff277f6b5cb960..b90bca2ac9182b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -126,6 +126,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bisection" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "021e079a1bab0ecce6cf4b4b74c0c37afa4a697136eb3b127875c84a8f04a8c3" + [[package]] name = "bit-set" version = "0.5.3" @@ -1925,6 +1931,7 @@ name = "ruff" version = "0.0.239" dependencies = [ "anyhow", + "bisection", "bitflags", "cfg-if", "chrono", diff --git a/Cargo.toml b/Cargo.toml index b2afea8f85fecd..8714c7cb23a623 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ doctest = false [dependencies] anyhow = { version = "1.0.66" } +bisection = { version = "0.1.0" } bitflags = { version = "1.3.2" } cfg-if = { version = "1.0.0" } chrono = { version = "0.4.21", default-features = false, features = ["clock"] } diff --git a/README.md b/README.md index 837bf34cecb9ad..2e433769e4dc40 100644 --- a/README.md +++ b/README.md @@ -695,6 +695,10 @@ For more, see [pycodestyle](https://pypi.org/project/pycodestyle/) on PyPI. | Code | Name | Message | Fix | | ---- | ---- | ------- | --- | | E101 | mixed-spaces-and-tabs | Indentation contains mixed spaces and tabs | | +| E221 | multiple-spaces-before-operator | Multiple spaces before operator | | +| E222 | multiple-spaces-after-operator | Multiple spaces after operator | | +| E223 | tab-before-operator | Tab before operator | | +| E224 | tab-after-operator | Tab after operator | | | 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) | | diff --git a/resources/test/fixtures/pycodestyle/E22.py b/resources/test/fixtures/pycodestyle/E22.py new file mode 100644 index 00000000000000..7ea27927e50fe9 --- /dev/null +++ b/resources/test/fixtures/pycodestyle/E22.py @@ -0,0 +1,171 @@ +#: E221 +a = 12 + 3 +b = 4 + 5 +#: E221 E221 +x = 1 +y = 2 +long_variable = 3 +#: E221 E221 +x[0] = 1 +x[1] = 2 +long_variable = 3 +#: E221 E221 +x = f(x) + 1 +y = long_variable + 2 +z = x[0] + 3 +#: E221:3:14 +text = """ + bar + foo %s""" % rofl +#: Okay +x = 1 +y = 2 +long_variable = 3 +#: + + +#: E222 +a = a + 1 +b = b + 10 +#: E222 E222 +x = -1 +y = -2 +long_variable = 3 +#: E222 E222 +x[0] = 1 +x[1] = 2 +long_variable = 3 +#: + + +#: E223 +foobart = 4 +a = 3 # aligned with tab +#: + + +#: E224 +a += 1 +b += 1000 +#: + + +#: E225 +submitted +=1 +#: E225 +submitted+= 1 +#: E225 +c =-1 +#: E225 +x = x /2 - 1 +#: E225 +c = alpha -4 +#: E225 +c = alpha- 4 +#: E225 +z = x **y +#: E225 +z = (x + 1) **y +#: E225 +z = (x + 1)** y +#: E225 +_1kB = _1MB >>10 +#: E225 +_1kB = _1MB>> 10 +#: E225 E225 +i=i+ 1 +#: E225 E225 +i=i +1 +#: E225 +i = 1and 1 +#: E225 +i = 1or 0 +#: E225 +1is 1 +#: E225 +1in [] +#: E225 +i = 1 @2 +#: E225 +i = 1@ 2 +#: E225 E226 +i=i+1 +#: E225 E226 +i =i+1 +#: E225 E226 +i= i+1 +#: E225 E226 +c = (a +b)*(a - b) +#: E225 E226 +c = (a+ b)*(a - b) +#: + +#: E226 +z = 2//30 +#: E226 E226 +c = (a+b) * (a-b) +#: E226 +norman = True+False +#: E226 +x = x*2 - 1 +#: E226 +x = x/2 - 1 +#: E226 E226 +hypot2 = x*x + y*y +#: E226 +c = (a + b)*(a - b) +#: E226 +def halves(n): + return (i//2 for i in range(n)) +#: E227 +_1kB = _1MB>>10 +#: E227 +_1MB = _1kB<<10 +#: E227 +a = b|c +#: E227 +b = c&a +#: E227 +c = b^a +#: E228 +a = b%c +#: E228 +msg = fmt%(errno, errmsg) +#: E228 +msg = "Error %d occurred"%errno +#: + +#: Okay +i = i + 1 +submitted += 1 +x = x * 2 - 1 +hypot2 = x * x + y * y +c = (a + b) * (a - b) +_1MiB = 2 ** 20 +_1TiB = 2**30 +foo(bar, key='word', *args, **kwargs) +baz(**kwargs) +negative = -1 +spam(-1) +-negative +func1(lambda *args, **kw: (args, kw)) +func2(lambda a, b=h[:], c=0: (a, b, c)) +if not -5 < x < +5: + print >>sys.stderr, "x is out of range." +print >> sys.stdout, "x is an integer." +x = x / 2 - 1 +x = 1 @ 2 + +if alpha[:-i]: + *a, b = (1, 2, 3) + + +def squares(n): + return (i**2 for i in range(n)) + + +ENG_PREFIXES = { + -6: "\u03bc", # Greek letter mu + -3: "m", +} +#: diff --git a/ruff.schema.json b/ruff.schema.json index f8e532a1b99426..4610f89b2e9b22 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1401,6 +1401,12 @@ "E1", "E10", "E101", + "E2", + "E22", + "E221", + "E222", + "E223", + "E224", "E4", "E40", "E401", diff --git a/src/checkers/logical_lines.rs b/src/checkers/logical_lines.rs new file mode 100644 index 00000000000000..262a8e310c026a --- /dev/null +++ b/src/checkers/logical_lines.rs @@ -0,0 +1,248 @@ +use bisection::bisect_left; +use itertools::Itertools; +use rustpython_ast::Location; +use rustpython_parser::lexer::{LexResult, Tok}; + +use crate::ast::types::Range; +use crate::registry::Diagnostic; +use crate::rules::pycodestyle::rules::space_around_operator; +use crate::settings::Settings; +use crate::source_code::Locator; + +#[derive(Debug)] +struct LogicalLine { + text: String, + mapping: Vec<(usize, Location)>, + /// Whether the logical line contains an operator. + operator: bool, +} + +fn build_line(tokens: &[(Location, &Tok, Location)], locator: &Locator) -> LogicalLine { + let mut logical = String::with_capacity(88); + let mut operator = false; + let mut mapping = Vec::new(); + let mut prev: Option<&Location> = None; + let mut length = 0; + for (start, tok, end) in tokens { + if matches!( + tok, + Tok::Newline | Tok::NonLogicalNewline | Tok::Indent | Tok::Dedent | Tok::Comment { .. } + ) { + continue; + } + if mapping.is_empty() { + mapping.push((0, *start)); + } + + if !operator { + operator |= matches!( + tok, + Tok::Amper + | Tok::AmperEqual + | Tok::CircumFlex + | Tok::CircumflexEqual + | Tok::Colon + | Tok::ColonEqual + | Tok::DoubleSlash + | Tok::DoubleSlashEqual + | Tok::DoubleStar + | Tok::Equal + | Tok::Greater + | Tok::GreaterEqual + | Tok::Less + | Tok::LessEqual + | Tok::Minus + | Tok::MinusEqual + | Tok::NotEqual + | Tok::Percent + | Tok::PercentEqual + | Tok::Plus + | Tok::PlusEqual + | Tok::Slash + | Tok::SlashEqual + | Tok::Star + | Tok::StarEqual + | Tok::Vbar + | Tok::VbarEqual + ); + } + + // TODO(charlie): "Mute" strings. + let text = if let Tok::String { .. } = tok { + "\"\"" + } else { + locator.slice_source_code_range(&Range { + location: *start, + end_location: *end, + }) + }; + + if let Some(prev) = prev { + if prev.row() != start.row() { + let prev_text = locator.slice_source_code_range(&Range { + location: *prev, + end_location: Location::new(prev.row() + 1, 0), + }); + if prev_text == "," + || ((prev_text != "{" && prev_text != "[" && prev_text != "(") + && (text != "}" || text != "]" || text != ")")) + { + logical.push(' '); + length += 1; + } + } else if prev.column() != start.column() { + let prev_text = locator.slice_source_code_range(&Range { + location: *prev, + end_location: *start, + }); + logical.push_str(prev_text); + length += prev_text.len(); + } + } + logical.push_str(text); + length += text.len(); + mapping.push((length, *end)); + prev = Some(end); + } + + LogicalLine { + text: logical, + operator, + mapping, + } +} + +fn iter_logical_lines(tokens: &[LexResult], locator: &Locator) -> Vec { + let mut parens = 0; + let mut accumulator = Vec::with_capacity(32); + let mut lines = Vec::with_capacity(128); + for &(start, ref tok, end) in tokens.iter().flatten() { + accumulator.push((start, tok, end)); + if matches!(tok, Tok::Lbrace | Tok::Lpar | Tok::Lsqb) { + parens += 1; + } else if matches!(tok, Tok::Rbrace | Tok::Rpar | Tok::Rsqb) { + parens -= 1; + } else if parens == 0 { + if matches!(tok, Tok::Newline) { + lines.push(build_line(&accumulator, locator)); + accumulator.drain(..); + } + } + } + lines +} + +pub fn check_logical_lines( + tokens: &[LexResult], + locator: &Locator, + settings: &Settings, +) -> Vec { + let mut diagnostics = vec![]; + for line in iter_logical_lines(tokens, locator) { + if line.operator { + let mapping_offsets = line.mapping.iter().map(|(offset, _)| *offset).collect_vec(); + for (index, kind) in space_around_operator(&line.text) { + let (token_offset, pos) = line.mapping[bisect_left(&mapping_offsets, &index)]; + let location = Location::new(pos.row(), pos.column() + index - token_offset); + if settings.rules.enabled(kind.rule()) { + diagnostics.push(Diagnostic { + kind, + location, + end_location: location, + fix: None, + parent: None, + }); + } + } + } + } + diagnostics +} + +#[cfg(test)] +mod tests { + use rustpython_parser::lexer; + use rustpython_parser::lexer::LexResult; + + use crate::checkers::logical_lines::iter_logical_lines; + use crate::source_code::Locator; + + #[test] + fn split_logical_lines() { + let contents = r#" +x = 1 +y = 2 +z = x + 1"#; + let lxr: Vec = lexer::make_tokenizer(contents).collect(); + let locator = Locator::new(contents); + let actual: Vec = iter_logical_lines(&lxr, &locator) + .into_iter() + .map(|line| line.text) + .collect(); + let expected = vec![ + "x = 1".to_string(), + "y = 2".to_string(), + "z = x + 1".to_string(), + ]; + assert_eq!(actual, expected); + + let contents = r#" +x = [ + 1, + 2, + 3, +] +y = 2 +z = x + 1"#; + let lxr: Vec = lexer::make_tokenizer(contents).collect(); + let locator = Locator::new(contents); + let actual: Vec = iter_logical_lines(&lxr, &locator) + .into_iter() + .map(|line| line.text) + .collect(); + let expected = vec![ + "x = [ 1, 2, 3, ]".to_string(), + "y = 2".to_string(), + "z = x + 1".to_string(), + ]; + assert_eq!(actual, expected); + + let contents = "x = 'abc'"; + let lxr: Vec = lexer::make_tokenizer(contents).collect(); + let locator = Locator::new(contents); + let actual: Vec = iter_logical_lines(&lxr, &locator) + .into_iter() + .map(|line| line.text) + .collect(); + let expected = vec!["x = \"\"".to_string()]; + assert_eq!(actual, expected); + + let contents = r#" +def f(): + x = 1 +f()"#; + let lxr: Vec = lexer::make_tokenizer(contents).collect(); + let locator = Locator::new(contents); + let actual: Vec = iter_logical_lines(&lxr, &locator) + .into_iter() + .map(|line| line.text) + .collect(); + let expected = vec!["def f():", "x = 1", "f()"]; + assert_eq!(actual, expected); + + let contents = r#" +def f(): + """Docstring goes here.""" + # Comment goes here. + x = 1 +f()"#; + let lxr: Vec = lexer::make_tokenizer(contents).collect(); + let locator = Locator::new(contents); + let actual: Vec = iter_logical_lines(&lxr, &locator) + .into_iter() + .map(|line| line.text) + .collect(); + let expected = vec!["def f():", "\"\"", "x = 1", "f()"]; + assert_eq!(actual, expected); + } +} diff --git a/src/checkers/mod.rs b/src/checkers/mod.rs index cec54e376bdffa..0befee33cef527 100644 --- a/src/checkers/mod.rs +++ b/src/checkers/mod.rs @@ -1,6 +1,7 @@ pub mod ast; pub mod filesystem; pub mod imports; -pub mod lines; +pub mod logical_lines; pub mod noqa; +pub mod physical_lines; pub mod tokens; diff --git a/src/checkers/lines.rs b/src/checkers/physical_lines.rs similarity index 97% rename from src/checkers/lines.rs rename to src/checkers/physical_lines.rs index 72a1eef03e7b0f..4c16d3b02a05f9 100644 --- a/src/checkers/lines.rs +++ b/src/checkers/physical_lines.rs @@ -1,4 +1,4 @@ -//! Lint rules based on checking raw physical lines. +//! Lint rules based on checking physical lines. use std::path::Path; @@ -15,7 +15,7 @@ use crate::rules::pyupgrade::rules::unnecessary_coding_comment; use crate::settings::{flags, Settings}; use crate::source_code::Stylist; -pub fn check_lines( +pub fn check_physical_lines( path: &Path, stylist: &Stylist, contents: &str, @@ -164,7 +164,7 @@ mod tests { use std::path::Path; - use super::check_lines; + use super::check_physical_lines; use crate::registry::Rule; use crate::settings::{flags, Settings}; use crate::source_code::{Locator, Stylist}; @@ -176,7 +176,7 @@ mod tests { let stylist = Stylist::from_contents(line, &locator); let check_with_max_line_length = |line_length: usize| { - check_lines( + check_physical_lines( Path::new("foo.py"), &stylist, line, diff --git a/src/linter.rs b/src/linter.rs index fff8aebfb27918..603f55ba1681c9 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -9,8 +9,9 @@ use crate::autofix::fix_file; use crate::checkers::ast::check_ast; use crate::checkers::filesystem::check_file_path; use crate::checkers::imports::check_imports; -use crate::checkers::lines::check_lines; +use crate::checkers::logical_lines::check_logical_lines; use crate::checkers::noqa::check_noqa; +use crate::checkers::physical_lines::check_physical_lines; use crate::checkers::tokens::check_tokens; use crate::directives::Directives; use crate::doc_lines::{doc_lines_from_ast, doc_lines_from_tokens}; @@ -71,6 +72,15 @@ pub fn check_path( diagnostics.extend(check_file_path(path, package, settings)); } + // Run the logical line-based rules. + if settings + .rules + .iter_enabled() + .any(|rule_code| matches!(rule_code.lint_source(), LintSource::LogicalLines)) + { + diagnostics.extend(check_logical_lines(&tokens, locator, settings)); + } + // Run the AST-based rules. let use_ast = settings .rules @@ -138,9 +148,9 @@ pub fn check_path( if settings .rules .iter_enabled() - .any(|rule_code| matches!(rule_code.lint_source(), LintSource::Lines)) + .any(|rule_code| matches!(rule_code.lint_source(), LintSource::PhysicalLines)) { - diagnostics.extend(check_lines( + diagnostics.extend(check_physical_lines( path, stylist, contents, diff --git a/src/registry.rs b/src/registry.rs index 3f656eec1283c9..5819876ed872d6 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -13,6 +13,10 @@ use crate::{rules, violations}; ruff_macros::define_rule_mapping!( // pycodestyle errors E101 => rules::pycodestyle::rules::MixedSpacesAndTabs, + E221 => rules::pycodestyle::rules::MultipleSpacesBeforeOperator, + E222 => rules::pycodestyle::rules::MultipleSpacesAfterOperator, + E223 => rules::pycodestyle::rules::TabBeforeOperator, + E224 => rules::pycodestyle::rules::TabAfterOperator, E401 => violations::MultipleImportsOnOneLine, E402 => violations::ModuleImportNotAtTopOfFile, E501 => rules::pycodestyle::rules::LineTooLong, @@ -661,7 +665,8 @@ impl Linter { pub enum LintSource { Ast, Io, - Lines, + PhysicalLines, + LogicalLines, Tokens, Imports, NoQa, @@ -674,6 +679,10 @@ impl Rule { pub fn lint_source(&self) -> &'static LintSource { match self { Rule::UnusedNOQA => &LintSource::NoQa, + Rule::TabBeforeOperator + | Rule::MultipleSpacesBeforeOperator + | Rule::MultipleSpacesAfterOperator + | Rule::TabAfterOperator => &LintSource::LogicalLines, Rule::BlanketNOQA | Rule::BlanketTypeIgnore | Rule::DocLineTooLong @@ -685,7 +694,7 @@ impl Rule { | Rule::ShebangNotExecutable | Rule::ShebangNewline | Rule::ShebangPython - | Rule::ShebangWhitespace => &LintSource::Lines, + | Rule::ShebangWhitespace => &LintSource::PhysicalLines, Rule::AmbiguousUnicodeCharacterComment | Rule::AmbiguousUnicodeCharacterDocstring | Rule::AmbiguousUnicodeCharacterString diff --git a/src/rules/pycodestyle/mod.rs b/src/rules/pycodestyle/mod.rs index 0f85e619967ddb..4d398d17c507ea 100644 --- a/src/rules/pycodestyle/mod.rs +++ b/src/rules/pycodestyle/mod.rs @@ -16,6 +16,10 @@ mod tests { use crate::registry::Rule; use crate::{assert_yaml_snapshot, settings}; + #[test_case(Rule::TabBeforeOperator, Path::new("E22.py"))] + #[test_case(Rule::MultipleSpacesBeforeOperator, Path::new("E22.py"))] + #[test_case(Rule::TabAfterOperator, Path::new("E22.py"))] + #[test_case(Rule::MultipleSpacesAfterOperator, Path::new("E22.py"))] #[test_case(Rule::MultipleImportsOnOneLine, Path::new("E40.py"))] #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E40.py"))] #[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402.py"))] diff --git a/src/rules/pycodestyle/rules/mod.rs b/src/rules/pycodestyle/rules/mod.rs index 7cda636d1a14cb..44315e9d71a2ab 100644 --- a/src/rules/pycodestyle/rules/mod.rs +++ b/src/rules/pycodestyle/rules/mod.rs @@ -10,6 +10,10 @@ pub use literal_comparisons::{literal_comparisons, NoneComparison, TrueFalseComp pub use mixed_spaces_and_tabs::{mixed_spaces_and_tabs, MixedSpacesAndTabs}; pub use no_newline_at_end_of_file::{no_newline_at_end_of_file, NoNewLineAtEndOfFile}; pub use not_tests::{not_tests, NotInTest, NotIsTest}; +pub use space_around_operator::{ + space_around_operator, MultipleSpacesAfterOperator, MultipleSpacesBeforeOperator, + TabAfterOperator, TabBeforeOperator, +}; pub use type_comparison::{type_comparison, TypeComparison}; mod ambiguous_class_name; @@ -24,4 +28,5 @@ mod literal_comparisons; mod mixed_spaces_and_tabs; mod no_newline_at_end_of_file; mod not_tests; +mod space_around_operator; mod type_comparison; diff --git a/src/rules/pycodestyle/rules/space_around_operator.rs b/src/rules/pycodestyle/rules/space_around_operator.rs new file mode 100644 index 00000000000000..eac66b581166ac --- /dev/null +++ b/src/rules/pycodestyle/rules/space_around_operator.rs @@ -0,0 +1,72 @@ +use once_cell::sync::Lazy; +use regex::Regex; + +use ruff_macros::derive_message_formats; + +use crate::define_violation; +use crate::registry::DiagnosticKind; +use crate::violation::Violation; + +define_violation!( + pub struct TabBeforeOperator; +); +impl Violation for TabBeforeOperator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Tab before operator") + } +} + +define_violation!( + pub struct MultipleSpacesBeforeOperator; +); +impl Violation for MultipleSpacesBeforeOperator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Multiple spaces before operator") + } +} + +define_violation!( + pub struct TabAfterOperator; +); +impl Violation for TabAfterOperator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Tab after operator") + } +} + +define_violation!( + pub struct MultipleSpacesAfterOperator; +); +impl Violation for MultipleSpacesAfterOperator { + #[derive_message_formats] + fn message(&self) -> String { + format!("Multiple spaces after operator") + } +} + +static OPERATOR_REGEX: Lazy = + Lazy::new(|| Regex::new(r"[^,\s](\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)").unwrap()); + +pub fn space_around_operator(line: &str) -> Vec<(usize, DiagnosticKind)> { + let mut diagnostics = vec![]; + for line_match in OPERATOR_REGEX.captures_iter(line) { + let before = line_match.get(1).unwrap(); + let after = line_match.get(2).unwrap().as_str(); + + if before.as_str().contains('\t') { + diagnostics.push((before.start(), TabBeforeOperator.into())); + } else if before.as_str().len() > 1 { + diagnostics.push((before.start(), MultipleSpacesBeforeOperator.into())); + } + + if after.contains('\t') { + diagnostics.push((before.start(), TabAfterOperator.into())); + } else if after.len() > 1 { + diagnostics.push((before.start(), MultipleSpacesAfterOperator.into())); + } + } + diagnostics +} diff --git a/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E221_E22.py.snap b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E221_E22.py.snap new file mode 100644 index 00000000000000..3716ba8c046797 --- /dev/null +++ b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E221_E22.py.snap @@ -0,0 +1,85 @@ +--- +source: src/rules/pycodestyle/mod.rs +expression: diagnostics +--- +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 3 + column: 5 + end_location: + row: 3 + column: 5 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 5 + column: 1 + end_location: + row: 5 + column: 1 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 6 + column: 1 + end_location: + row: 6 + column: 1 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 9 + column: 4 + end_location: + row: 9 + column: 4 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 10 + column: 4 + end_location: + row: 10 + column: 4 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 13 + column: 8 + end_location: + row: 13 + column: 8 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 15 + column: 8 + end_location: + row: 15 + column: 8 + fix: ~ + parent: ~ +- kind: + MultipleSpacesBeforeOperator: ~ + location: + row: 19 + column: 13 + end_location: + row: 19 + column: 13 + fix: ~ + parent: ~ + diff --git a/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E222_E22.py.snap b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E222_E22.py.snap new file mode 100644 index 00000000000000..63c2111608fca5 --- /dev/null +++ b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E222_E22.py.snap @@ -0,0 +1,55 @@ +--- +source: src/rules/pycodestyle/mod.rs +expression: diagnostics +--- +- kind: + MultipleSpacesAfterOperator: ~ + location: + row: 28 + column: 5 + end_location: + row: 28 + column: 5 + fix: ~ + parent: ~ +- kind: + MultipleSpacesAfterOperator: ~ + location: + row: 31 + column: 1 + end_location: + row: 31 + column: 1 + fix: ~ + parent: ~ +- kind: + MultipleSpacesAfterOperator: ~ + location: + row: 32 + column: 1 + end_location: + row: 32 + column: 1 + fix: ~ + parent: ~ +- kind: + MultipleSpacesAfterOperator: ~ + location: + row: 35 + column: 4 + end_location: + row: 35 + column: 4 + fix: ~ + parent: ~ +- kind: + MultipleSpacesAfterOperator: ~ + location: + row: 36 + column: 4 + end_location: + row: 36 + column: 4 + fix: ~ + parent: ~ + diff --git a/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E223_E22.py.snap b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E223_E22.py.snap new file mode 100644 index 00000000000000..61e968130ab19b --- /dev/null +++ b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E223_E22.py.snap @@ -0,0 +1,15 @@ +--- +source: src/rules/pycodestyle/mod.rs +expression: diagnostics +--- +- kind: + TabBeforeOperator: ~ + location: + row: 43 + column: 1 + end_location: + row: 43 + column: 1 + fix: ~ + parent: ~ + diff --git a/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E224_E22.py.snap b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E224_E22.py.snap new file mode 100644 index 00000000000000..18ed679c223047 --- /dev/null +++ b/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__E224_E22.py.snap @@ -0,0 +1,15 @@ +--- +source: src/rules/pycodestyle/mod.rs +expression: diagnostics +--- +- kind: + TabAfterOperator: ~ + location: + row: 48 + column: 1 + end_location: + row: 48 + column: 1 + fix: ~ + parent: ~ +