Fix joining of f-strings with different quotes when using quote style Preserve (#15524)

This commit is contained in:
Micha Reiser 2025-01-16 12:01:42 +01:00 committed by GitHub
parent fc9dd63d64
commit 420365811f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 55 additions and 11 deletions

View file

@ -44,15 +44,33 @@ impl<'a, 'src> StringNormalizer<'a, 'src> {
let preferred_quote_style = self
.preferred_quote_style
.unwrap_or(self.context.options().quote_style());
let supports_pep_701 = self.context.options().target_version().supports_pep_701();
// For f-strings prefer alternating the quotes unless The outer string is triple quoted and the inner isn't.
if let FStringState::InsideExpressionElement(parent_context) = self.context.f_string_state()
{
let parent_flags = parent_context.f_string().flags();
if !parent_flags.is_triple_quoted() || string.flags().is_triple_quoted() {
// This logic is even necessary when using preserve and the target python version doesn't support PEP701 because
// we might end up joining two f-strings that have different quote styles, in which case we need to alternate the quotes
// for inner strings to avoid a syntax error: `string = "this is my string with " f'"{params.get("mine")}"'`
if !preferred_quote_style.is_preserve() || !supports_pep_701 {
return QuoteStyle::from(parent_flags.quote_style().opposite());
}
}
}
// Leave the quotes unchanged for all other strings.
if preferred_quote_style.is_preserve() {
return QuoteStyle::Preserve;
}
// There are cases where it is necessary to preserve the quotes to prevent an invalid f-string.
if let StringLikePart::FString(fstring) = string {
// There are two cases where it's necessary to preserve the quotes if the
// target version is pre 3.12 and the part is an f-string.
if !self.context.options().target_version().supports_pep_701() {
if !supports_pep_701 {
// An f-string expression contains a debug text with a quote character
// because the formatter will emit the debug expression **exactly** the
// same as in the source text.
@ -77,16 +95,6 @@ impl<'a, 'src> StringNormalizer<'a, 'src> {
}
}
// For f-strings prefer alternating the quotes unless The outer string is triple quoted and the inner isn't.
if let FStringState::InsideExpressionElement(parent_context) = self.context.f_string_state()
{
let parent_flags = parent_context.f_string().flags();
if !parent_flags.is_triple_quoted() || string.flags().is_triple_quoted() {
return QuoteStyle::from(parent_flags.quote_style().opposite());
}
}
// Per PEP 8, always prefer double quotes for triple-quoted strings.
if string.flags().is_triple_quoted() {
// ... unless we're formatting a code snippet inside a docstring,