From 06a693545bb06f9c9fe37a0b956020c6780fd712 Mon Sep 17 00:00:00 2001 From: Eljees <3.14hell@gmail.com> Date: Fri, 25 Sep 2026 10:56:30 +0300 Subject: [PATCH] Fix list formatting forcing a split before short function-call elements MustSplit() forced a break before any function-call element in a list/dict/set literal whenever the container as a whole didn't fit on one line, even when that specific call was short enough to stay on the line (e.g. ()). This produced inconsistent formatting where plain elements were crammed together but call elements each started a new line. The check now only forces the split when the call itself doesn't fit on the line, matching the check already used for calls that aren't inside a [/{ container. The original motivating case (a list of long, multi-line function calls) is unaffected, since those calls still don't fit on the line by themselves. Fixes #422 Signed-off-by: Eljees <3.14hell@gmail.com> --- CHANGELOG.md | 3 +++ yapf/yapflib/format_decision_state.py | 9 ++++++++- yapftests/reformatter_basic_test.py | 16 ++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ccc8726c9..a05893e0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,9 @@ by taking precedence over SPLIT_BEFORE_NAMED_ASSIGNS. - Fix SPLIT_ALL_COMMA_SEPARATED_VALUES and SPLIT_ALL_TOP_LEVEL_COMMA_SEPARATED_VALUES being too agressive for lambdas and unpacking. +- Fix a short, no-argument function call in a list being forced onto its own + line just because the list as a whole didn't fit on one line, producing + inconsistent formatting between call and non-call elements. ## [0.40.2] 2023-09-22 ### Changes diff --git a/yapf/yapflib/format_decision_state.py b/yapf/yapflib/format_decision_state.py index 06f3455d9..8c31321fc 100644 --- a/yapf/yapflib/format_decision_state.py +++ b/yapf/yapflib/format_decision_state.py @@ -317,11 +317,18 @@ def SurroundedByParens(token): if func_call_or_string_format: open_bracket = logical_line.IsSurroundedByBrackets(current) if open_bracket: - if open_bracket.value in '[{': + if open_bracket.value in '[{' and tok.value != '(': if not self._FitsOnLine(open_bracket, open_bracket.matching_bracket): return True elif tok.value == '(': + # Only force a split before this function-call element if the + # call itself doesn't fit on the line. Checking whether the + # *whole* surrounding list/dict fits (as above) forces a split + # before every function-call element whenever the container is + # too long overall, even for short calls like `f()`, producing + # inconsistent formatting between call and non-call elements. + # See https://github.com/google/yapf/issues/422. if not self._FitsOnLine(current, tok.matching_bracket): return True diff --git a/yapftests/reformatter_basic_test.py b/yapftests/reformatter_basic_test.py index 74b1ba405..f772189c8 100644 --- a/yapftests/reformatter_basic_test.py +++ b/yapftests/reformatter_basic_test.py @@ -2816,6 +2816,22 @@ def foo(): llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) + def testListWithShortFunctionCallsAmongPlainElements(self): + # A short, no-argument function call in a list shouldn't be forced onto + # its own line just because the list as a whole doesn't fit: only calls + # that don't themselves fit on the line should be split like that. + # See https://github.com/google/yapf/issues/422. + unformatted_code = textwrap.dedent("""\ + array = [first, make_second(), third, fourth, fifth, make_sixth(), seventh, eighth] + """) + expected_code = textwrap.dedent("""\ + array = [ + first, make_second(), third, fourth, fifth, make_sixth(), seventh, eighth + ] + """) + llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) + self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) + def testEllipses(self): unformatted_code = textwrap.dedent("""\ X=...