From 9063f4524d8c3d2eab75bb6a4b32db584e91715b Mon Sep 17 00:00:00 2001 From: konsti Date: Mon, 31 Jul 2023 19:25:16 +0200 Subject: [PATCH] Fix formatting of trailing unescaped quotes in raw triple quoted strings (#6202) **Summary** This prevents us from turning `r'''\""'''` into `r"""\"""""`, which is invalid syntax. This PR fixes CI, which is currently broken on main (in a way that still passes on linter PRs and allows merging formatter PRs, but it's bad to have a job be red). Once merged, i'll make the formatted ecosystem checks a required check. **Test Plan** Added a regression test. --- .../test/fixtures/ruff/expression/string.py | 6 ++++++ .../src/expression/string.rs | 19 +++++++++++++------ .../format@expression__string.py.snap | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/string.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/string.py index 6767a2463e9ed..78e215f91ada6 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/string.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/string.py @@ -24,6 +24,12 @@ r"Test" R"Test" +# Block conversion if there is an unescaped quote just before the end of the triple +# quoted string +r'''\""''' +r'''""''' +r'\""' + 'This string will not include \ backslashes or newline characters.' diff --git a/crates/ruff_python_formatter/src/expression/string.rs b/crates/ruff_python_formatter/src/expression/string.rs index fdf6270982562..d6ed59f5ed8e5 100644 --- a/crates/ruff_python_formatter/src/expression/string.rs +++ b/crates/ruff_python_formatter/src/expression/string.rs @@ -323,14 +323,21 @@ fn preferred_quotes_raw( break true; } - if chars.peek() == Some(&configured_quote_char) { - // `""` or `''` - chars.next(); + match chars.peek() { + // We can't turn `r'''\""'''` into `r"""\"""""`, this would confuse the parser + // about where the closing triple quotes start + None => break true, + Some(next) if *next == configured_quote_char => { + // `""` or `''` + chars.next(); - if chars.peek() == Some(&configured_quote_char) { - // `"""` or `'''` - break true; + // We can't turn `r'''""'''` into `r""""""""`, nor can we have + // `"""` or `'''` respectively inside the string + if chars.peek().is_none() || chars.peek() == Some(&configured_quote_char) { + break true; + } } + _ => {} } } Some(_) => continue, diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap index 53afe8b2a34c0..a3ed8ac6ec4b0 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__string.py.snap @@ -30,6 +30,12 @@ U"Test" r"Test" R"Test" +# Block conversion if there is an unescaped quote just before the end of the triple +# quoted string +r'''\""''' +r'''""''' +r'\""' + 'This string will not include \ backslashes or newline characters.' @@ -162,6 +168,12 @@ magic-trailing-comma = Respect r"Test" R"Test" +# Block conversion if there is an unescaped quote just before the end of the triple +# quoted string +r'''\""''' +r'''""''' +r'\""' + "This string will not include \ backslashes or newline characters." @@ -310,6 +322,12 @@ magic-trailing-comma = Respect r'Test' R'Test' +# Block conversion if there is an unescaped quote just before the end of the triple +# quoted string +r'''\""''' +r'''""''' +r'\""' + 'This string will not include \ backslashes or newline characters.'