Allow shebang comments at start-of-file (#4473)

This commit is contained in:
Charlie Marsh 2023-05-17 12:32:12 -04:00 committed by GitHub
parent 67c5086aba
commit 3bc29d6c0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 71 additions and 7 deletions

View File

@ -64,3 +64,11 @@ a = 42 #  (One space one NBSP)
#: E262:2:9 #: E262:2:9
# (Two spaces) Ok for block comment # (Two spaces) Ok for block comment
a = 42 # (Two spaces) a = 42 # (Two spaces)
#: E265:5:1
### Means test is not done yet
# E Means test is giving error (E)
# F Means test is failing (F)
# EF Means test is giving error and Failing
#! Means test is segfaulting
# 8 Means test runs forever

View File

@ -0,0 +1,4 @@
#!/usr/bin/python
#
#!
#:

View File

@ -67,7 +67,7 @@ pub(crate) fn check_logical_lines(
} }
if line.flags().contains(TokenFlags::COMMENT) { if line.flags().contains(TokenFlags::COMMENT) {
whitespace_before_comment(&line, locator, prev_line.is_none(), &mut context); whitespace_before_comment(&line, locator, &mut context);
} }
if line.flags().contains(TokenFlags::BRACKET) { if line.flags().contains(TokenFlags::BRACKET) {

View File

@ -128,6 +128,21 @@ mod tests {
Ok(()) Ok(())
} }
#[test]
fn shebang() -> Result<()> {
let diagnostics = test_path(
Path::new("pycodestyle/shebang.py"),
&settings::Settings::for_rules(vec![
Rule::TooFewSpacesBeforeInlineComment,
Rule::NoSpaceAfterInlineComment,
Rule::NoSpaceAfterBlockComment,
Rule::MultipleLeadingHashesForBlockComment,
]),
)?;
assert_messages!(diagnostics);
Ok(())
}
#[test_case(false)] #[test_case(false)]
#[test_case(true)] #[test_case(true)]
fn task_tags(ignore_overlong_task_comments: bool) -> Result<()> { fn task_tags(ignore_overlong_task_comments: bool) -> Result<()> {

View File

@ -151,6 +151,11 @@ pub(crate) struct LogicalLine<'a> {
} }
impl<'a> LogicalLine<'a> { impl<'a> LogicalLine<'a> {
/// Returns `true` if this line is positioned at the start of the file.
pub(crate) const fn is_start_of_file(&self) -> bool {
self.line.tokens_start == 0
}
/// Returns `true` if this is a comment only line /// Returns `true` if this is a comment only line
pub(crate) fn is_comment_only(&self) -> bool { pub(crate) fn is_comment_only(&self) -> bool {
self.flags() == TokenFlags::COMMENT self.flags() == TokenFlags::COMMENT

View File

@ -139,7 +139,6 @@ impl Violation for MultipleLeadingHashesForBlockComment {
pub(crate) fn whitespace_before_comment( pub(crate) fn whitespace_before_comment(
line: &LogicalLine, line: &LogicalLine,
locator: &Locator, locator: &Locator,
is_first_row: bool,
context: &mut LogicalLinesContext, context: &mut LogicalLinesContext,
) { ) {
let mut prev_end = TextSize::default(); let mut prev_end = TextSize::default();
@ -149,13 +148,13 @@ pub(crate) fn whitespace_before_comment(
if let TokenKind::Comment = kind { if let TokenKind::Comment = kind {
let range = token.range(); let range = token.range();
let line = locator.slice(TextRange::new( let line_text = locator.slice(TextRange::new(
locator.line_start(range.start()), locator.line_start(range.start()),
range.start(), range.start(),
)); ));
let text = locator.slice(range); let token_text = locator.slice(range);
let is_inline_comment = !line.trim().is_empty(); let is_inline_comment = !line_text.trim().is_empty();
if is_inline_comment { if is_inline_comment {
if range.start() - prev_end < " ".text_len() { if range.start() - prev_end < " ".text_len() {
context.push( context.push(
@ -166,7 +165,7 @@ pub(crate) fn whitespace_before_comment(
} }
// Split into the portion before and after the first space. // Split into the portion before and after the first space.
let mut parts = text.splitn(2, ' '); let mut parts = token_text.splitn(2, ' ');
let symbol = parts.next().unwrap_or(""); let symbol = parts.next().unwrap_or("");
let comment = parts.next().unwrap_or(""); let comment = parts.next().unwrap_or("");
@ -182,7 +181,7 @@ pub(crate) fn whitespace_before_comment(
context.push(NoSpaceAfterInlineComment, range); context.push(NoSpaceAfterInlineComment, range);
} }
} else if let Some(bad_prefix) = bad_prefix { } else if let Some(bad_prefix) = bad_prefix {
if bad_prefix != '!' || !is_first_row { if bad_prefix != '!' || !line.is_start_of_file() {
if bad_prefix != '#' { if bad_prefix != '#' {
context.push(NoSpaceAfterBlockComment, range); context.push(NoSpaceAfterBlockComment, range);
} else if !comment.is_empty() { } else if !comment.is_empty() {

View File

@ -47,6 +47,8 @@ E26.py:66:9: E262 Inline comment should start with `# `
67 | # (Two spaces) Ok for block comment 67 | # (Two spaces) Ok for block comment
68 | a = 42 # (Two spaces) 68 | a = 42 # (Two spaces)
| ^^^^^^^^^^^^^^^ E262 | ^^^^^^^^^^^^^^^ E262
69 |
70 | #: E265:5:1
| |

View File

@ -40,4 +40,13 @@ E26.py:32:1: E265 Block comment should start with `# `
35 | pass # an inline comment 35 | pass # an inline comment
| |
E26.py:73:1: E265 Block comment should start with `# `
|
73 | # F Means test is failing (F)
74 | # EF Means test is giving error and Failing
75 | #! Means test is segfaulting
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E265
76 | # 8 Means test runs forever
|

View File

@ -30,4 +30,13 @@ E26.py:26:1: E266 Too many leading `#` before block comment
30 | ######################################### 30 | #########################################
| |
E26.py:69:1: E266 Too many leading `#` before block comment
|
69 | #: E265:5:1
70 | ### Means test is not done yet
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E266
71 | # E Means test is giving error (E)
72 | # F Means test is failing (F)
|

View File

@ -0,0 +1,13 @@
---
source: crates/ruff/src/rules/pycodestyle/mod.rs
---
shebang.py:3:1: E265 Block comment should start with `# `
|
3 | #!/usr/bin/python
4 | #
5 | #!
| ^^ E265
6 | #:
|