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"),
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(), space(),
maybe_parenthesize_expression(test, item, Parenthesize::IfBreaks) 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,8 +321,7 @@ 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,
@ -366,9 +331,9 @@ class C:
key7: value7, key7: value7,
key8: value8, key8: value8,
key9: value9, key9: value9,
} } == expected, (
== expected "Not what we expected and the message is too long to fit in one line"
), "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,8 +321,7 @@ 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,
@ -366,9 +331,9 @@ class C:
key7: value7, key7: value7,
key8: value8, key8: value8,
key9: value9, key9: value9,
} } == expected, (
== expected "Not what we expected and the message is too long to fit in one line"
), "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,8 +211,7 @@ assert (
def test(): def test():
assert ( assert {
{
key1: value1, key1: value1,
key2: value2, key2: value2,
key3: value3, key3: value3,
@ -222,12 +221,11 @@ def test():
key7: value7, key7: value7,
key8: value8, key8: value8,
key9: value9, key9: value9,
} } == expected, (
== expected "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 {
{
key1: value1, key1: value1,
key2: value2, key2: value2,
key3: value3, key3: value3,
@ -237,12 +235,11 @@ def test():
key7: value7, key7: value7,
key8: value8, key8: value8,
key9: value9, key9: value9,
} } == expected, (
== expected "Not what we expected and the message is too long to fit in one lineeeee"
), "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,
@ -252,12 +249,9 @@ def test():
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,
@ -267,12 +261,9 @@ def test():
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,
@ -282,9 +273,7 @@ def test():
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,9 +287,7 @@ 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, key1: value1,
key2: value2, key2: value2,
key3: value3, key3: value3,
@ -310,8 +297,7 @@ def test():
key7: value7, key7: value7,
key8: value8, key8: value8,
key9: value9, key9: value9,
} }, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeeeeee"
), "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeeeeeeee"
assert ( assert (
expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee expectedeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
@ -326,11 +312,11 @@ 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, key1: value1,
key2: value2, key2: value2,
key3: value3, key3: value3,
@ -340,8 +326,7 @@ def test():
key7: value7, key7: value7,
key8: value8, key8: value8,
key9: value9, key9: value9,
} }, "Not what we expected and the message is too long to fit in one lineeeeeeeeeeeeeee"
), "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