POC of assert formatting

This commit is contained in:
Micha Reiser 2023-08-24 19:33:55 +02:00
parent 86bc5394f1
commit d1a76d0011
No known key found for this signature in database
10 changed files with 323 additions and 245 deletions

View File

@ -11,7 +11,7 @@ use unicode_width::UnicodeWidthChar;
use crate::format_element::tag::{GroupMode, LabelId, Tag}; use crate::format_element::tag::{GroupMode, LabelId, Tag};
use crate::source_code::SourceCodeSlice; use crate::source_code::SourceCodeSlice;
use crate::{IndentWidth, TagKind}; use crate::{GroupId, IndentWidth, TagKind};
use ruff_text_size::TextSize; use ruff_text_size::TextSize;
/// Language agnostic IR for formatting source code. /// Language agnostic IR for formatting source code.
@ -34,7 +34,9 @@ pub enum FormatElement {
SourcePosition(TextSize), SourcePosition(TextSize),
/// A ASCII only Token that contains no line breaks or tab characters. /// 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. /// An arbitrary text that can contain tabs, newlines, and unicode characters.
Text { 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`. /// deep cloning the IR when using the `best_fitting!` macro or `if_group_fits_on_line` and `if_group_breaks`.
Interned(Interned), Interned(Interned),
GroupMode {
id: GroupId,
mode: PrintMode,
},
/// A list of different variants representing the same content. The printer picks the best fitting content. /// 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. /// Line breaks inside of a best fitting don't propagate to parent groups.
BestFitting { BestFitting {
@ -97,6 +104,9 @@ impl std::fmt::Debug for FormatElement {
.field("variants", variants) .field("variants", variants)
.field("mode", &mode) .field("mode", &mode)
.finish(), .finish(),
FormatElement::GroupMode { id, mode } => {
fmt.debug_tuple("GroupMode").field(id).field(mode).finish()
}
FormatElement::Interned(interned) => fmt.debug_list().entries(&**interned).finish(), FormatElement::Interned(interned) => fmt.debug_list().entries(&**interned).finish(),
FormatElement::Tag(tag) => fmt.debug_tuple("Tag").field(tag).finish(), FormatElement::Tag(tag) => fmt.debug_tuple("Tag").field(tag).finish(),
FormatElement::SourcePosition(position) => { FormatElement::SourcePosition(position) => {
@ -277,6 +287,7 @@ impl FormatElements for FormatElement {
FormatElement::LineSuffixBoundary FormatElement::LineSuffixBoundary
| FormatElement::Space | FormatElement::Space
| FormatElement::Tag(_) | FormatElement::Tag(_)
| FormatElement::GroupMode { .. }
| FormatElement::Token { .. } | FormatElement::Token { .. }
| FormatElement::SourcePosition(_) => false, | FormatElement::SourcePosition(_) => false,
} }

View File

@ -381,6 +381,17 @@ impl Format<IrFormatContext<'_>> for &[FormatElement] {
write!(f, [token("])")])?; 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) => { FormatElement::Interned(interned) => {
let interned_elements = &mut f.context_mut().printed_interned_elements; let interned_elements = &mut f.context_mut().printed_interned_elements;

View File

@ -141,6 +141,10 @@ impl<'a> Printer<'a> {
// Handled in `Document::propagate_expands() // Handled in `Document::propagate_expands()
} }
FormatElement::GroupMode { id, mode } => {
self.state.group_modes.insert_print_mode(*id, *mode);
}
FormatElement::SourcePosition(position) => { FormatElement::SourcePosition(position) => {
self.state.source_position = *position; self.state.source_position = *position;
self.push_marker(); 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 => { FormatElement::ExpandParent => {
if self.must_be_flat { if self.must_be_flat {
return Ok(Fits::No); return Ok(Fits::No);

View File

@ -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 ruff_text_size::{Ranged, TextRange, TextSize};
use crate::context::{NodeLevel, WithNodeLevel}; use crate::context::{NodeLevel, WithNodeLevel};
@ -12,11 +12,28 @@ where
{ {
ParenthesizeIfExpands { ParenthesizeIfExpands {
inner: Argument::new(content), inner: Argument::new(content),
group_id: None,
should_expand: false,
} }
} }
pub(crate) struct ParenthesizeIfExpands<'a, 'ast> { pub(crate) struct ParenthesizeIfExpands<'a, 'ast> {
inner: Argument<'a, PyFormatContext<'ast>>, inner: Argument<'a, PyFormatContext<'ast>>,
group_id: Option<GroupId>,
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<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> { impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> {
@ -30,7 +47,9 @@ impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> {
if_group_breaks(&token("(")), if_group_breaks(&token("(")),
soft_block_indent(&Arguments::from(&self.inner)), soft_block_indent(&Arguments::from(&self.inner)),
if_group_breaks(&token(")")), if_group_breaks(&token(")")),
])] ])
.with_group_id(self.group_id)
.should_expand(self.should_expand)]
) )
} }
} }

