From d1a76d00112c3252ac3a17b7ecdc0d2bc8c2e8b0 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Thu, 24 Aug 2023 19:33:55 +0200 Subject: [PATCH] POC of assert formatting --- crates/ruff_formatter/src/format_element.rs | 15 +- .../src/format_element/document.rs | 11 ++ crates/ruff_formatter/src/printer/mod.rs | 8 + crates/ruff_python_formatter/src/builders.rs | 23 ++- .../src/expression/mod.rs | 70 ++++--- .../src/expression/parentheses.rs | 15 +- .../src/statement/stmt_assert.rs | 117 +++++++++-- ...tibility@simple_cases__composition.py.snap | 63 ++---- ...ses__composition_no_trailing_comma.py.snap | 63 ++---- .../format@statement__assert.py.snap | 183 ++++++++---------- 10 files changed, 323 insertions(+), 245 deletions(-) diff --git a/crates/ruff_formatter/src/format_element.rs b/crates/ruff_formatter/src/format_element.rs index f9fe281df3..dea1e2b030 100644 --- a/crates/ruff_formatter/src/format_element.rs +++ b/crates/ruff_formatter/src/format_element.rs @@ -11,7 +11,7 @@ use unicode_width::UnicodeWidthChar; use crate::format_element::tag::{GroupMode, LabelId, Tag}; use crate::source_code::SourceCodeSlice; -use crate::{IndentWidth, TagKind}; +use crate::{GroupId, IndentWidth, TagKind}; use ruff_text_size::TextSize; /// Language agnostic IR for formatting source code. @@ -34,7 +34,9 @@ pub enum FormatElement { SourcePosition(TextSize), /// A ASCII only Token that contains no line breaks or tab characters. - Token { text: &'static str }, + Token { + text: &'static str, + }, /// An arbitrary text that can contain tabs, newlines, and unicode characters. Text { @@ -57,6 +59,11 @@ pub enum FormatElement { /// deep cloning the IR when using the `best_fitting!` macro or `if_group_fits_on_line` and `if_group_breaks`. Interned(Interned), + GroupMode { + id: GroupId, + mode: PrintMode, + }, + /// A list of different variants representing the same content. The printer picks the best fitting content. /// Line breaks inside of a best fitting don't propagate to parent groups. BestFitting { @@ -97,6 +104,9 @@ impl std::fmt::Debug for FormatElement { .field("variants", variants) .field("mode", &mode) .finish(), + FormatElement::GroupMode { id, mode } => { + fmt.debug_tuple("GroupMode").field(id).field(mode).finish() + } FormatElement::Interned(interned) => fmt.debug_list().entries(&**interned).finish(), FormatElement::Tag(tag) => fmt.debug_tuple("Tag").field(tag).finish(), FormatElement::SourcePosition(position) => { @@ -277,6 +287,7 @@ impl FormatElements for FormatElement { FormatElement::LineSuffixBoundary | FormatElement::Space | FormatElement::Tag(_) + | FormatElement::GroupMode { .. } | FormatElement::Token { .. } | FormatElement::SourcePosition(_) => false, } diff --git a/crates/ruff_formatter/src/format_element/document.rs b/crates/ruff_formatter/src/format_element/document.rs index d5e71fd495..f24c8d05c4 100644 --- a/crates/ruff_formatter/src/format_element/document.rs +++ b/crates/ruff_formatter/src/format_element/document.rs @@ -381,6 +381,17 @@ impl Format> for &[FormatElement] { write!(f, [token("])")])?; } + FormatElement::GroupMode { id, mode } => write!( + f, + [ + token("group_mode("), + text(&std::format!("{id:?}"), None), + token(", "), + text(&std::format!("{mode:?}"), None), + token(")") + ] + )?, + FormatElement::Interned(interned) => { let interned_elements = &mut f.context_mut().printed_interned_elements; diff --git a/crates/ruff_formatter/src/printer/mod.rs b/crates/ruff_formatter/src/printer/mod.rs index 4535234fa3..4a60725e13 100644 --- a/crates/ruff_formatter/src/printer/mod.rs +++ b/crates/ruff_formatter/src/printer/mod.rs @@ -141,6 +141,10 @@ impl<'a> Printer<'a> { // Handled in `Document::propagate_expands() } + FormatElement::GroupMode { id, mode } => { + self.state.group_modes.insert_print_mode(*id, *mode); + } + FormatElement::SourcePosition(position) => { self.state.source_position = *position; self.push_marker(); @@ -1219,6 +1223,10 @@ impl<'a, 'print> FitsMeasurer<'a, 'print> { } } + FormatElement::GroupMode { id, mode } => { + self.group_modes_mut().insert_print_mode(*id, *mode); + } + FormatElement::ExpandParent => { if self.must_be_flat { return Ok(Fits::No); diff --git a/crates/ruff_python_formatter/src/builders.rs b/crates/ruff_python_formatter/src/builders.rs index fa4e30ea79..087f4086e5 100644 --- a/crates/ruff_python_formatter/src/builders.rs +++ b/crates/ruff_python_formatter/src/builders.rs @@ -1,4 +1,4 @@ -use ruff_formatter::{format_args, write, Argument, Arguments}; +use ruff_formatter::{format_args, write, Argument, Arguments, GroupId}; use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::context::{NodeLevel, WithNodeLevel}; @@ -12,11 +12,28 @@ where { ParenthesizeIfExpands { inner: Argument::new(content), + group_id: None, + should_expand: false, } } pub(crate) struct ParenthesizeIfExpands<'a, 'ast> { inner: Argument<'a, PyFormatContext<'ast>>, + group_id: Option, + should_expand: bool, +} + +impl ParenthesizeIfExpands<'_, '_> { + #[must_use] + pub(crate) fn should_expand(mut self, expand: bool) -> Self { + self.should_expand = expand; + self + } + + pub(crate) fn with_group_id(mut self, group_id: GroupId) -> Self { + self.group_id = Some(group_id); + self + } } impl<'ast> Format> for ParenthesizeIfExpands<'_, 'ast> { @@ -30,7 +47,9 @@ impl<'ast> Format> for ParenthesizeIfExpands<'_, 'ast> { if_group_breaks(&token("(")), soft_block_indent(&Arguments::from(&self.inner)), if_group_breaks(&token(")")), - ])] + ]) + .with_group_id(self.group_id) + .should_expand(self.should_expand)] ) } } diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 6cae0c2973..7cd6fc7747 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -12,7 +12,7 @@ use ruff_python_ast::{Constant, Expr, ExpressionRef, Operator}; use ruff_python_trivia::CommentRanges; use crate::builders::parenthesize_if_expands; -use crate::comments::leading_comments; +use crate::comments::{leading_comments, LeadingDanglingTrailingComments}; use crate::context::{NodeLevel, WithNodeLevel}; use crate::expression::parentheses::{ is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses, @@ -179,6 +179,45 @@ pub(crate) struct MaybeParenthesizeExpression<'a> { parenthesize: Parenthesize, } +impl MaybeParenthesizeExpression<'_> { + pub(crate) fn needs_parentheses( + &self, + context: &PyFormatContext, + node_comments: &LeadingDanglingTrailingComments, + ) -> OptionalParentheses { + let MaybeParenthesizeExpression { + expression, + parent, + parenthesize, + } = self; + + let preserve_parentheses = parenthesize.is_optional() + && is_expression_parenthesized( + (*expression).into(), + context.comments().ranges(), + context.source(), + ); + + let has_comments = node_comments.has_leading() || node_comments.has_trailing_own_line(); + + // If the expression has comments, we always want to preserve the parentheses. This also + // ensures that we correctly handle parenthesized comments, and don't need to worry about + // them in the implementation below. + if preserve_parentheses || has_comments { + OptionalParentheses::Always + } else { + match expression.needs_parentheses(*parent, context) { + OptionalParentheses::Always => OptionalParentheses::Always, + // The reason to add parentheses is to avoid a syntax error when breaking an expression over multiple lines. + // Therefore, it is unnecessary to add an additional pair of parentheses if an outer expression + // is parenthesized. + _ if context.node_level().is_parenthesized() => OptionalParentheses::Never, + needs_parentheses => needs_parentheses, + } + } + } +} + impl Format> for MaybeParenthesizeExpression<'_> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { let MaybeParenthesizeExpression { @@ -188,34 +227,9 @@ impl Format> for MaybeParenthesizeExpression<'_> { } = self; let comments = f.context().comments(); - let preserve_parentheses = parenthesize.is_optional() - && is_expression_parenthesized( - (*expression).into(), - f.context().comments().ranges(), - f.context().source(), - ); - let node_comments = comments.leading_dangling_trailing(*expression); - let has_comments = node_comments.has_leading() || node_comments.has_trailing_own_line(); - - // If the expression has comments, we always want to preserve the parentheses. This also - // ensures that we correctly handle parenthesized comments, and don't need to worry about - // them in the implementation below. - if preserve_parentheses || has_comments { - return expression.format().with_options(Parentheses::Always).fmt(f); - } - - let needs_parentheses = match expression.needs_parentheses(*parent, f.context()) { - OptionalParentheses::Always => OptionalParentheses::Always, - // The reason to add parentheses is to avoid a syntax error when breaking an expression over multiple lines. - // Therefore, it is unnecessary to add an additional pair of parentheses if an outer expression - // is parenthesized. - _ if f.context().node_level().is_parenthesized() => OptionalParentheses::Never, - needs_parentheses => needs_parentheses, - }; - - match needs_parentheses { + match self.needs_parentheses(f.context(), &node_comments) { OptionalParentheses::Multiline => match parenthesize { Parenthesize::IfBreaksOrIfRequired => { parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) @@ -342,7 +356,7 @@ impl<'ast> IntoFormat> for Expr { /// * The expression contains at least one parenthesized sub expression (optimization to avoid unnecessary work) /// /// This mimics Black's [`_maybe_split_omitting_optional_parens`](https://github.com/psf/black/blob/d1248ca9beaf0ba526d265f4108836d89cf551b7/src/black/linegen.py#L746-L820) -fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool { +pub(crate) fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool { let mut visitor = CanOmitOptionalParenthesesVisitor::new(context); visitor.visit_subexpression(expr); diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 005b3efa05..7f103a4e99 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -1,5 +1,5 @@ use ruff_formatter::prelude::tag::Condition; -use ruff_formatter::{format_args, write, Argument, Arguments}; +use ruff_formatter::{format_args, write, Argument, Arguments, GroupId}; use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::ExpressionRef; use ruff_python_trivia::CommentRanges; @@ -196,18 +196,29 @@ where { FormatOptionalParentheses { content: Argument::new(content), + group_id: None, } } pub(crate) struct FormatOptionalParentheses<'content, 'ast> { content: Argument<'content, PyFormatContext<'ast>>, + group_id: Option, +} + +impl FormatOptionalParentheses<'_, '_> { + pub(crate) fn with_group_id(mut self, group_id: GroupId) -> Self { + self.group_id = Some(group_id); + self + } } impl<'ast> Format> for FormatOptionalParentheses<'_, 'ast> { fn fmt(&self, f: &mut Formatter>) -> FormatResult<()> { // The group id is used as a condition in [`in_parentheses_only_group`] to create a // conditional group that is only active if the optional parentheses group expands. - let parens_id = f.group_id("optional_parentheses"); + let parens_id = self + .group_id + .unwrap_or_else(|| f.group_id("optional_parentheses")); let mut f = WithNodeLevel::new(NodeLevel::Expression(Some(parens_id)), f); diff --git a/crates/ruff_python_formatter/src/statement/stmt_assert.rs b/crates/ruff_python_formatter/src/statement/stmt_assert.rs index 7b3930d252..0f3e4907cc 100644 --- a/crates/ruff_python_formatter/src/statement/stmt_assert.rs +++ b/crates/ruff_python_formatter/src/statement/stmt_assert.rs @@ -1,12 +1,13 @@ -use ruff_formatter::prelude::{space, token}; -use ruff_formatter::write; -use ruff_python_ast::StmtAssert; +use ruff_formatter::{format_args, write}; +use ruff_python_ast::{Constant, Expr, ExprConstant, StmtAssert}; +use crate::builders::parenthesize_if_expands; use crate::comments::{SourceComment, SuppressionKind}; - -use crate::expression::maybe_parenthesize_expression; -use crate::expression::parentheses::Parenthesize; +use crate::context::{NodeLevel, WithNodeLevel}; +use crate::expression::parentheses::{OptionalParentheses, Parentheses, Parenthesize}; +use crate::expression::{can_omit_optional_parentheses, maybe_parenthesize_expression}; use crate::prelude::*; +use crate::FormatNodeRule; #[derive(Default)] pub struct FormatStmtAssert; @@ -19,14 +20,102 @@ impl FormatNodeRule for FormatStmtAssert { msg, } = item; - write!( - f, - [ - token("assert"), - space(), - maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks) - ] - )?; + write!(f, [token("assert"), space()])?; + + let parenthesize_test = maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks); + + if let Some( + msg @ (Expr::FString(_) + | Expr::Constant(ExprConstant { + value: Constant::Str(_) | Constant::Bytes(_), + .. + })), + ) = msg.as_deref() + { + let parenthesize_message = + maybe_parenthesize_expression(msg, item, Parenthesize::IfBreaks); + + let comments = f.context().comments(); + let test_comments = comments.leading_dangling_trailing(test.as_ref()); + let msg_comments = comments.leading_dangling_trailing(msg); + + // TODO limit to can omit parentheses and has own parentheses + if parenthesize_test.needs_parentheses(f.context(), &test_comments) + == OptionalParentheses::Multiline + && parenthesize_message.needs_parentheses(f.context(), &msg_comments) + == OptionalParentheses::BestFit + && can_omit_optional_parentheses(test, f.context()) + { + let test_group_id = f.group_id("optional_parentheses"); + + let mut format_test = test.format().with_options(Parentheses::Never).memoized(); + let mut format_msg = msg.format().with_options(Parentheses::Never).memoized(); + + let test_breaks = { + let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(test_group_id)), f); + format_test.inspect(f)?.will_break() + }; + + return if test_breaks || format_msg.inspect(f)?.will_break() { + todo!() + } else { + best_fitting![ + // --------------------------------------------------------------------- + // Variant 1: + // Try to fit both expressions without parentheses + format_args![ + group(&format_test).with_group_id(Some(test_group_id)), + token(","), + space(), + format_msg + ], + // --------------------------------------------------------------------- + // Variant 2: + // Try to parenthesize the string, but don't parenthesize the test just yet + format_args![ + group(&format_test).with_group_id(Some(test_group_id)), + token(","), + space(), + parenthesize_if_expands(&format_msg).should_expand(true) + ], + // --------------------------------------------------------------------- + // Variant 3: + // Try to parenthesize both test and message + format_args![ + parenthesize_if_expands(&format_test) + .with_group_id(test_group_id) + .should_expand(true), + token(","), + space(), + parenthesize_if_expands(&format_msg).should_expand(true) + ], + // --------------------------------------------------------------------- + // Variant 4: + // If it wasn't possible to make test and message fit by now, fallback to the first variant + // and omit any optional parentheses. + format_args![ + // Create an empty group that always fits. Necessary because the content + // of format_test might refer the group id. + format_with(|f| { + f.write_element(FormatElement::GroupMode { + id: test_group_id, + mode: PrintMode::Flat, + }); + Ok(()) + }), + format_test, + token(","), + space(), + format_msg + ], + ] + .with_mode(BestFittingMode::AllLines) + .fmt(f) + }; + } + } + + maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks).fmt(f)?; if let Some(msg) = msg { write!( diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap index fbda66e07b..e2a6649640 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition.py.snap @@ -193,41 +193,7 @@ class C: ```diff --- Black +++ Ruff -@@ -110,19 +110,20 @@ - value, is_going_to_be="too long to fit in a single line", srsly=True - ), "Not what we expected" - -- assert { -- key1: value1, -- key2: value2, -- key3: value3, -- key4: value4, -- key5: value5, -- key6: value6, -- key7: value7, -- key8: value8, -- key9: value9, -- } == expected, ( -- "Not what we expected and the message is too long to fit in one line" -- ) -+ assert ( -+ { -+ key1: value1, -+ key2: value2, -+ key3: value3, -+ key4: value4, -+ key5: value5, -+ key6: value6, -+ key7: value7, -+ key8: value8, -+ key9: value9, -+ } -+ == expected -+ ), "Not what we expected and the message is too long to fit in one line" - - assert expected( - value, is_going_to_be="too long to fit in a single line", srsly=True -@@ -161,9 +162,7 @@ +@@ -161,9 +161,7 @@ 8 STORE_ATTR 0 (x) 10 LOAD_CONST 0 (None) 12 RETURN_VALUE @@ -355,20 +321,19 @@ class C: value, is_going_to_be="too long to fit in a single line", srsly=True ), "Not what we expected" - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expected - ), "Not what we expected and the message is too long to fit in one line" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expected, ( + "Not what we expected and the message is too long to fit in one line" + ) assert expected( value, is_going_to_be="too long to fit in a single line", srsly=True diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap index 06bcb6b4e7..5dff4c325e 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__composition_no_trailing_comma.py.snap @@ -193,41 +193,7 @@ class C: ```diff --- Black +++ Ruff -@@ -110,19 +110,20 @@ - value, is_going_to_be="too long to fit in a single line", srsly=True - ), "Not what we expected" - -- assert { -- key1: value1, -- key2: value2, -- key3: value3, -- key4: value4, -- key5: value5, -- key6: value6, -- key7: value7, -- key8: value8, -- key9: value9, -- } == expected, ( -- "Not what we expected and the message is too long to fit in one line" -- ) -+ assert ( -+ { -+ key1: value1, -+ key2: value2, -+ key3: value3, -+ key4: value4, -+ key5: value5, -+ key6: value6, -+ key7: value7, -+ key8: value8, -+ key9: value9, -+ } -+ == expected -+ ), "Not what we expected and the message is too long to fit in one line" - - assert expected( - value, is_going_to_be="too long to fit in a single line", srsly=True -@@ -161,9 +162,7 @@ +@@ -161,9 +161,7 @@ 8 STORE_ATTR 0 (x) 10 LOAD_CONST 0 (None) 12 RETURN_VALUE @@ -355,20 +321,19 @@ class C: value, is_going_to_be="too long to fit in a single line", srsly=True ), "Not what we expected" - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expected - ), "Not what we expected and the message is too long to fit in one line" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expected, ( + "Not what we expected and the message is too long to fit in one line" + ) assert expected( value, is_going_to_be="too long to fit in a single line", srsly=True diff --git a/crates/ruff_python_formatter/tests/snapshots/format@statement__assert.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@statement__assert.py.snap index 8f502dfe0a..896515bed6 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@statement__assert.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@statement__assert.py.snap @@ -211,80 +211,69 @@ assert ( def test(): - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expected - ), "Not what we expected and the message is too long to fit ineeeeee one line" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expected, ( + "Not what we expected and the message is too long to fit ineeeeee one line" + ) - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expected - ), "Not what we expected and the message is too long to fit in one lineeeee" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expected, ( + "Not what we expected and the message is too long to fit in one lineeeee" + ) - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expected - ), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeee" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expected, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeee" - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee - ), "Not what we expected and the message is too long to fit in one lin" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, "Not what we expected and the message is too long to fit in one lin" - assert ( - { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - == expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee - ), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeee" + assert { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + } == expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeee" assert expected == { key1: value1, @@ -298,20 +287,17 @@ def test(): key9: value9, }, "Not what we expected and the message is too long to fit ineeeeee one line" - assert ( - expected - == { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - ), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeeeeee" + assert expected == { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + }, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeeeeee" assert ( expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee @@ -326,22 +312,21 @@ def test(): key8: value8, key9: value9, } - ), "Not what we expected and the message is too long to fit in one lin" + ), ( + "Not what we expected and the message is too long to fit in one lin" + ) - assert ( - expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee - == { - key1: value1, - key2: value2, - key3: value3, - key4: value4, - key5: value5, - key6: value6, - key7: value7, - key8: value8, - key9: value9, - } - ), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeee" + assert expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee == { + key1: value1, + key2: value2, + key3: value3, + key4: value4, + key5: value5, + key6: value6, + key7: value7, + key8: value8, + key9: value9, + }, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeee" # Test for https://github.com/astral-sh/ruff/issues/7246