diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java index b309e5636758..a8fe74c5cce4 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java @@ -109,6 +109,7 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction element = element.getParent(); } final LanguageLevel languageLevel = LanguageLevel.forElement(element); + final boolean useFormatMethod = languageLevel.isAtLeast(LanguageLevel.PYTHON27); NotNullFunction escaper = StringUtil.escaper(false, "\"\'\\"); StringBuilder stringLiteral = new StringBuilder(); @@ -122,7 +123,11 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction quotes = PythonStringUtil.getQuotes(expression.getText()); quotesDetected = true; } - stringLiteral.append(escaper.fun(((PyStringLiteralExpression)expression).getStringValue())); + String value = ((PyStringLiteralExpression)expression).getStringValue(); + if (!useFormatMethod) { + value = value.replace("%", "%%"); + } + stringLiteral.append(escaper.fun(value)); } else { addParamToString(stringLiteral, paramCount, languageLevel); parameters.add(expression.getText()); @@ -137,7 +142,7 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction PyElementGenerator elementGenerator = PyElementGenerator.getInstance(project); if (!parameters.isEmpty()) { - if (LanguageLevel.forElement(element).isAtLeast(LanguageLevel.PYTHON27)) { + if (useFormatMethod) { stringLiteral.append(".format(").append(StringUtil.join(parameters, ",")).append(")"); } diff --git a/python/testData/intentions/afterStringConcatToFormatEscaping.py b/python/testData/intentions/afterStringConcatToFormatEscaping.py new file mode 100644 index 000000000000..1a9fa469aff7 --- /dev/null +++ b/python/testData/intentions/afterStringConcatToFormatEscaping.py @@ -0,0 +1,2 @@ +string = "bar" +some_string = "%%foo %s baz%%" % string diff --git a/python/testData/intentions/beforeStringConcatToFormatEscaping.py b/python/testData/intentions/beforeStringConcatToFormatEscaping.py new file mode 100644 index 000000000000..a5cad1632a75 --- /dev/null +++ b/python/testData/intentions/beforeStringConcatToFormatEscaping.py @@ -0,0 +1,2 @@ +string = "bar" +some_string = "%foo " + string + " baz%" diff --git a/python/testSrc/com/jetbrains/python/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/PyIntentionTest.java index 4ae80397e92d..13ecb4392e5d 100644 --- a/python/testSrc/com/jetbrains/python/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/PyIntentionTest.java @@ -358,6 +358,11 @@ public class PyIntentionTest extends PyTestCase { doTest(PyBundle.message("INTN.replace.plus.with.str.format"), LanguageLevel.PYTHON33); } + // PY-8588 + public void testStringConcatToFormatEscaping() { + doTest(PyBundle.message("INTN.replace.plus.with.format.operator")); + } + private void doDocStubTest(LanguageLevel languageLevel) { PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), languageLevel); try {