View File

@ -12,7 +12,7 @@ use ruff_python_ast::{Constant, Expr, ExpressionRef, Operator};
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
use crate::builders::parenthesize_if_expands; use crate::builders::parenthesize_if_expands;
use crate::comments::leading_comments; use crate::comments::{leading_comments, LeadingDanglingTrailingComments};
use crate::context::{NodeLevel, WithNodeLevel}; use crate::context::{NodeLevel, WithNodeLevel};
use crate::expression::parentheses::{ use crate::expression::parentheses::{
is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses, is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses,
@ -179,6 +179,45 @@ pub(crate) struct MaybeParenthesizeExpression<'a> {
parenthesize: Parenthesize, 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<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> { impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> { fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
let MaybeParenthesizeExpression { let MaybeParenthesizeExpression {
@ -188,34 +227,9 @@ impl Format<PyFormatContext<'_>> for MaybeParenthesizeExpression<'_> {
} = self; } = self;
let comments = f.context().comments(); 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 node_comments = comments.leading_dangling_trailing(*expression);
let has_comments = node_comments.has_leading() || node_comments.has_trailing_own_line(); match self.needs_parentheses(f.context(), &node_comments) {
// 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 {
OptionalParentheses::Multiline => match parenthesize { OptionalParentheses::Multiline => match parenthesize {
Parenthesize::IfBreaksOrIfRequired => { Parenthesize::IfBreaksOrIfRequired => {
parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) parenthesize_if_expands(&expression.format().with_options(Parentheses::Never))
@ -342,7 +356,7 @@ impl<'ast> IntoFormat<PyFormatContext<'ast>> for Expr {
/// * The expression contains at least one parenthesized sub expression (optimization to avoid unnecessary work) /// * 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) /// 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); let mut visitor = CanOmitOptionalParenthesesVisitor::new(context);
visitor.visit_subexpression(expr); visitor.visit_subexpression(expr);

View File

@ -1,5 +1,5 @@
use ruff_formatter::prelude::tag::Condition; 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::node::AnyNodeRef;
use ruff_python_ast::ExpressionRef; use ruff_python_ast::ExpressionRef;
use ruff_python_trivia::CommentRanges; use ruff_python_trivia::CommentRanges;
@ -196,18 +196,29 @@ where
{ {
FormatOptionalParentheses { FormatOptionalParentheses {
content: Argument::new(content), content: Argument::new(content),
group_id: None,
} }
} }
pub(crate) struct FormatOptionalParentheses<'content, 'ast> { pub(crate) struct FormatOptionalParentheses<'content, 'ast> {
content: Argument<'content, PyFormatContext<'ast>>, content: Argument<'content, PyFormatContext<'ast>>,
group_id: Option<GroupId>,
}
impl FormatOptionalParentheses<'_, '_> {
pub(crate) fn with_group_id(mut self, group_id: GroupId) -> Self {
self.group_id = Some(group_id);
self
}
} }
impl<'ast> Format<PyFormatContext<'ast>> for FormatOptionalParentheses<'_, 'ast> { impl<'ast> Format<PyFormatContext<'ast>> for FormatOptionalParentheses<'_, 'ast> {
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> { fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
// The group id is used as a condition in [`in_parentheses_only_group`] to create a // 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. // 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); let mut f = WithNodeLevel::new(NodeLevel::Expression(Some(parens_id)), f);

View File

@ -1,12 +1,13 @@
use ruff_formatter::prelude::{space, token}; use ruff_formatter::{format_args, write};
use ruff_formatter::write; use ruff_python_ast::{Constant, Expr, ExprConstant, StmtAssert};
use ruff_python_ast::StmtAssert;
use crate::builders::parenthesize_if_expands;
use crate::comments::{SourceComment, SuppressionKind}; use crate::comments::{SourceComment, SuppressionKind};
use crate::context::{NodeLevel, WithNodeLevel};
use crate::expression::maybe_parenthesize_expression; use crate::expression::parentheses::{OptionalParentheses, Parentheses, Parenthesize};
use crate::expression::parentheses::Parenthesize; use crate::expression::{can_omit_optional_parentheses, maybe_parenthesize_expression};
use crate::prelude::*; use crate::prelude::*;
use crate::FormatNodeRule;
#[derive(Default)] #[derive(Default)]
pub struct FormatStmtAssert; pub struct FormatStmtAssert;
@ -19,14 +20,102 @@ impl FormatNodeRule<StmtAssert> for FormatStmtAssert {
msg, msg,
} = item; } = item;
write!( write!(f, [token("assert"), space()])?;
f,
[ let parenthesize_test = maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks);
token("assert"),
space(), if let Some(
maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks) 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 { if let Some(msg) = msg {
write!( write!(

View File

@ -193,41 +193,7 @@ class C:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -110,19 +110,20 @@ @@ -161,9 +161,7 @@
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 @@
8 STORE_ATTR 0 (x) 8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None) 10 LOAD_CONST 0 (None)
12 RETURN_VALUE 12 RETURN_VALUE
@ -355,20 +321,19 @@ class C:
value, is_going_to_be="too long to fit in a single line", srsly=True value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected" ), "Not what we expected"
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expected, (
} "Not what we expected and the message is too long to fit in one line"
== expected )
), "Not what we expected and the message is too long to fit in one line"
assert expected( assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True value, is_going_to_be="too long to fit in a single line", srsly=True

View File

@ -193,41 +193,7 @@ class C:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -110,19 +110,20 @@ @@ -161,9 +161,7 @@
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 @@
8 STORE_ATTR 0 (x) 8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None) 10 LOAD_CONST 0 (None)
12 RETURN_VALUE 12 RETURN_VALUE
@ -355,20 +321,19 @@ class C:
value, is_going_to_be="too long to fit in a single line", srsly=True value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected" ), "Not what we expected"
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expected, (
} "Not what we expected and the message is too long to fit in one line"
== expected )
), "Not what we expected and the message is too long to fit in one line"
assert expected( assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True value, is_going_to_be="too long to fit in a single line", srsly=True

View File

@ -211,80 +211,69 @@ assert (
def test(): def test():
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expected, (
} "Not what we expected and the message is too long to fit ineeeeee one line"
== expected )
), "Not what we expected and the message is too long to fit ineeeeee one line"
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expected, (
} "Not what we expected and the message is too long to fit in one lineeeee"
== expected )
), "Not what we expected and the message is too long to fit in one lineeeee"
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expected, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeee"
}
== expected
), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeee"
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, "Not what we expected and the message is too long to fit in one lin"
}
== expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
), "Not what we expected and the message is too long to fit in one lin"
assert ( assert {
{ key1: value1,
key1: value1, key2: value2,
key2: value2, key3: value3,
key3: value3, key4: value4,
key4: value4, key5: value5,
key5: value5, key6: value6,
key6: value6, key7: value7,
key7: value7, key8: value8,
key8: value8, key9: value9,
key9: value9, } == expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeee"
}
== expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeee"
assert expected == { assert expected == {
key1: value1, key1: value1,
@ -298,20 +287,17 @@ def test():
key9: value9, key9: value9,
}, "Not what we expected and the message is too long to fit ineeeeee one line" }, "Not what we expected and the message is too long to fit ineeeeee one line"
assert ( assert expected == {
expected key1: value1,
== { key2: value2,
key1: value1, key3: value3,
key2: value2, key4: value4,
key3: value3, key5: value5,
key4: value4, key6: value6,
key5: value5, key7: value7,
key6: value6, key8: value8,
key7: value7, key9: value9,
key8: value8, }, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeeeeee"
key9: value9,
}
), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeeeeee"
assert ( assert (
expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
@ -326,22 +312,21 @@ def test():
key8: value8, key8: value8,
key9: value9, 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 ( assert expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee == {
expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee key1: value1,
== { key2: value2,
key1: value1, key3: value3,
key2: value2, key4: value4,
key3: value3, key5: value5,
key4: value4, key6: value6,
key5: value5, key7: value7,
key6: value6, key8: value8,
key7: value7, key9: value9,
key8: value8, }, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeee"
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 # Test for https://github.com/astral-sh/ruff/issues/7246