-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
dfe4291
commit dd4acf0
Showing
11 changed files
with
449 additions
and
4 deletions.
There are no files selected for viewing
143 changes: 143 additions & 0 deletions
143
crates/ruff_linter/resources/test/fixtures/pycodestyle/E122.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
#: E122 | ||
print("E122", ( | ||
"str")) | ||
|
||
# OK | ||
print("E122", ( | ||
"str")) | ||
|
||
#: E122:6:5 E122:7:5 E122:8:1 | ||
print(dedent( | ||
''' | ||
mkdir -p ./{build}/ | ||
mv ./build/ ./{build}/%(revision)s/ | ||
'''.format( | ||
build='build', | ||
# more stuff | ||
) | ||
)) | ||
|
||
# OK | ||
print(dedent( | ||
''' | ||
mkdir -p ./{build}/ | ||
mv ./build/ ./{build}/%(revision)s/ | ||
'''.format( | ||
build='build', | ||
# more stuff | ||
) | ||
)) | ||
|
||
#: E122 | ||
if True: | ||
result = some_function_that_takes_arguments( | ||
'a', 'b', 'c', | ||
'd', 'e', 'f', | ||
) | ||
|
||
# OK | ||
if True: | ||
result = some_function_that_takes_arguments( | ||
'a', 'b', 'c', | ||
'd', 'e', 'f', | ||
) | ||
|
||
#: E122 | ||
if some_very_very_very_long_variable_name or var \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
# OK | ||
if some_very_very_very_long_variable_name or var \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
#: E122 | ||
if some_very_very_very_long_variable_name or var[0] \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
# OK | ||
if some_very_very_very_long_variable_name or var[0] \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
#: E122 | ||
if True: | ||
if some_very_very_very_long_variable_name or var \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
# OK | ||
if True: | ||
if some_very_very_very_long_variable_name or var \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
#: E122 | ||
if True: | ||
if some_very_very_very_long_variable_name or var[0] \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
#: OK | ||
if True: | ||
if some_very_very_very_long_variable_name or var[0] \ | ||
or another_very_long_variable_name: | ||
raise Exception() | ||
|
||
#: E122 | ||
dictionary = { | ||
"is": { | ||
"nested": yes(), | ||
}, | ||
} | ||
|
||
# OK | ||
dictionary = { | ||
"is": { | ||
"nested": yes(), | ||
}, | ||
} | ||
|
||
#: E122 | ||
setup('', | ||
scripts=[''], | ||
classifiers=[ | ||
'Development Status :: 4 - Beta', | ||
'Environment :: Console', | ||
'Intended Audience :: Developers', | ||
]) | ||
|
||
# OK | ||
setup('', | ||
scripts=[''], | ||
classifiers=[ | ||
'Development Status :: 4 - Beta', | ||
'Environment :: Console', | ||
'Intended Audience :: Developers', | ||
]) | ||
|
||
#: E122:2:1 | ||
if True:\ | ||
print(True) | ||
|
||
# OK | ||
if True:\ | ||
print(True) | ||
|
||
# E122 | ||
def f(): | ||
x = (( | ||
( | ||
) | ||
) | ||
+ 2) | ||
|
||
# OK | ||
def f(): | ||
x = (( | ||
( | ||
) | ||
) | ||
+ 2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,23 @@ | ||
use crate::line_width::IndentWidth; | ||
|
||
/// Returns `true` if the name should be considered "ambiguous". | ||
pub(super) fn is_ambiguous_name(name: &str) -> bool { | ||
name == "l" || name == "I" || name == "O" | ||
} | ||
|
||
/// Return the amount of indentation, expanding tabs to the next multiple of the settings' tab size. | ||
pub(crate) fn expand_indent(line: &str, indent_width: IndentWidth) -> usize { | ||
let line = line.trim_end_matches(['\n', '\r']); | ||
|
||
let mut indent = 0; | ||
let tab_size = indent_width.as_usize(); | ||
for c in line.bytes() { | ||
match c { | ||
b'\t' => indent += (indent / tab_size) * tab_size + tab_size, | ||
b' ' => indent += 1, | ||
_ => break, | ||
} | ||
} | ||
|
||
indent | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
...ruff_linter/src/rules/pycodestyle/rules/logical_lines/missing_or_outdented_indentation.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
use super::{LogicalLine, LogicalLineToken}; | ||
use crate::checkers::logical_lines::LogicalLinesContext; | ||
use crate::line_width::IndentWidth; | ||
use ruff_diagnostics::{Diagnostic, Violation}; | ||
use ruff_macros::{derive_message_formats, violation}; | ||
use ruff_python_parser::TokenKind; | ||
use ruff_source_file::Locator; | ||
use ruff_text_size::{Ranged, TextRange}; | ||
|
||
use crate::rules::pycodestyle::helpers::expand_indent; | ||
|
||
/// ## What it does | ||
/// Checks for continuation lines not indented as far as they should be or indented too far. | ||
/// | ||
/// ## Why is this bad? | ||
/// This makes distinguishing continuation line harder. | ||
/// | ||
/// ## Example | ||
/// ```python | ||
/// print("Python", ( | ||
/// "Rules")) | ||
/// ``` | ||
/// | ||
/// Use instead: | ||
/// ```python | ||
/// print("Python", ( | ||
/// "Rules")) | ||
/// ``` | ||
/// | ||
/// [PEP 8]: https://www.python.org/dev/peps/pep-0008/#indentation | ||
#[violation] | ||
pub struct MissingOrOutdentedIndentation; | ||
|
||
impl Violation for MissingOrOutdentedIndentation { | ||
#[derive_message_formats] | ||
fn message(&self) -> String { | ||
format!("Continuation line missing indentation or outdented.") | ||
} | ||
} | ||
|
||
/// E122 | ||
pub(crate) fn missing_or_outdented_indentation( | ||
line: &LogicalLine, | ||
indent_level: usize, | ||
indent_width: IndentWidth, | ||
locator: &Locator, | ||
context: &mut LogicalLinesContext, | ||
) { | ||
if line.tokens().len() <= 1 { | ||
return; | ||
} | ||
|
||
let first_token = line.first_token().unwrap(); | ||
let mut line_end = locator.full_line_end(first_token.start()); | ||
|
||
let tab_size = indent_width.as_usize(); | ||
let mut indentation = indent_level; | ||
// Start by increasing indent on any continuation line | ||
let mut desired_indentation = indentation + tab_size; | ||
let mut indent_increased = true; | ||
let mut indentation_stack: std::vec::Vec<usize> = Vec::new(); | ||
|
||
let mut iter = line.tokens().iter().peekable(); | ||
while let Some(token) = iter.next() { | ||
// If continuation line | ||
if token.start() >= line_end { | ||
// Reset and calculate current indentation | ||
indent_increased = false; | ||
indentation = expand_indent(locator.line(token.start()), indent_width); | ||
|
||
// Calculate correct indentation | ||
let correct_indentation = if first_token_is_closing_bracket(token, iter.peek().copied()) | ||
{ | ||
// If first non-indent token is a closing bracket | ||
// then the correct indentation is the one on top of the stack | ||
// unless we are back at the starting indentation in which case | ||
// the initial indentation is correct. | ||
if desired_indentation == indent_level + tab_size { | ||
indent_level | ||
} else { | ||
*indentation_stack | ||
.last() | ||
.expect("Closing brackets should always be preceded by opening brackets") | ||
} | ||
} else { | ||
desired_indentation | ||
}; | ||
|
||
if indentation < correct_indentation { | ||
let diagnostic = Diagnostic::new( | ||
MissingOrOutdentedIndentation, | ||
TextRange::new(locator.line_start(token.start()), token.start()), | ||
); | ||
context.push_diagnostic(diagnostic); | ||
} | ||
|
||
line_end = locator.full_line_end(token.start()); | ||
} | ||
|
||
match token.kind() { | ||
TokenKind::Lpar | TokenKind::Lsqb | TokenKind::Lbrace => { | ||
// Store indent to return to once bracket closes | ||
indentation_stack.push(desired_indentation); | ||
// Only increase the indent once per continuation line | ||
if !indent_increased { | ||
desired_indentation += tab_size; | ||
indent_increased = true; | ||
} | ||
} | ||
TokenKind::Rpar | TokenKind::Rsqb | TokenKind::Rbrace => { | ||
// Return to previous indent | ||
desired_indentation = indentation_stack | ||
.pop() | ||
.expect("Closing brackets should always be preceded by opening brackets"); | ||
} | ||
_ => {} | ||
} | ||
} | ||
} | ||
|
||
fn first_token_is_closing_bracket( | ||
first_token: &LogicalLineToken, | ||
second_token: Option<&LogicalLineToken>, | ||
) -> bool { | ||
match first_token.kind { | ||
TokenKind::Rpar | TokenKind::Rsqb | TokenKind::Rbrace => true, | ||
TokenKind::Indent => { | ||
second_token.is_some() | ||
&& matches!( | ||
second_token.unwrap().kind, | ||
TokenKind::Rpar | TokenKind::Rsqb | TokenKind::Rbrace | ||
) | ||
} | ||
_ => false, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.