Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[925] Improve multiline dictionary and list indentation for sole function parameter #3964

Merged
merged 14 commits into from Oct 25, 2023
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -13,6 +13,8 @@
### Preview style

- Fix merging implicit multiline strings that have inline comments (#3956)
- 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
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved

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
14 changes: 14 additions & 0 deletions src/black/linegen.py
Expand Up @@ -815,6 +815,20 @@ 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 head_leaves[-1].type == token.LPAR
and head_leaves[-1].value
and body_leaves[0].type in [token.LBRACE, token.LSQB]
and body_leaves[-1].type in [token.RBRACE, token.RSQB]
):
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()


class Deprecated(UserWarning):
Expand Down
258 changes: 258 additions & 0 deletions tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py
@@ -0,0 +1,258 @@
# flags: --preview
def foo_brackets(request):
return JsonResponse(
JelleZijlstra marked this conversation as resolved.
Show resolved Hide resolved
{
"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"}})


# 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",
}
})
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