From 3d612d1e8fd36a06ff003cbeac8c121ddc703828 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 9 Jan 2025 18:49:37 +0100 Subject: [PATCH 1/4] Keep trailing part comment associated with its part --- crates/ruff_python_ast/src/expression.rs | 31 +++++++- ...implicit_concatenated_string_assignment.py | 43 ++++++++++ .../src/comments/placement.rs | 77 +++++++++++++++++- crates/ruff_python_formatter/src/lib.rs | 13 ++- .../format@expression__fstring.py.snap | 6 +- ...cit_concatenated_string_assignment.py.snap | 79 +++++++++++++++++++ 6 files changed, 235 insertions(+), 14 deletions(-) diff --git a/crates/ruff_python_ast/src/expression.rs b/crates/ruff_python_ast/src/expression.rs index 6f9db5a2cdeef..40bc5ea64f67b 100644 --- a/crates/ruff_python_ast/src/expression.rs +++ b/crates/ruff_python_ast/src/expression.rs @@ -407,13 +407,13 @@ pub enum StringLike<'a> { FString(&'a ast::ExprFString), } -impl StringLike<'_> { +impl<'a> StringLike<'a> { pub const fn is_fstring(self) -> bool { matches!(self, Self::FString(_)) } /// Returns an iterator over the [`StringLikePart`] contained in this string-like expression. - pub fn parts(&self) -> StringLikePartIter<'_> { + pub fn parts(&self) -> StringLikePartIter<'a> { match self { StringLike::String(expr) => StringLikePartIter::String(expr.value.iter()), StringLike::Bytes(expr) => StringLikePartIter::Bytes(expr.value.iter()), @@ -429,6 +429,14 @@ impl StringLike<'_> { Self::FString(ExprFString { value, .. }) => value.is_implicit_concatenated(), } } + + pub const fn as_expression_ref(self) -> ExpressionRef<'a> { + match self { + StringLike::String(expr) => ExpressionRef::StringLiteral(expr), + StringLike::Bytes(expr) => ExpressionRef::BytesLiteral(expr), + StringLike::FString(expr) => ExpressionRef::FString(expr), + } + } } impl<'a> From<&'a ast::ExprStringLiteral> for StringLike<'a> { @@ -488,6 +496,19 @@ impl<'a> TryFrom<&'a Expr> for StringLike<'a> { } } +impl<'a> TryFrom> for StringLike<'a> { + type Error = (); + + fn try_from(value: AnyNodeRef<'a>) -> Result { + match value { + AnyNodeRef::ExprStringLiteral(value) => Ok(Self::String(value)), + AnyNodeRef::ExprBytesLiteral(value) => Ok(Self::Bytes(value)), + AnyNodeRef::ExprFString(value) => Ok(Self::FString(value)), + _ => Err(()), + } + } +} + impl Ranged for StringLike<'_> { fn range(&self) -> TextRange { match self { @@ -561,6 +582,12 @@ impl<'a> From<&'a ast::FString> for StringLikePart<'a> { impl<'a> From<&StringLikePart<'a>> for AnyNodeRef<'a> { fn from(value: &StringLikePart<'a>) -> Self { + AnyNodeRef::from(*value) + } +} + +impl<'a> From> for AnyNodeRef<'a> { + fn from(value: StringLikePart<'a>) -> Self { match value { StringLikePart::String(part) => AnyNodeRef::StringLiteral(part), StringLikePart::Bytes(part) => AnyNodeRef::BytesLiteral(part), diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py index 2cd23efdc254d..9d2a1d148be65 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py @@ -291,3 +291,46 @@ f"testeeeeeeeeeeeeeeeeeeeeeeeee{a =}" "moreeeeeeeeeeeeeeeeeetest" # comment ) + + +# Trailing last-part comments + +a = ( + "a" + "b" # belongs to `b` +) + +a = ( + "a" + "b" +) # belongs to the assignment + + +a = ( + "a" "b" # belongs to the f-string expression +) + +a = ( + "a" "b" + # belongs to the f-string expression +) + +a = ( + "a" + "b" "c" # belongs to the f-string expression +) + +logger.error( + f"Failed to run task {task} for job" + f"with id {str(job.id)}" # type: ignore[union-attr] +) + +a = (10 + + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # belongs to binary operation +) + +a = 10 + ( + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # belongs to last-part +) diff --git a/crates/ruff_python_formatter/src/comments/placement.rs b/crates/ruff_python_formatter/src/comments/placement.rs index 02c61e2faadd4..22e2230354e0a 100644 --- a/crates/ruff_python_formatter/src/comments/placement.rs +++ b/crates/ruff_python_formatter/src/comments/placement.rs @@ -1,9 +1,7 @@ -use std::cmp::Ordering; - use ast::helpers::comment_indentation_after; use ruff_python_ast::whitespace::indentation; use ruff_python_ast::{ - self as ast, AnyNodeRef, Comprehension, Expr, ModModule, Parameter, Parameters, + self as ast, AnyNodeRef, Comprehension, Expr, ModModule, Parameter, Parameters, StringLike, }; use ruff_python_trivia::{ find_only_token_in_range, first_non_trivia_token, indentation_at_offset, BackwardsTokenizer, @@ -11,9 +9,11 @@ use ruff_python_trivia::{ }; use ruff_source_file::LineRanges; use ruff_text_size::{Ranged, TextLen, TextRange}; +use std::cmp::Ordering; use crate::comments::visitor::{CommentPlacement, DecoratedComment}; use crate::expression::expr_slice::{assign_comment_in_slice, ExprSliceCommentSection}; +use crate::expression::parentheses::is_expression_parenthesized; use crate::other::parameters::{ assign_argument_separator_comment_placement, find_parameter_separators, }; @@ -28,6 +28,9 @@ pub(super) fn place_comment<'a>( handle_parenthesized_comment(comment, source) .or_else(|comment| handle_end_of_line_comment_around_body(comment, source)) .or_else(|comment| handle_own_line_comment_around_body(comment, source)) + .or_else(|comment| { + handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) + }) .or_else(|comment| handle_enclosed_comment(comment, comment_ranges, source)) } @@ -2086,6 +2089,74 @@ fn handle_comprehension_comment<'a>( CommentPlacement::Default(comment) } +/// Handle end-of-line comments for parenthesized implicitly concatenated strings: +/// +/// ```python +/// a = ( +/// "a" +/// "b" +/// "c" # comment +/// ) +/// ``` +/// +/// `# comment` is a trailing comment of the last part and not a trailing comment of the entire f-string. +/// Associating the comment with the last part is important or the assignment formatting might move +/// the comment at the end of the assignment, making it impossible to suppress an error for the last part. +/// +/// On the other hand, `# comment` is a trailing end-of-line f-string comment for: +/// +/// ```python +/// a = ( +/// "a" "b" "c" # comment +/// ) +/// +/// a = ( +/// "a" +/// "b" +/// "c" +/// ) # comment +/// ``` +/// +/// Associating the comment with the f-string is desired in those cases because it allows +/// joining the string literals into a single string literal if it fits on the line. +fn handle_trailing_implicit_concatenated_string_comment<'a>( + comment: DecoratedComment<'a>, + comment_ranges: &CommentRanges, + source: &str, +) -> CommentPlacement<'a> { + if !comment.line_position().is_end_of_line() { + return CommentPlacement::Default(comment); + } + + let Some(string_like) = comment + .preceding_node() + .and_then(|preceding| StringLike::try_from(preceding).ok()) + else { + return CommentPlacement::Default(comment); + }; + + let mut parts = string_like.parts(); + + let (Some(last), Some(second_last)) = (parts.next_back(), parts.next_back()) else { + return CommentPlacement::Default(comment); + }; + + if source.contains_line_break(TextRange::new(second_last.end(), last.start())) + && is_expression_parenthesized(string_like.as_expression_ref(), comment_ranges, source) + { + let range = TextRange::new(last.end(), comment.start()); + + if !SimpleTokenizer::new(source, range) + .skip_trivia() + .any(|token| token.kind() == SimpleTokenKind::RParen) + { + return CommentPlacement::trailing(AnyNodeRef::from(last), comment); + } + } + + CommentPlacement::Default(comment) +} + /// Returns `true` if the parameters are parenthesized (as in a function definition), or `false` if /// not (as in a lambda). fn are_parameters_parenthesized(parameters: &Parameters, contents: &str) -> bool { diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index cbe56762f269d..839393983500f 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -186,13 +186,12 @@ if True: #[test] fn quick_test() { let source = r#" -def main() -> None: - if True: - some_very_long_variable_name_abcdefghijk = Foo() - some_very_long_variable_name_abcdefghijk = some_very_long_variable_name_abcdefghijk[ - some_very_long_variable_name_abcdefghijk.some_very_long_attribute_name - == "This is a very long string abcdefghijk" - ] +def test(): + a = 10 + ( + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe] + ) + "#; let source_type = PySourceType::Python; diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap index 5a9fbef4b9eac..6bc0043272754 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap @@ -776,7 +776,8 @@ result_f = ( ) ( - f"{1}{2}" # comment 3 + f"{1}" + f"{2}" # comment 3 ) ( @@ -1550,7 +1551,8 @@ result_f = ( ) ( - f"{1}{2}" # comment 3 + f"{1}" + f"{2}" # comment 3 ) ( diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap index b30f507d8d144..4eb4c221b1deb 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap @@ -1,6 +1,7 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py +snapshot_kind: text --- ## Input ```python @@ -297,6 +298,49 @@ aaaaa[aaaaaaaaaaa] = ( f"testeeeeeeeeeeeeeeeeeeeeeeeee{a =}" "moreeeeeeeeeeeeeeeeeetest" # comment ) + + +# Trailing last-part comments + +a = ( + "a" + "b" # belongs to `b` +) + +a = ( + "a" + "b" +) # belongs to the assignment + + +a = ( + "a" "b" # belongs to the f-string expression +) + +a = ( + "a" "b" + # belongs to the f-string expression +) + +a = ( + "a" + "b" "c" # belongs to the f-string expression +) + +logger.error( + f"Failed to run task {task} for job" + f"with id {str(job.id)}" # type: ignore[union-attr] +) + +a = (10 + + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # belongs to binary operation +) + +a = 10 + ( + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # belongs to last-part +) ``` ## Output @@ -619,4 +663,39 @@ aaaaa[aaaaaaaaaaa] = ( =}" "moreeeeeeeeeeeeeeeeeetest" # comment ) + + +# Trailing last-part comments + +a = ( + "a" + "b" # belongs to `b` +) + +a = "ab" # belongs to the assignment + + +a = "ab" # belongs to the f-string expression + +a = ( + "ab" + # belongs to the f-string expression +) + +a = "abc" # belongs to the f-string expression + +logger.error( + f"Failed to run task {task} for job" + f"with id {str(job.id)}" # type: ignore[union-attr] +) + +a = ( + 10 + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # belongs to binary operation +) + +a = 10 + ( + "Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # belongs to last-part +) ``` From bde498b49412a886f288c241dc470465fc12296f Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 10 Jan 2025 11:00:58 +0100 Subject: [PATCH 2/4] Only apply new logic in places where we use FormatLastStatementExpression --- ...implicit_concatenated_string_assignment.py | 37 +++++++++ .../src/comments/placement.rs | 41 +++++++++- crates/ruff_python_formatter/src/lib.rs | 13 ++-- .../src/string/implicit.rs | 2 +- .../format@expression__fstring.py.snap | 7 +- ...cit_concatenated_string_assignment.py.snap | 75 ++++++++++++++++++- 6 files changed, 155 insertions(+), 20 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py index 9d2a1d148be65..beccf1967b1f1 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py @@ -300,11 +300,36 @@ "b" # belongs to `b` ) +a: Literal[str] = ( + "a" + "b" # belongs to `b` +) + +a += ( + "a" + "b" # belongs to `b` +) + +a = ( + r"a" + r"b" # belongs to `b` +) + a = ( "a" "b" ) # belongs to the assignment +a = ((( + "a" + "b" # belongs to `b` +))) + +a = ((( + "a" + "b" +) # belongs to the f-string expression +)) a = ( "a" "b" # belongs to the f-string expression @@ -334,3 +359,15 @@ "Exception in {call_back_name} when handling msg on " f"'{msg.topic}': '{msg.payload}'" # belongs to last-part ) + +self._attr_unique_id = ( + f"{self._device.temperature.group_address_state}_" + f"{self._device.target_temperature.group_address_state}_" + f"{self._device.target_temperature.group_address}_" + f"{self._device._setpoint_shift.group_address}" # noqa: SLF001 +) + +return ( + f"Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe] +) \ No newline at end of file diff --git a/crates/ruff_python_formatter/src/comments/placement.rs b/crates/ruff_python_formatter/src/comments/placement.rs index 22e2230354e0a..6b3b07d966312 100644 --- a/crates/ruff_python_formatter/src/comments/placement.rs +++ b/crates/ruff_python_formatter/src/comments/placement.rs @@ -28,9 +28,6 @@ pub(super) fn place_comment<'a>( handle_parenthesized_comment(comment, source) .or_else(|comment| handle_end_of_line_comment_around_body(comment, source)) .or_else(|comment| handle_own_line_comment_around_body(comment, source)) - .or_else(|comment| { - handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) - }) .or_else(|comment| handle_enclosed_comment(comment, comment_ranges, source)) } @@ -358,6 +355,41 @@ fn handle_enclosed_comment<'a>( AnyNodeRef::ExprGenerator(generator) if generator.parenthesized => { handle_bracketed_end_of_line_comment(comment, source) } + AnyNodeRef::StmtReturn(_) => { + handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) + } + AnyNodeRef::StmtAssign(assignment) + if comment.preceding_node().is_some_and(|preceding| { + preceding.ptr_eq(AnyNodeRef::from(&*assignment.value)) + }) => + { + handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) + } + AnyNodeRef::StmtAnnAssign(assignment) + if comment.preceding_node().is_some_and(|preceding| { + assignment + .value + .as_deref() + .is_some_and(|value| preceding.ptr_eq(value.into())) + }) => + { + handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) + } + AnyNodeRef::StmtAugAssign(assignment) + if comment.preceding_node().is_some_and(|preceding| { + preceding.ptr_eq(AnyNodeRef::from(&*assignment.value)) + }) => + { + handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) + } + AnyNodeRef::StmtTypeAlias(assignment) + if comment.preceding_node().is_some_and(|preceding| { + preceding.ptr_eq(AnyNodeRef::from(&*assignment.value)) + }) => + { + handle_trailing_implicit_concatenated_string_comment(comment, comment_ranges, source) + } + _ => CommentPlacement::Default(comment), } } @@ -2089,7 +2121,8 @@ fn handle_comprehension_comment<'a>( CommentPlacement::Default(comment) } -/// Handle end-of-line comments for parenthesized implicitly concatenated strings: +/// Handle end-of-line comments for parenthesized implicitly concatenated strings when used in +/// a `FormatStatementLastExpression` context: /// /// ```python /// a = ( diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 839393983500f..cbe56762f269d 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -186,12 +186,13 @@ if True: #[test] fn quick_test() { let source = r#" -def test(): - a = 10 + ( - "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe] - ) - +def main() -> None: + if True: + some_very_long_variable_name_abcdefghijk = Foo() + some_very_long_variable_name_abcdefghijk = some_very_long_variable_name_abcdefghijk[ + some_very_long_variable_name_abcdefghijk.some_very_long_attribute_name + == "This is a very long string abcdefghijk" + ] "#; let source_type = PySourceType::Python; diff --git a/crates/ruff_python_formatter/src/string/implicit.rs b/crates/ruff_python_formatter/src/string/implicit.rs index c13ec2d593258..88061d0792aff 100644 --- a/crates/ruff_python_formatter/src/string/implicit.rs +++ b/crates/ruff_python_formatter/src/string/implicit.rs @@ -99,7 +99,7 @@ impl Format> for FormatImplicitConcatenatedStringExpanded<'_ StringLikePart::FString(part) => part.format().fmt(f), }); - let part_comments = comments.leading_dangling_trailing(&part); + let part_comments = comments.leading_dangling_trailing(part); joiner.entry(&format_args![ leading_comments(part_comments.leading), format_part, diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap index 6bc0043272754..f8020fc193ec8 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__fstring.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/fstring.py -snapshot_kind: text --- ## Input ```python @@ -776,8 +775,7 @@ result_f = ( ) ( - f"{1}" - f"{2}" # comment 3 + f"{1}{2}" # comment 3 ) ( @@ -1551,8 +1549,7 @@ result_f = ( ) ( - f"{1}" - f"{2}" # comment 3 + f"{1}{2}" # comment 3 ) ( diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap index 4eb4c221b1deb..4b19bf1e8a3b2 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap @@ -1,7 +1,6 @@ --- source: crates/ruff_python_formatter/tests/fixtures.rs input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py -snapshot_kind: text --- ## Input ```python @@ -307,11 +306,36 @@ a = ( "b" # belongs to `b` ) +a: Literal[str] = ( + "a" + "b" # belongs to `b` +) + +a += ( + "a" + "b" # belongs to `b` +) + +a = ( + r"a" + r"b" # belongs to `b` +) + a = ( "a" "b" ) # belongs to the assignment +a = ((( + "a" + "b" # belongs to `b` +))) + +a = ((( + "a" + "b" +) # belongs to the f-string expression +)) a = ( "a" "b" # belongs to the f-string expression @@ -341,7 +365,18 @@ a = 10 + ( "Exception in {call_back_name} when handling msg on " f"'{msg.topic}': '{msg.payload}'" # belongs to last-part ) -``` + +self._attr_unique_id = ( + f"{self._device.temperature.group_address_state}_" + f"{self._device.target_temperature.group_address_state}_" + f"{self._device.target_temperature.group_address}_" + f"{self._device._setpoint_shift.group_address}" # noqa: SLF001 +) + +return ( + f"Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe] +)``` ## Output ```python @@ -672,8 +707,29 @@ a = ( "b" # belongs to `b` ) +a: Literal[str] = ( + "a" + "b" # belongs to `b` +) + +a += ( + "a" + "b" # belongs to `b` +) + +a = ( + r"a" + r"b" # belongs to `b` +) + a = "ab" # belongs to the assignment +a = ( + "a" + "b" # belongs to `b` +) + +a = "ab" # belongs to the f-string expression a = "ab" # belongs to the f-string expression @@ -685,8 +741,7 @@ a = ( a = "abc" # belongs to the f-string expression logger.error( - f"Failed to run task {task} for job" - f"with id {str(job.id)}" # type: ignore[union-attr] + f"Failed to run task {task} for jobwith id {str(job.id)}" # type: ignore[union-attr] ) a = ( @@ -698,4 +753,16 @@ a = 10 + ( "Exception in {call_back_name} when handling msg on " f"'{msg.topic}': '{msg.payload}'" # belongs to last-part ) + +self._attr_unique_id = ( + f"{self._device.temperature.group_address_state}_" + f"{self._device.target_temperature.group_address_state}_" + f"{self._device.target_temperature.group_address}_" + f"{self._device._setpoint_shift.group_address}" # noqa: SLF001 +) + +return ( + f"Exception in {call_back_name} when handling msg on " + f"'{msg.topic}': '{msg.payload}'" # type: ignore[str-bytes-safe] +) ``` From 09738cc4aa2aac897ffb4542987505b1e6c4eaaf Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 10 Jan 2025 14:18:46 +0100 Subject: [PATCH 3/4] improve test examples --- ...join_implicit_concatenated_string_assignment.py | 8 ++++---- ...implicit_concatenated_string_assignment.py.snap | 14 ++++++-------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py index beccf1967b1f1..544608dc61e88 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py @@ -351,13 +351,13 @@ ) a = (10 + - "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # belongs to binary operation + "Exception in {call_back_name} " + f"'{msg}'" # belongs to binary operation ) a = 10 + ( - "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # belongs to last-part + "Exception in {call_back_name} " + f"'{msg}'" # belongs to f-string ) self._attr_unique_id = ( diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap index 4b19bf1e8a3b2..0b22aea593d22 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap @@ -357,13 +357,13 @@ logger.error( ) a = (10 + - "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # belongs to binary operation + "Exception in {call_back_name} " + f"'{msg}'" # belongs to binary operation ) a = 10 + ( - "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # belongs to last-part + "Exception in {call_back_name} " + f"'{msg}'" # belongs to f-string ) self._attr_unique_id = ( @@ -745,13 +745,11 @@ logger.error( ) a = ( - 10 + "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # belongs to binary operation + 10 + f"Exception in {{call_back_name}} '{msg}'" # belongs to binary operation ) a = 10 + ( - "Exception in {call_back_name} when handling msg on " - f"'{msg.topic}': '{msg.payload}'" # belongs to last-part + f"Exception in {{call_back_name}} '{msg}'" # belongs to f-string ) self._attr_unique_id = ( From d12a0e0276b3f503181146c428a04e6ee918420f Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Fri, 10 Jan 2025 15:16:54 +0100 Subject: [PATCH 4/4] Add comment --- ...in_implicit_concatenated_string_assignment.py | 6 +++++- ...plicit_concatenated_string_assignment.py.snap | 16 ++++++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py index 544608dc61e88..642ad83c27444 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/join_implicit_concatenated_string_assignment.py @@ -340,9 +340,13 @@ # belongs to the f-string expression ) +# There's no "right" answer if some parts are on the same line while others are on separate lines. +# This is likely a comment for one of the last two parts but could also just be a comment for the entire f-string expression. +# Because there's no right answer, follow what we do elsewhere and associate the comment with the outer-most node which +# is the f-string expression. a = ( "a" - "b" "c" # belongs to the f-string expression + "b" "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" # belongs to the f-string expression ) logger.error( diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap index 0b22aea593d22..7133eb0b8c117 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__join_implicit_concatenated_string_assignment.py.snap @@ -346,9 +346,13 @@ a = ( # belongs to the f-string expression ) +# There's no "right" answer if some parts are on the same line while others are on separate lines. +# This is likely a comment for one of the last two parts but could also just be a comment for the entire f-string expression. +# Because there's no right answer, follow what we do elsewhere and associate the comment with the outer-most node which +# is the f-string expression. a = ( "a" - "b" "c" # belongs to the f-string expression + "b" "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" # belongs to the f-string expression ) logger.error( @@ -738,7 +742,15 @@ a = ( # belongs to the f-string expression ) -a = "abc" # belongs to the f-string expression +# There's no "right" answer if some parts are on the same line while others are on separate lines. +# This is likely a comment for one of the last two parts but could also just be a comment for the entire f-string expression. +# Because there's no right answer, follow what we do elsewhere and associate the comment with the outer-most node which +# is the f-string expression. +a = ( + "a" + "b" + "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" +) # belongs to the f-string expression logger.error( f"Failed to run task {task} for jobwith id {str(job.id)}" # type: ignore[union-attr]