Skip to content

Commit

Permalink
[925] Improve multiline dictionary and list indentation for sole func…
Browse files Browse the repository at this point in the history
…tion parameter (#3964)
  • Loading branch information
henriholopainen committed Oct 25, 2023
1 parent ef1048d commit 1d4c31a
Show file tree
Hide file tree
Showing 6 changed files with 325 additions and 13 deletions.
3 changes: 2 additions & 1 deletion CHANGES.md
Expand Up @@ -12,7 +12,8 @@

### Preview style

<!-- Changes that affect Black's preview style -->
- Multiline dictionaries and lists that are the sole argument to a function are now
indented less (#3964)

### Configuration

Expand Down
26 changes: 26 additions & 0 deletions docs/the_black_code_style/future_style.md
Expand Up @@ -113,6 +113,32 @@ my_dict = {
}
```

### Improved multiline dictionary and list indentation for sole function parameter

For better readability and less verticality, _Black_ now pairs parantheses ("(", ")")
with braces ("{", "}") and square brackets ("[", "]") on the same line for single
parameter function calls. For example:

```python
foo(
[
1,
2,
3,
]
)
```

will be changed to:

```python
foo([
1,
2,
3,
])
```

### Improved multiline string handling

_Black_ is smarter when formatting multiline strings, especially in function arguments,
Expand Down
13 changes: 13 additions & 0 deletions src/black/linegen.py
Expand Up @@ -815,6 +815,19 @@ def _first_right_hand_split(
tail_leaves.reverse()
body_leaves.reverse()
head_leaves.reverse()

if Preview.hug_parens_with_braces_and_square_brackets in line.mode:
if (
tail_leaves[0].type == token.RPAR
and tail_leaves[0].value
and tail_leaves[0].opening_bracket is head_leaves[-1]
and body_leaves[-1].type in [token.RBRACE, token.RSQB]
and body_leaves[-1].opening_bracket is body_leaves[0]
):
head_leaves = head_leaves + body_leaves[:1]
tail_leaves = body_leaves[-1:] + tail_leaves
body_leaves = body_leaves[1:-1]

head = bracket_split_build_line(
head_leaves, line, opening_bracket, component=_BracketSplitComponent.head
)
Expand Down
1 change: 1 addition & 0 deletions src/black/mode.py
Expand Up @@ -190,6 +190,7 @@ class Preview(Enum):
module_docstring_newlines = auto()
accept_raw_docstrings = auto()
fix_power_op_line_length = auto()
hug_parens_with_braces_and_square_brackets = auto()
allow_empty_first_line_before_new_block_or_comment = auto()


Expand Down
273 changes: 273 additions & 0 deletions tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py
@@ -0,0 +1,273 @@
# flags: --preview
def foo_brackets(request):
return JsonResponse(
{
"var_1": foo,
"var_2": bar,
}
)

def foo_square_brackets(request):
return JsonResponse(
[
"var_1",
"var_2",
]
)

func({"a": 37, "b": 42, "c": 927, "aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111})

func(["random_string_number_one","random_string_number_two","random_string_number_three","random_string_number_four"])

func(
{
# expand me
'a':37,
'b':42,
'c':927
}
)

func(
[
'a',
'b',
'c',
]
)

func( # a
[ # b
"c", # c
"d", # d
"e", # e
] # f
) # g

func( # a
{ # b
"c": 1, # c
"d": 2, # d
"e": 3, # e
} # f
) # g

func(
# preserve me
[
"c",
"d",
"e",
]
)

func(
[ # preserve me but hug brackets
"c",
"d",
"e",
]
)

func(
[
# preserve me but hug brackets
"c",
"d",
"e",
]
)

func(
[
"c",
# preserve me but hug brackets
"d",
"e",
]
)

func(
[
"c",
"d",
"e",
# preserve me but hug brackets
]
)

func(
[
"c",
"d",
"e",
] # preserve me but hug brackets
)

func(
[
"c",
"d",
"e",
]
# preserve me
)

func([x for x in "short line"])
func([x for x in "long line long line long line long line long line long line long line"])
func([x for x in [x for x in "long line long line long line long line long line long line long line"]])

func({"short line"})
func({"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"})
func({{"long line", "long long line", "long long long line", "long long long long line", "long long long long long line"}})

foooooooooooooooooooo(
[{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size}
)

baaaaaaaaaaaaar(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
)

# output
def foo_brackets(request):
return JsonResponse({
"var_1": foo,
"var_2": bar,
})


def foo_square_brackets(request):
return JsonResponse([
"var_1",
"var_2",
])


func({
"a": 37,
"b": 42,
"c": 927,
"aaaaaaaaaaaaaaaaaaaaaaaaa": 11111111111111111111111111111111111111111,
})

func([
"random_string_number_one",
"random_string_number_two",
"random_string_number_three",
"random_string_number_four",
])

func({
# expand me
"a": 37,
"b": 42,
"c": 927,
})

func([
"a",
"b",
"c",
])

func([ # a # b
"c", # c
"d", # d
"e", # e
]) # f # g

func({ # a # b
"c": 1, # c
"d": 2, # d
"e": 3, # e
}) # f # g

func(
# preserve me
[
"c",
"d",
"e",
]
)

func([ # preserve me but hug brackets
"c",
"d",
"e",
])

func([
# preserve me but hug brackets
"c",
"d",
"e",
])

func([
"c",
# preserve me but hug brackets
"d",
"e",
])

func([
"c",
"d",
"e",
# preserve me but hug brackets
])

func([
"c",
"d",
"e",
]) # preserve me but hug brackets

func(
[
"c",
"d",
"e",
]
# preserve me
)

func([x for x in "short line"])
func([
x for x in "long line long line long line long line long line long line long line"
])
func([
x
for x in [
x
for x in "long line long line long line long line long line long line long line"
]
])

func({"short line"})
func({
"long line",
"long long line",
"long long long line",
"long long long long line",
"long long long long long line",
})
func({
{
"long line",
"long long line",
"long long long line",
"long long long long line",
"long long long long long line",
}
})

foooooooooooooooooooo(
[{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size}
)

baaaaaaaaaaaaar(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
)
22 changes: 10 additions & 12 deletions tests/data/cases/preview_long_strings__regression.py
Expand Up @@ -962,19 +962,17 @@ def who(self):
)


xxxxxxx_xxxxxx_xxxxxxx = xxx(
[
xxxxxxxxxxxx(
xxxxxx_xxxxxxx=(
'((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx ='
' "xxxxxxxxxxxx")) && '
# xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx.
"(x.bbbbbbbbbbbb.xxx != "
'"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && '
)
xxxxxxx_xxxxxx_xxxxxxx = xxx([
xxxxxxxxxxxx(
xxxxxx_xxxxxxx=(
'((x.aaaaaaaaa = "xxxxxx.xxxxxxxxxxxxxxxxxxxxx") || (x.xxxxxxxxx ='
' "xxxxxxxxxxxx")) && '
# xxxxx xxxxxxxxxxxx xxxx xxx (xxxxxxxxxxxxxxxx) xx x xxxxxxxxx xx xxxxxx.
"(x.bbbbbbbbbbbb.xxx != "
'"xxx:xxx:xxx::cccccccccccc:xxxxxxx-xxxx/xxxxxxxxxxx/xxxxxxxxxxxxxxxxx") && '
)
]
)
)
])

if __name__ == "__main__":
for i in range(4, 8):
Expand Down

0 comments on commit 1d4c31a

Please sign in to comment.