From 0ce38b650ec3a8a05a849d229a41ea9a99610e2a Mon Sep 17 00:00:00 2001 From: Shantanu <12621235+hauntsaninja@users.noreply.github.com> Date: Sun, 25 Jun 2023 14:35:07 -0700 Subject: [PATCH] Change W605 autofix to use raw strings if possible (#5352) Fixes #5061. --- .../test/fixtures/pycodestyle/W605_0.py | 3 ++ .../rules/invalid_escape_sequence.rs | 31 ++++++++++---- ...s__pycodestyle__tests__W605_W605_0.py.snap | 40 ++++++++++++++----- ...s__pycodestyle__tests__W605_W605_1.py.snap | 24 +++++------ 4 files changed, 69 insertions(+), 29 deletions(-) diff --git a/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py b/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py index 5322443e87..ef350df454 100644 --- a/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py +++ b/crates/ruff/resources/test/fixtures/pycodestyle/W605_0.py @@ -19,6 +19,9 @@ with \_ somewhere in the middle """ +#: W605:1:38 +value = 'new line\nand invalid escape \_ here' + #: 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 792ec845ec..65a73bbf51 100644 --- a/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs +++ b/crates/ruff/src/rules/pycodestyle/rules/invalid_escape_sequence.rs @@ -79,6 +79,8 @@ pub(crate) fn invalid_escape_sequence( let mut chars_iter = body.char_indices().peekable(); + let mut contains_valid_escape_sequence = false; + while let Some((i, c)) = chars_iter.next() { if c != '\\' { continue; @@ -101,20 +103,35 @@ pub(crate) fn invalid_escape_sequence( // If the next character is a valid escape sequence, skip. if VALID_ESCAPE_SEQUENCES.contains(next_char) { + contains_valid_escape_sequence = true; continue; } let location = start_offset + TextSize::try_from(i).unwrap(); let range = TextRange::at(location, next_char.text_len() + TextSize::from(1)); - let mut diagnostic = Diagnostic::new(InvalidEscapeSequence(*next_char), range); - if autofix { - diagnostic.set_fix(Fix::automatic(Edit::insertion( - r"\".to_string(), - range.start() + TextSize::from(1), - ))); - } + let diagnostic = Diagnostic::new(InvalidEscapeSequence(*next_char), range); diagnostics.push(diagnostic); } + + if autofix { + if contains_valid_escape_sequence { + // Escape with backslash + for diagnostic in &mut diagnostics { + diagnostic.set_fix(Fix::automatic(Edit::insertion( + r"\".to_string(), + diagnostic.range().start() + TextSize::from(1), + ))); + } + } else { + // Turn into raw string + for diagnostic in &mut diagnostics { + diagnostic.set_fix(Fix::automatic(Edit::insertion( + "r".to_string(), + range.start() + TextSize::try_from(quote_pos).unwrap(), + ))); + } + } + } } diagnostics 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 fb5b4e8950..e863c676fd 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 @@ -14,7 +14,7 @@ W605_0.py:2:10: W605 [*] Invalid escape sequence: `\.` ℹ Fix 1 1 | #: W605:1:10 2 |-regex = '\.png$' - 2 |+regex = '\\.png$' + 2 |+regex = r'\.png$' 3 3 | 4 4 | #: W605:2:1 5 5 | regex = ''' @@ -30,14 +30,14 @@ W605_0.py:6:1: W605 [*] Invalid escape sequence: `\.` = help: Add backslash to escape sequence ℹ Fix +2 2 | regex = '\.png$' 3 3 | 4 4 | #: W605:2:1 -5 5 | regex = ''' -6 |-\.png$ - 6 |+\\.png$ +5 |-regex = ''' + 5 |+regex = r''' +6 6 | \.png$ 7 7 | ''' 8 8 | -9 9 | #: W605:2:6 W605_0.py:11:6: W605 [*] Invalid escape sequence: `\_` | @@ -54,7 +54,7 @@ W605_0.py:11:6: W605 [*] Invalid escape sequence: `\_` 9 9 | #: W605:2:6 10 10 | f( 11 |- '\_' - 11 |+ '\\_' + 11 |+ r'\_' 12 12 | ) 13 13 | 14 14 | #: W605:4:6 @@ -71,13 +71,33 @@ W605_0.py:18:6: W605 [*] Invalid escape sequence: `\_` = help: Add backslash to escape sequence ℹ Fix -15 15 | """ +12 12 | ) +13 13 | +14 14 | #: W605:4:6 +15 |-""" + 15 |+r""" 16 16 | multi-line 17 17 | literal -18 |-with \_ somewhere - 18 |+with \\_ somewhere -19 19 | in the middle +18 18 | with \_ somewhere + +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 + +ℹ Fix 20 20 | """ 21 21 | +22 22 | #: W605:1:38 +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$' 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 b6e26e233a..e3e8807ca4 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 @@ -14,7 +14,7 @@ W605_1.py:2:10: W605 [*] Invalid escape sequence: `\.` ℹ Fix 1 1 | #: W605:1:10 2 |-regex = '\.png$' - 2 |+regex = '\\.png$' + 2 |+regex = r'\.png$' 3 3 | 4 4 | #: W605:2:1 5 5 | regex = ''' @@ -30,14 +30,14 @@ W605_1.py:6:1: W605 [*] Invalid escape sequence: `\.` = help: Add backslash to escape sequence ℹ Fix +2 2 | regex = '\.png$' 3 3 | 4 4 | #: W605:2:1 -5 5 | regex = ''' -6 |-\.png$ - 6 |+\\.png$ +5 |-regex = ''' + 5 |+regex = r''' +6 6 | \.png$ 7 7 | ''' 8 8 | -9 9 | #: W605:2:6 W605_1.py:11:6: W605 [*] Invalid escape sequence: `\_` | @@ -54,7 +54,7 @@ W605_1.py:11:6: W605 [*] Invalid escape sequence: `\_` 9 9 | #: W605:2:6 10 10 | f( 11 |- '\_' - 11 |+ '\\_' + 11 |+ r'\_' 12 12 | ) 13 13 | 14 14 | #: W605:4:6 @@ -71,13 +71,13 @@ W605_1.py:18:6: W605 [*] Invalid escape sequence: `\_` = help: Add backslash to escape sequence ℹ Fix -15 15 | """ +12 12 | ) +13 13 | +14 14 | #: W605:4:6 +15 |-""" + 15 |+r""" 16 16 | multi-line 17 17 | literal -18 |-with \_ somewhere - 18 |+with \\_ somewhere -19 19 | in the middle -20 20 | """ -21 21 | +18 18 | with \_ somewhere