diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py b/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py index ef350df454..287e71a1d9 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py @@ -22,6 +22,11 @@ in the middle #: W605:1:38 value = 'new line\nand invalid escape \_ here' + +def f(): + #: W605:1:11 + return'\.png$' + #: Okay regex = r'\.png$' regex = '\\.png$' diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/W605_1.py b/crates/ruff/resources/test/fixtures/pycodestyle/W605_1.py index 5322443e87..20bf0ea14c 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/W605_1.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/W605_1.py @@ -19,6 +19,11 @@ with \_ somewhere in the middle """ + +def f(): + #: W605:1:11 + return'\.png$' + #: Okay regex = r'\.png$' regex = '\\.png$' diff --git a/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs b/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs index 65a73bbf51..9a57ec84d8 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs @@ -70,10 +70,10 @@ pub(crate) fn invalid_escape_sequence( return diagnostics; }; let quote_pos = text.find(quote).unwrap(); - let prefix = text[..quote_pos].to_lowercase(); + let prefix = &text[..quote_pos]; let body = &text[quote_pos + quote.len()..text.len() - quote.len()]; - if !prefix.contains('r') { + if !prefix.contains(['r', 'R']) { let start_offset = range.start() + TextSize::try_from(quote_pos).unwrap() + quote.text_len(); @@ -115,7 +115,7 @@ pub(crate) fn invalid_escape_sequence( if autofix { if contains_valid_escape_sequence { - // Escape with backslash + // Escape with backslash. for diagnostic in &mut diagnostics { diagnostic.set_fix(Fix::automatic(Edit::insertion( r"\".to_string(), @@ -123,10 +123,23 @@ pub(crate) fn invalid_escape_sequence( ))); } } else { - // Turn into raw string + // Turn into raw string. for diagnostic in &mut diagnostics { + // If necessary, add a space between any leading keyword (`return`, `yield`, + // `assert`, etc.) and the string. For example, `return"foo"` is valid, but + // `returnr"foo"` is not. + let requires_space = locator + .slice(TextRange::up_to(range.start())) + .chars() + .last() + .map_or(false, |char| char.is_ascii_alphabetic()); + diagnostic.set_fix(Fix::automatic(Edit::insertion( - "r".to_string(), + if requires_space { + " r".to_string() + } else { + "r".to_string() + }, range.start() + TextSize::try_from(quote_pos).unwrap(), ))); } diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_0.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_0.py.snap index e863c676fd..7a4317fb36 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_0.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_0.py.snap @@ -85,8 +85,6 @@ W605_0.py:23:39: W605 [*] Invalid escape sequence: `\_` 22 | #: W605:1:38 23 | value = 'new line\nand invalid escape \_ here' | ^^ W605 -24 | -25 | #: Okay | = help: Add backslash to escape sequence @@ -97,7 +95,28 @@ W605_0.py:23:39: W605 [*] Invalid escape sequence: `\_` 23 |-value = 'new line\nand invalid escape \_ here' 23 |+value = 'new line\nand invalid escape \\_ here' 24 24 | -25 25 | #: Okay -26 26 | regex = r'\.png$' +25 25 | +26 26 | def f(): + +W605_0.py:28:12: W605 [*] Invalid escape sequence: `\.` + | +26 | def f(): +27 | #: W605:1:11 +28 | return'\.png$' + | ^^ W605 +29 | +30 | #: Okay + | + = help: Add backslash to escape sequence + +ℹ Fix +25 25 | +26 26 | def f(): +27 27 | #: W605:1:11 +28 |- return'\.png$' + 28 |+ return r'\.png$' +29 29 | +30 30 | #: Okay +31 31 | regex = r'\.png$' diff --git a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_1.py.snap b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_1.py.snap index e3e8807ca4..6b6f5939fb 100644 --- a/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_1.py.snap +++ b/crates/ruff/src/rules/pycodestyle/snapshots/ruff__rules__pycodestyle__tests__W605_W605_1.py.snap @@ -80,4 +80,25 @@ W605_1.py:18:6: W605 [*] Invalid escape sequence: `\_` 17 17 | literal 18 18 | with \_ somewhere +W605_1.py:25:12: W605 [*] Invalid escape sequence: `\.` + | +23 | def f(): +24 | #: W605:1:11 +25 | return'\.png$' + | ^^ W605 +26 | +27 | #: Okay + | + = help: Add backslash to escape sequence + +ℹ Fix +22 22 | +23 23 | def f(): +24 24 | #: W605:1:11 +25 |- return'\.png$' + 25 |+ return r'\.png$' +26 26 | +27 27 | #: Okay +28 28 | regex = r'\.png$' +