From aa7e59b7b08a996cf1631e00fc261d559f23f5d3 Mon Sep 17 00:00:00 2001 From: Micha Reiser Date: Wed, 23 Aug 2023 11:22:14 +0200 Subject: [PATCH] Maybe parenthesize long constants and names --- crates/ruff_formatter/src/builders.rs | 4 +- .../src/format_element/document.rs | 8 +- .../test/fixtures/ruff/expression/unary.py | 6 + .../fixtures/ruff/expression/unspittable.py | 54 ++++++++ .../src/expression/expr_call.rs | 5 +- .../src/expression/expr_constant.rs | 12 +- .../src/expression/expr_name.rs | 11 +- .../src/expression/expr_subscript.rs | 5 +- .../src/expression/expr_unary_op.rs | 4 +- .../src/expression/mod.rs | 37 ++++- .../src/expression/parentheses.rs | 10 +- crates/ruff_python_formatter/src/lib.rs | 17 ++- ...bility@simple_cases__remove_parens.py.snap | 26 +--- ...__trailing_commas_in_leading_parts.py.snap | 12 +- .../format@expression__unary.py.snap | 13 ++ .../format@expression__unspittable.py.snap | 126 ++++++++++++++++++ 16 files changed, 296 insertions(+), 54 deletions(-) create mode 100644 crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unspittable.py create mode 100644 crates/ruff_python_formatter/tests/snapshots/format@expression__unspittable.py.snap diff --git a/crates/ruff_formatter/src/builders.rs b/crates/ruff_formatter/src/builders.rs index 1e66f0b6214ee4..881a80e557cd6a 100644 --- a/crates/ruff_formatter/src/builders.rs +++ b/crates/ruff_formatter/src/builders.rs @@ -2534,17 +2534,17 @@ impl<'a, Context> BestFitting<'a, Context> { impl Format for BestFitting<'_, Context> { fn fmt(&self, f: &mut Formatter) -> FormatResult<()> { - let mut buffer = VecBuffer::new(f.state_mut()); let variants = self.variants.items(); let mut formatted_variants = Vec::with_capacity(variants.len()); for variant in variants { + let mut buffer = VecBuffer::with_capacity(8, f.state_mut()); buffer.write_element(FormatElement::Tag(StartEntry)); buffer.write_fmt(Arguments::from(variant))?; buffer.write_element(FormatElement::Tag(EndEntry)); - formatted_variants.push(buffer.take_vec().into_boxed_slice()); + formatted_variants.push(buffer.into_vec().into_boxed_slice()); } // SAFETY: The constructor guarantees that there are always at least two variants. It's, therefore, diff --git a/crates/ruff_formatter/src/format_element/document.rs b/crates/ruff_formatter/src/format_element/document.rs index 5fa0e0af48c15e..159a667d19c0be 100644 --- a/crates/ruff_formatter/src/format_element/document.rs +++ b/crates/ruff_formatter/src/format_element/document.rs @@ -122,8 +122,12 @@ impl Document { expands } - let mut enclosing: Vec = Vec::new(); - let mut interned: FxHashMap<&Interned, bool> = FxHashMap::default(); + let mut enclosing = Vec::with_capacity(if self.is_empty() { + 0 + } else { + self.len().ilog2() as usize + }); + let mut interned = FxHashMap::default(); propagate_expands(self, &mut enclosing, &mut interned); } diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py index 11106d7d2396a9..9b08dc9baaa36b 100644 --- a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unary.py @@ -140,3 +140,9 @@ # Regression: https://github.com/astral-sh/ruff/issues/5338 if a and not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... + +if ( + not + # comment + a): + ... diff --git a/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unspittable.py b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unspittable.py new file mode 100644 index 00000000000000..83a1158ec32aed --- /dev/null +++ b/crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unspittable.py @@ -0,0 +1,54 @@ +x = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +x_aa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +xxxxx = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +while ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + pass + +while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + pass + +# Only applies in `Parenthesize::IfBreaks` positions +raise aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +raise ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +) + +raise a from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +raise a from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# Can never apply on expression statement level +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# Is it only relevant for items that can't break + +aaaaaaa = 111111111111111111111111111111111111111111111111111111111111111111111111111111 +aaaaaaa = ( + 1111111111111111111111111111111111111111111111111111111111111111111111111111111 +) + +aaaaaaa = """111111111111111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111""" + +# Never parenthesize multiline strings +aaaaaaa = ( + """1111111111111111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111""" +) + + + +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + + +for converter in connection.ops.get_db_converters( + expression +) + expression.get_db_converters(connection): + ... diff --git a/crates/ruff_python_formatter/src/expression/expr_call.rs b/crates/ruff_python_formatter/src/expression/expr_call.rs index 5483aabdcaee8b..c517f2ce8585cd 100644 --- a/crates/ruff_python_formatter/src/expression/expr_call.rs +++ b/crates/ruff_python_formatter/src/expression/expr_call.rs @@ -69,7 +69,10 @@ impl NeedsParentheses for ExprCall { { OptionalParentheses::Multiline } else { - self.func.needs_parentheses(self.into(), context) + match self.func.needs_parentheses(self.into(), context) { + OptionalParentheses::IfFits => OptionalParentheses::Never, + parentheses => parentheses, + } } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_constant.rs b/crates/ruff_python_formatter/src/expression/expr_constant.rs index 64cfb8cd4c20e6..178260680c358d 100644 --- a/crates/ruff_python_formatter/src/expression/expr_constant.rs +++ b/crates/ruff_python_formatter/src/expression/expr_constant.rs @@ -1,5 +1,5 @@ use crate::comments::SourceComment; -use ruff_formatter::FormatRuleWithOptions; +use ruff_formatter::{FormatContext, FormatOptions, FormatRuleWithOptions}; use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::{Constant, ExprConstant, Ranged}; use ruff_text_size::{TextLen, TextRange}; @@ -86,8 +86,16 @@ impl NeedsParentheses for ExprConstant { } else { OptionalParentheses::Multiline } - } else { + } else if self.value.is_none() | self.value.is_bool() || self.value.is_ellipsis() { OptionalParentheses::Never + } else { + let text_len = context.source()[self.range].len(); + + if text_len > 4 && text_len < context.options().line_width().value() as usize { + OptionalParentheses::IfFits + } else { + OptionalParentheses::Never + } } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_name.rs b/crates/ruff_python_formatter/src/expression/expr_name.rs index a2aef805935446..bc6627c267e76f 100644 --- a/crates/ruff_python_formatter/src/expression/expr_name.rs +++ b/crates/ruff_python_formatter/src/expression/expr_name.rs @@ -2,7 +2,7 @@ use crate::comments::SourceComment; use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; use crate::prelude::*; use crate::FormatNodeRule; -use ruff_formatter::{write, FormatContext}; +use ruff_formatter::{write, FormatContext, FormatOptions}; use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::ExprName; @@ -38,9 +38,14 @@ impl NeedsParentheses for ExprName { fn needs_parentheses( &self, _parent: AnyNodeRef, - _context: &PyFormatContext, + context: &PyFormatContext, ) -> OptionalParentheses { - OptionalParentheses::Never + let text_len = context.source()[self.range].len(); + if text_len > 4 && text_len < context.options().line_width().value() as usize { + OptionalParentheses::IfFits + } else { + OptionalParentheses::Never + } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_subscript.rs b/crates/ruff_python_formatter/src/expression/expr_subscript.rs index 90c1d5c32d3cf9..747df92c889b7a 100644 --- a/crates/ruff_python_formatter/src/expression/expr_subscript.rs +++ b/crates/ruff_python_formatter/src/expression/expr_subscript.rs @@ -101,7 +101,10 @@ impl NeedsParentheses for ExprSubscript { { OptionalParentheses::Multiline } else { - self.value.needs_parentheses(self.into(), context) + match self.value.needs_parentheses(self.into(), context) { + OptionalParentheses::IfFits => OptionalParentheses::Never, + parentheses => parentheses, + } } } } diff --git a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs index 7523edc77728ad..971f7a2d09d465 100644 --- a/crates/ruff_python_formatter/src/expression/expr_unary_op.rs +++ b/crates/ruff_python_formatter/src/expression/expr_unary_op.rs @@ -3,7 +3,7 @@ use ruff_python_ast::{ExprUnaryOp, Ranged}; use ruff_text_size::{TextLen, TextRange}; use ruff_formatter::prelude::{hard_line_break, space, text}; -use ruff_formatter::{Format, FormatContext, FormatResult}; +use ruff_formatter::{Format, FormatResult}; use ruff_python_ast::node::AnyNodeRef; use ruff_python_trivia::{SimpleTokenKind, SimpleTokenizer}; @@ -57,7 +57,7 @@ impl FormatNodeRule for FormatExprUnaryOp { // a) // ``` if !leading_operand_comments.is_empty() - && !is_operand_parenthesized(item, f.context().source_code().as_str()) + && !is_operand_parenthesized(item, f.context().source()) { hard_line_break().fmt(f)?; } else if op.is_not() { diff --git a/crates/ruff_python_formatter/src/expression/mod.rs b/crates/ruff_python_formatter/src/expression/mod.rs index 75dce1be2296dc..2845940e2bec6b 100644 --- a/crates/ruff_python_formatter/src/expression/mod.rs +++ b/crates/ruff_python_formatter/src/expression/mod.rs @@ -1,7 +1,7 @@ use std::cmp::Ordering; use ruff_formatter::{ - write, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions, + format_args, write, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions, }; use ruff_python_ast as ast; use ruff_python_ast::node::AnyNodeRef; @@ -220,6 +220,40 @@ impl Format> for MaybeParenthesizeExpression<'_> { } } }, + OptionalParentheses::IfFits => match parenthesize { + Parenthesize::IfBreaksOrIfRequired => { + parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) + .fmt(f) + } + + Parenthesize::Optional | Parenthesize::IfRequired => { + expression.format().with_options(Parentheses::Never).fmt(f) + } + Parenthesize::IfBreaks => { + let group_id = f.group_id("optional_parentheses"); + let f = &mut WithNodeLevel::new(NodeLevel::Expression(Some(group_id)), f); + let format_expression = expression + .format() + .with_options(Parentheses::Never) + .memoized(); + + best_fitting![ + group(&format_expression).with_group_id(Some(group_id)), + group(&format_args![ + text("("), + soft_block_indent(&format_expression), + text(")") + ]) + .with_group_id(Some(group_id)) + .should_expand(true), + group(&format_expression) + .with_group_id(Some(group_id)) + .should_expand(true) + ] + .with_mode(BestFittingMode::AllLines) + .fmt(f) + } + }, OptionalParentheses::Never => match parenthesize { Parenthesize::IfBreaksOrIfRequired => { parenthesize_if_expands(&expression.format().with_options(Parentheses::Never)) @@ -230,6 +264,7 @@ impl Format> for MaybeParenthesizeExpression<'_> { expression.format().with_options(Parentheses::Never).fmt(f) } }, + OptionalParentheses::Always => { expression.format().with_options(Parentheses::Always).fmt(f) } diff --git a/crates/ruff_python_formatter/src/expression/parentheses.rs b/crates/ruff_python_formatter/src/expression/parentheses.rs index 748583ae0cc8a2..32cf48ff10583a 100644 --- a/crates/ruff_python_formatter/src/expression/parentheses.rs +++ b/crates/ruff_python_formatter/src/expression/parentheses.rs @@ -15,11 +15,16 @@ pub(crate) enum OptionalParentheses { /// Add parentheses if the expression expands over multiple lines Multiline, - /// Always set parentheses regardless if the expression breaks or if they were + /// Always set parentheses regardless if the expression breaks or if they are /// present in the source. Always, - /// Never add parentheses + /// Add parentheses if it helps to make this expression fit. Otherwise never add parentheses. + /// This mode should only be used for expressions that don't have their own split points, e.g. identifiers, + /// or constants. + IfFits, + + /// Never add parentheses. Use it for expressions that have their own parentheses or if the expression body always spans multiple lines (multiline strings). Never, } @@ -48,6 +53,7 @@ pub(crate) enum Parenthesize { /// Parenthesizes the expression if the group doesn't fit on a line (e.g., even name expressions are parenthesized), or if /// the expression doesn't break, but _does_ reports that it always requires parentheses in this position (e.g., walrus /// operators in function return annotations). + // TODO can this be replaced by IfBreaks IfBreaksOrIfRequired, } diff --git a/crates/ruff_python_formatter/src/lib.rs b/crates/ruff_python_formatter/src/lib.rs index 39ac5ed30dda55..4303eac0d8f067 100644 --- a/crates/ruff_python_formatter/src/lib.rs +++ b/crates/ruff_python_formatter/src/lib.rs @@ -249,12 +249,10 @@ if True: #[test] fn quick_test() { let src = r#" -@MyDecorator(list = a) # fmt: skip -# trailing comment -class Test: - pass - - +for converter in connection.ops.get_db_converters( + expression +) + expression.get_db_converters(connection): + ... "#; // Tokenize once let mut tokens = Vec::new(); @@ -291,9 +289,10 @@ class Test: assert_eq!( printed.as_code(), - r#"while True: - if something.changed: - do.stuff() # trailing comment + r#"for converter in connection.ops.get_db_converters( + expression +) + expression.get_db_converters(connection): + ... "# ); } diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_parens.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_parens.py.snap index 9cb91d4c09e58f..21523115af4493 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_parens.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__remove_parens.py.snap @@ -80,24 +80,6 @@ def example8(): except Exception as e: pass -@@ -30,15 +32,11 @@ - - - def example2(): -- return ( -- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -- ) -+ return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - - - def example3(): -- return ( -- 1111111111111111111111111111111111111111111111111111111111111111111111111111111 -- ) -+ return 1111111111111111111111111111111111111111111111111111111111111111111111111111111 - - - def example4(): ``` ## Ruff Output @@ -137,11 +119,15 @@ def example1point5(): def example2(): - return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + return ( + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + ) def example3(): - return 1111111111111111111111111111111111111111111111111111111111111111111111111111111 + return ( + 1111111111111111111111111111111111111111111111111111111111111111111111111111111 + ) def example4(): diff --git a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap index 6a978187fcc969..3abf27d802c1b1 100644 --- a/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/black_compatibility@simple_cases__trailing_commas_in_leading_parts.py.snap @@ -56,14 +56,6 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( # Example from https://github.com/psf/black/issues/3229 -@@ -45,6 +43,4 @@ - # Regression test for https://github.com/psf/black/issues/3414. - assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( - xxxxxxxxx --).xxxxxxxxxxxxxxxxxx(), ( -- "xxx {xxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --) -+).xxxxxxxxxxxxxxxxxx(), "xxx {xxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" ``` ## Ruff Output @@ -114,7 +106,9 @@ assert ( # Regression test for https://github.com/psf/black/issues/3414. assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( xxxxxxxxx -).xxxxxxxxxxxxxxxxxx(), "xxx {xxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +).xxxxxxxxxxxxxxxxxx(), ( + "xxx {xxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +) ``` ## Black Output diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__unary.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__unary.py.snap index e0325c897bd0b3..b9d8bd127e2c2f 100644 --- a/crates/ruff_python_formatter/tests/snapshots/format@expression__unary.py.snap +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__unary.py.snap @@ -146,6 +146,12 @@ if not \ # Regression: https://github.com/astral-sh/ruff/issues/5338 if a and not aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: ... + +if ( + not + # comment + a): + ... ``` ## Output @@ -304,6 +310,13 @@ if ( & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ): ... + +if ( + not + # comment + a +): + ... ``` diff --git a/crates/ruff_python_formatter/tests/snapshots/format@expression__unspittable.py.snap b/crates/ruff_python_formatter/tests/snapshots/format@expression__unspittable.py.snap new file mode 100644 index 00000000000000..8d9fb5b06e18aa --- /dev/null +++ b/crates/ruff_python_formatter/tests/snapshots/format@expression__unspittable.py.snap @@ -0,0 +1,126 @@ +--- +source: crates/ruff_python_formatter/tests/fixtures.rs +input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/unspittable.py +--- +## Input +```py +x = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +x_aa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +xxxxx = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +while ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + pass + +while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + pass + +# Only applies in `Parenthesize::IfBreaks` positions +raise aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +raise ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +) + +raise a from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +raise a from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# Can never apply on expression statement level +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# Is it only relevant for items that can't break + +aaaaaaa = 111111111111111111111111111111111111111111111111111111111111111111111111111111 +aaaaaaa = ( + 1111111111111111111111111111111111111111111111111111111111111111111111111111111 +) + +aaaaaaa = """111111111111111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111""" + +# Never parenthesize multiline strings +aaaaaaa = ( + """1111111111111111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111""" +) + + + +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + + +for converter in connection.ops.get_db_converters( + expression +) + expression.get_db_converters(connection): + ... +``` + +## Output +```py +x = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +x_aa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +xxxxx = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +) + +while ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +): + pass + +while aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: + pass + +# Only applies in `Parenthesize::IfBreaks` positions +raise aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +raise ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +) + +raise a from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +raise a from aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# Can never apply on expression statement level +aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + +# Is it only relevant for items that can't break + +aaaaaaa = 111111111111111111111111111111111111111111111111111111111111111111111111111111 +aaaaaaa = ( + 1111111111111111111111111111111111111111111111111111111111111111111111111111111 +) + +aaaaaaa = """111111111111111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111""" + +# Never parenthesize multiline strings +aaaaaaa = """1111111111111111111111111111111111111111111111111111111111111111111111111111 +1111111111111111111111111111111111111111111111111111111111111111111111111111111111111""" + + +aaaaaaaa = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbb +aaaaaaaa = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) + +aaaaaaaa = ( + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb +) + + +for converter in connection.ops.get_db_converters( + expression +) + expression.get_db_converters(connection): + ... +``` + + +