From 4c3d4df9876358959ecdd7227cdefb4f8b140e79 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:06:24 +0300 Subject: [PATCH 01/12] Add new test cases --- ..._parens_with_braces_and_square_brackets.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py diff --git a/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py b/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py new file mode 100644 index 00000000000..7d7131cd884 --- /dev/null +++ b/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py @@ -0,0 +1,79 @@ +# 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', + ] +) + +# 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", +]) From cb2465cbbf50f5eaf1061bc0f2233eabbd724bdb Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:06:46 +0300 Subject: [PATCH 02/12] Modify existing test --- .../cases/preview_long_strings__regression.py | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/tests/data/cases/preview_long_strings__regression.py b/tests/data/cases/preview_long_strings__regression.py index 436157f4e05..313d898cd83 100644 --- a/tests/data/cases/preview_long_strings__regression.py +++ b/tests/data/cases/preview_long_strings__regression.py @@ -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): From 4c56b2f075782501cdbc71148b152309304badba Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:07:28 +0300 Subject: [PATCH 03/12] Add preview toggle for feature --- src/black/mode.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/black/mode.py b/src/black/mode.py index 309f22dae94..744a1d64d03 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -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): From 254006abc33229adedd5e97f99a46a4b0fb9e3cb Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:08:19 +0300 Subject: [PATCH 04/12] Hug parens with brackets and square braces --- src/black/linegen.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/black/linegen.py b/src/black/linegen.py index 2bfe587fa0e..43144ad44d2 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -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 ) From a8dde633884f0c7669419fc864ab378ff59e8b3d Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:09:16 +0300 Subject: [PATCH 05/12] Update docs --- docs/the_black_code_style/future_style.md | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 367ff98537c..e73c16ba26e 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -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, From 90d9197ca28c0e1459ebca58954e73087745d37d Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:10:28 +0300 Subject: [PATCH 06/12] Add changelog line --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 79b5c6034e8..dbc28b606a2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ ### Preview style - Fix merging implicit multiline strings that have inline comments (#3956) +- Improve multiline dictionary and list indentation for sole function parameter (#XXXX) ### Configuration From 083b676b140b97d4296ff413d877de22220c7be3 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Sun, 22 Oct 2023 20:18:35 +0300 Subject: [PATCH 07/12] Update PR number --- CHANGES.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index dbc28b606a2..08d2be452f2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,7 @@ ### Preview style - Fix merging implicit multiline strings that have inline comments (#3956) -- Improve multiline dictionary and list indentation for sole function parameter (#XXXX) +- Improve multiline dictionary and list indentation for sole function parameter (#3964) ### Configuration From 3432bd4131474f5b0110002710fe938b674fbfb8 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Mon, 23 Oct 2023 11:28:48 +0300 Subject: [PATCH 08/12] Make changelog entry less opinionated --- CHANGES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 08d2be452f2..77fe84fe68a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,7 +13,8 @@ ### Preview style - Fix merging implicit multiline strings that have inline comments (#3956) -- Improve multiline dictionary and list indentation for sole function parameter (#3964) +- Multiline dictionaries and lists that are the sole argument to a function are now + indented less (#3964) ### Configuration From eb74ddb760fe2526fc265ac20073b11b8efc42e9 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Mon, 23 Oct 2023 12:00:06 +0300 Subject: [PATCH 09/12] More exhaustive test cases --- ..._parens_with_braces_and_square_brackets.py | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py b/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py index 7d7131cd884..b1e4b8a710a 100644 --- a/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py +++ b/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py @@ -36,6 +36,92 @@ def foo_square_brackets(request): ] ) +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({ @@ -77,3 +163,96 @@ def foo_square_brackets(request): "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", + } +}) From f42642b91bc5d57ced1777d2316cdc1c2cb4a532 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Tue, 24 Oct 2023 10:28:57 +0300 Subject: [PATCH 10/12] Add test cases --- ..._hug_parens_with_braces_and_square_brackets.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py b/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py index b1e4b8a710a..98ed342fcbc 100644 --- a/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py +++ b/tests/data/cases/preview_hug_parens_with_braces_and_square_brackets.py @@ -121,6 +121,13 @@ def foo_square_brackets(request): 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): @@ -256,3 +263,11 @@ def foo_square_brackets(request): "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] +) From aaaa025cf13577423591ae02c5e97dfaacd21682 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Tue, 24 Oct 2023 10:31:48 +0300 Subject: [PATCH 11/12] More robust block detection --- src/black/linegen.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/black/linegen.py b/src/black/linegen.py index 43144ad44d2..5f5a69152d5 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -820,10 +820,9 @@ def _first_right_hand_split( 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 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 From c066e69e1dc589669f516e6c0852b6f2a8734583 Mon Sep 17 00:00:00 2001 From: Henri Holopainen Date: Tue, 24 Oct 2023 23:29:47 +0300 Subject: [PATCH 12/12] Update CHANGES.md Co-authored-by: Jelle Zijlstra --- CHANGES.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d1050087400..f7d02af187d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -12,10 +12,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) -- Allow empty first line after block open before a comment or compound statement (#3967) ### Configuration