Skip to content

Commit f36b8c2

Browse files
authored
Add new DISABLE_SPLIT_LIST_WITH_COMMENT flag. (#1177)
`DISABLE_SPLIT_LIST_WITH_COMMENT` is a new knob that changes the behavior of splitting a list when a comment is present inside the list. Before, we split a list containing a comment just like we split a list containing a trailing comma: Each element goes on its own line (unless `DISABLE_ENDING_COMMA_HEURISTIC` is true). Now, if `DISABLE_SPLIT_LIST_WITH_COMMENT` is true, we do not split every element of the list onto a new line just because there's a comment somewhere in the list. This mirrors the behavior of clang-format, and is useful for e.g. forming "logical groups" of elements in a list. Note: Upgrading will result in a behavioral change if you have `DISABLE_ENDING_COMMA_HEURISTIC` in your config. Before this version, this flag caused us not to split lists with a trailing comma *and* lists that contain comments. Now, if you set only that flag, we *will* split lists that contain comments. Set the new `DISABLE_SPLIT_LIST_WITH_COMMENT` flag to true to preserve the old behavior.
1 parent 486a5a2 commit f36b8c2

File tree

5 files changed

+150
-6
lines changed

5 files changed

+150
-6
lines changed

CHANGELOG.md

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,70 @@
22
# All notable changes to this project will be documented in this file.
33
# This project adheres to [Semantic Versioning](http://semver.org/).
44

5-
## (0.40.3) UNRELEASED
5+
## (0.41.0) UNRELEASED
6+
### Added
7+
- New `DISABLE_SPLIT_LIST_WITH_COMMENT` flag.
8+
`DISABLE_SPLIT_LIST_WITH_COMMENT` is a new knob that changes the
9+
behavior of splitting a list when a comment is present inside the list.
10+
11+
Before, we split a list containing a comment just like we split a list
12+
containing a trailing comma: Each element goes on its own line (unless
13+
`DISABLE_ENDING_COMMA_HEURISTIC` is true).
14+
15+
This new flag allows you to control the behavior of a list with a comment
16+
*separately* from the behavior when the list contains a trailing comma.
17+
18+
This mirrors the behavior of clang-format, and is useful for e.g. forming
19+
"logical groups" of elements in a list.
20+
21+
Without this flag:
22+
23+
```
24+
[
25+
a,
26+
b, #
27+
c
28+
]
29+
```
30+
31+
With this flag:
32+
33+
```
34+
[
35+
a, b, #
36+
c
37+
]
38+
```
39+
40+
Before we had one flag that controlled two behaviors.
41+
42+
- `DISABLE_ENDING_COMMA_HEURISTIC=false` (default):
43+
- Split a list that has a trailing comma.
44+
- Split a list that contains a comment.
45+
- `DISABLE_ENDING_COMMA_HEURISTIC=true`:
46+
- Don't split on trailing comma.
47+
- Don't split on comment.
48+
49+
Now we have two flags.
50+
51+
- `DISABLE_ENDING_COMMA_HEURISTIC=false` and `DISABLE_SPLIT_LIST_WITH_COMMENT=false` (default):
52+
- Split a list that has a trailing comma.
53+
- Split a list that contains a comment.
54+
Behavior is unchanged from the default before.
55+
- `DISABLE_ENDING_COMMA_HEURISTIC=true` and `DISABLE_SPLIT_LIST_WITH_COMMENT=false` :
56+
- Don't split on trailing comma.
57+
- Do split on comment. **This is a change in behavior from before.**
58+
- `DISABLE_ENDING_COMMA_HEURISTIC=false` and `DISABLE_SPLIT_LIST_WITH_COMMENT=true` :
59+
- Split on trailing comma.
60+
- Don't split on comment.
61+
- `DISABLE_ENDING_COMMA_HEURISTIC=true` and `DISABLE_SPLIT_LIST_WITH_COMMENT=true` :
62+
- Don't split on trailing comma.
63+
- Don't split on comment.
64+
**You used to get this behavior just by setting one flag, but now you have to set both.**
65+
66+
Note the behavioral change above; if you set
67+
`DISABLE_ENDING_COMMA_HEURISTIC=true` and want to keep the old behavior, you
68+
now also need to set `DISABLE_SPLIT_LIST_WITH_COMMENT=true`.
669
### Changes
770
- Remove dependency on importlib-metadata
871
- Remove dependency on tomli when using >= py311

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,41 @@ optional arguments:
512512

513513
> Disable the heuristic which places each list element on a separate line if
514514
> the list is comma-terminated.
515+
>
516+
> Note: The behavior of this flag changed in v0.40.3. Before, if this flag
517+
> was true, we would split lists that contained a trailing comma or a
518+
> comment. Now, we have a separate flag, `DISABLE_SPLIT_LIST_WITH_COMMENT`,
519+
> that controls splitting when a list contains a comment. To get the old
520+
> behavior, set both flags to true. More information in
521+
> [CHANGELOG.md](CHANGELOG.md#new-disable_split_list_with_comment-flag).
522+
523+
#### `DISABLE_DISABLE_SPLIT_LIST_WITH_COMMENT` (new in 0.40.3)
524+
525+
> Don't put every element on a new line within a list that contains
526+
> interstitial comments.
527+
>
528+
> Without this flag (default):
529+
>
530+
> ```
531+
> [
532+
> a,
533+
> b, #
534+
> c
535+
> ]
536+
> ```
537+
>
538+
> With this flag:
539+
>
540+
> ```
541+
> [
542+
> a, b, #
543+
> c
544+
> ]
545+
> ```
546+
>
547+
> This mirrors the behavior of clang-format and is useful for forming
548+
> "logical groups" of elements in a list. It also works in function
549+
> declarations.
515550
516551
#### `EACH_DICT_ENTRY_ON_SEPARATE_LINE`
517552

yapf/pytree/pytree_unwrapper.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -407,16 +407,27 @@ def _AdjustSplitPenalty(line):
407407

408408
def _DetermineMustSplitAnnotation(node):
409409
"""Enforce a split in the list if the list ends with a comma."""
410-
if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'):
411-
return
412-
if not _ContainsComments(node):
410+
411+
def SplitBecauseTrailingComma():
412+
if style.Get('DISABLE_ENDING_COMMA_HEURISTIC'):
413+
return False
413414
token = next(node.parent.leaves())
414415
if token.value == '(':
415416
if sum(1 for ch in node.children if ch.type == grammar_token.COMMA) < 2:
416-
return
417+
return False
417418
if (not isinstance(node.children[-1], pytree.Leaf) or
418419
node.children[-1].value != ','):
419-
return
420+
return False
421+
return True
422+
423+
def SplitBecauseListContainsComment():
424+
return (not style.Get('DISABLE_SPLIT_LIST_WITH_COMMENT') and
425+
_ContainsComments(node))
426+
427+
if (not SplitBecauseTrailingComma() and
428+
not SplitBecauseListContainsComment()):
429+
return
430+
420431
num_children = len(node.children)
421432
index = 0
422433
_SetMustSplitOnFirstLeaf(node.children[0])

yapf/yapflib/style.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,16 @@ def method():
179179
DISABLE_ENDING_COMMA_HEURISTIC=textwrap.dedent("""\
180180
Disable the heuristic which places each list element on a separate line
181181
if the list is comma-terminated.
182+
183+
Note: The behavior of this flag changed in v0.40.3. Before, if this flag
184+
was true, we would split lists that contained a trailing comma or a
185+
comment. Now, we have a separate flag, `DISABLE_SPLIT_LIT_WITH_COMMENT`,
186+
that controls splitting when a list contains a comment. To get the old
187+
behavior, set both flags to true. More information in CHANGELOG.md.
188+
"""),
189+
DISABLE_SPLIT_LIST_WITH_COMMENT=textwrap.dedent("""
190+
Don't put every element on a new line within a list that contains
191+
interstitial comments.
182192
"""),
183193
EACH_DICT_ENTRY_ON_SEPARATE_LINE=textwrap.dedent("""\
184194
Place each dictionary entry onto its own line.
@@ -483,6 +493,7 @@ def CreatePEP8Style():
483493
CONTINUATION_INDENT_WIDTH=4,
484494
DEDENT_CLOSING_BRACKETS=False,
485495
DISABLE_ENDING_COMMA_HEURISTIC=False,
496+
DISABLE_SPLIT_LIST_WITH_COMMENT=False,
486497
EACH_DICT_ENTRY_ON_SEPARATE_LINE=True,
487498
FORCE_MULTILINE_DICT=False,
488499
I18N_COMMENT='',
@@ -671,6 +682,7 @@ def _IntOrIntListConverter(s):
671682
CONTINUATION_INDENT_WIDTH=int,
672683
DEDENT_CLOSING_BRACKETS=_BoolConverter,
673684
DISABLE_ENDING_COMMA_HEURISTIC=_BoolConverter,
685+
DISABLE_SPLIT_LIST_WITH_COMMENT=_BoolConverter,
674686
EACH_DICT_ENTRY_ON_SEPARATE_LINE=_BoolConverter,
675687
FORCE_MULTILINE_DICT=_BoolConverter,
676688
I18N_COMMENT=str,

yapftests/reformatter_basic_test.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,29 @@ def f( # Intermediate comment
345345
llines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
346346
self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines))
347347

348+
def testParamListWithTrailingComments(self):
349+
unformatted_code = textwrap.dedent("""\
350+
def f(a,
351+
b, #
352+
c):
353+
pass
354+
""")
355+
expected_formatted_code = textwrap.dedent("""\
356+
def f(a, b, #
357+
c):
358+
pass
359+
""")
360+
try:
361+
style.SetGlobalStyle(
362+
style.CreateStyleFromConfig(
363+
'{based_on_style: yapf,'
364+
' disable_split_list_with_comment: True}'))
365+
llines = yapf_test_helper.ParseAndUnwrap(unformatted_code)
366+
self.assertCodeEqual(expected_formatted_code,
367+
reformatter.Reformat(llines))
368+
finally:
369+
style.SetGlobalStyle(style.CreateYapfStyle())
370+
348371
def testBlankLinesBetweenTopLevelImportsAndVariables(self):
349372
unformatted_code = textwrap.dedent("""\
350373
import foo as bar

0 commit comments

Comments
 (0)