From 183a65b5326809968db47809dcb978af1c7e1386 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+RedGuy12@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:20:30 -0500 Subject: [PATCH 01/14] fix: Remove parenthesis around sole list items Signed-off-by: cobalt <61329810+RedGuy12@users.noreply.github.com> --- docs/the_black_code_style/future_style.md | 43 ++++- src/black/linegen.py | 29 +++- src/black/lines.py | 6 +- src/black/mode.py | 4 +- src/black/resources/black.schema.json | 2 +- .../preview_remove_sole_list_item_parens.py | 156 ++++++++++++++++++ 6 files changed, 228 insertions(+), 12 deletions(-) create mode 100644 tests/data/cases/preview_remove_sole_list_item_parens.py diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index e0f45b47106..d60f9c7a999 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -47,8 +47,8 @@ The unstable style additionally includes the following features: ([see below](labels/wrap-long-dict-values)) - `multiline_string_handling`: more compact formatting of expressions involving multiline strings ([see below](labels/multiline-string-handling)) -- `hug_parens_with_braces_and_square_brackets`: more compact formatting of nested - brackets ([see below](labels/hug-parens)) +- `condence_nested_brackets`: more compact formatting of nested brackets + ([see below](labels/hug-parens)) (labels/hug-parens)= @@ -124,6 +124,45 @@ foo( ) ``` +Parenthesises around sole list items will also be removed for similar reasons. Trailing +commas are respected here as well. For example: + +```python +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ) +] + +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ), +] +``` + +will be changed to: + +```python +items = [ + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name +] + +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ), +] +``` + (labels/string-processing)= ### Improved string processing diff --git a/src/black/linegen.py b/src/black/linegen.py index 2d9c27a6141..efad4fca205 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -501,6 +501,19 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]: yield from self.visit_default(leaf) + def visit_atom(self, node: Node) -> Iterator[Line]: + """Visit any atom""" + if ( + Preview.condence_nested_brackets in self.mode + and len(node.children) == 3 + and node.children[0].type == token.LSQB + and node.children[-1].type == token.RSQB + ): + # Lists of one item + maybe_make_parens_invisible_in_atom(node.children[1], parent=node) + + yield from self.visit_default(node) + def __post_init__(self) -> None: """You are in a twisty little maze of passages.""" self.current_line = Line(mode=self.mode) @@ -811,7 +824,7 @@ def _first_right_hand_split( body: Optional[Line] = None if ( - Preview.hug_parens_with_braces_and_square_brackets in line.mode + Preview.condence_nested_brackets in line.mode and tail_leaves[0].value and tail_leaves[0].opening_bracket is head_leaves[-1] ): @@ -883,19 +896,25 @@ def _maybe_split_omitting_optional_parens( features: Collection[Feature] = (), omit: Collection[LeafID] = (), ) -> Iterator[Line]: - if ( + both_optional_parens = ( Feature.FORCE_OPTIONAL_PARENTHESES not in features - # the opening bracket is an optional paren and rhs.opening_bracket.type == token.LPAR and not rhs.opening_bracket.value - # the closing bracket is an optional paren and rhs.closing_bracket.type == token.RPAR and not rhs.closing_bracket.value + ) + if ( + # If both brackets are optional parens + both_optional_parens # it's not an import (optional parens are the only thing we can split on # in this case; attempting a split without them is a waste of time) and not line.is_import # and we can actually remove the parens - and can_omit_invisible_parens(rhs, mode.line_length) + and can_omit_invisible_parens( + rhs, + mode.line_length, + Preview.condence_nested_brackets in mode and line.inside_brackets, + ) ): omit = {id(rhs.closing_bracket), *omit} try: diff --git a/src/black/lines.py b/src/black/lines.py index 6b65372fb3f..76531c3332a 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -929,6 +929,7 @@ def can_be_split(line: Line) -> bool: def can_omit_invisible_parens( rhs: RHSResult, line_length: int, + inside_brackets: bool, ) -> bool: """Does `rhs.body` have a shape safe to reformat without optional parens around it? @@ -962,8 +963,9 @@ def can_omit_invisible_parens( max_priority = bt.max_delimiter_priority() delimiter_count = bt.delimiter_count_with_priority(max_priority) if delimiter_count > 1: - # With more than one delimiter of a kind the optional parentheses read better. - return False + # With more than one delimiter of a kind the optional parentheses read + # better, but they're redundant if we're already inside brackets. + return inside_brackets if delimiter_count == 1: if max_priority == COMMA_PRIORITY and rhs.head.is_with_or_async_with_stmt: diff --git a/src/black/mode.py b/src/black/mode.py index b54f355e20a..88b6e76d30b 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -171,7 +171,7 @@ class Preview(Enum): # NOTE: string_processing requires wrap_long_dict_values_in_parens # for https://github.com/psf/black/issues/3117 to be fixed. string_processing = auto() - hug_parens_with_braces_and_square_brackets = auto() + condence_nested_brackets = auto() unify_docstring_detection = auto() no_normalize_fmt_skip_whitespace = auto() wrap_long_dict_values_in_parens = auto() @@ -191,7 +191,7 @@ class Preview(Enum): # See issue #4159 Preview.multiline_string_handling, # See issue #4036 (crash), #4098, #4099 (proposed tweaks) - Preview.hug_parens_with_braces_and_square_brackets, + Preview.condence_nested_brackets, } diff --git a/src/black/resources/black.schema.json b/src/black/resources/black.schema.json index 5c800775d57..12ac1bb7068 100644 --- a/src/black/resources/black.schema.json +++ b/src/black/resources/black.schema.json @@ -80,7 +80,7 @@ "enum": [ "hex_codes_in_unicode_sequences", "string_processing", - "hug_parens_with_braces_and_square_brackets", + "condence_nested_brackets", "unify_docstring_detection", "no_normalize_fmt_skip_whitespace", "wrap_long_dict_values_in_parens", diff --git a/tests/data/cases/preview_remove_sole_list_item_parens.py b/tests/data/cases/preview_remove_sole_list_item_parens.py new file mode 100644 index 00000000000..7cbd61e9b2a --- /dev/null +++ b/tests/data/cases/preview_remove_sole_list_item_parens.py @@ -0,0 +1,156 @@ +# flags: --unstable +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else { "key": "val" } + ) +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else { "key": "val" } + ), +] +items = [( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else { "key": "val" } +)] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else {"key": "val"} +] +items = [ + ( + {"key1": "val1", "key2": "val2"} if some_var == "longstring" else { "key": "val" } + ) +] +items = [( + {"key1": "val1", "key2": "val2"} if some_var == "" else { "key": "val" } +)] +items = [ + {"key1": "val1", "key2": "val2"} if some_var == "longstring" else { "key": "val" } +] +items = [ + ({"key1": "val1", "key2": "val2"} if some_var == "longstring" else { "key": "val" }) +] +items = [({"key1": "val1", "key2": "val2"} if some_var == "" else { "key": "val" })] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else { "key": "val" }] + +items = [ + ( + "123456890123457890123468901234567890" + if some_var == "longstrings" + else "123467890123467890" + ) +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "longstring" + and {"key": "val"} +] +items = [ + ( + "123456890123457890123468901234567890" + and some_var == "longstrings" + and "123467890123467890" + ) +] +items = [( + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "longstring" + and {"key": "val"} +)] + + +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ) +] + +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ), +] + + +# output +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else {"key": "val"} +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else {"key": "val"} + ), +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else {"key": "val"} +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "longstring" + else {"key": "val"} +] +items = [ + {"key1": "val1", "key2": "val2"} if some_var == "longstring" else {"key": "val"} +] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] +items = [ + {"key1": "val1", "key2": "val2"} if some_var == "longstring" else {"key": "val"} +] +items = [ + {"key1": "val1", "key2": "val2"} if some_var == "longstring" else {"key": "val"} +] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] + +items = [ + "123456890123457890123468901234567890" + if some_var == "longstrings" + else "123467890123467890" +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "longstring" + and {"key": "val"} +] +items = [ + "123456890123457890123468901234567890" + and some_var == "longstrings" + and "123467890123467890" +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "longstring" + and {"key": "val"} +] + + +items = [ + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name +] + +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ), +] From e8d291d7999094ecd1cac368ac2f3f91c21f45cd Mon Sep 17 00:00:00 2001 From: cobalt <61329810+RedGuy12@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:55:58 -0500 Subject: [PATCH 02/14] fix: Remove parenthesis around sole list items Signed-off-by: cobalt <61329810+RedGuy12@users.noreply.github.com> --- CHANGES.md | 3 +++ docs/the_black_code_style/future_style.md | 2 +- src/black/linegen.py | 18 ++++++------------ src/black/lines.py | 11 +++-------- src/black/mode.py | 4 ++-- src/black/resources/black.schema.json | 2 +- 6 files changed, 16 insertions(+), 24 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index af756c79621..4708f41009a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,9 @@ ### Preview style +- Remove parenthesis around sole list items and rename + `hug_parens_with_braces_and_square_brackets` unstable style to + `concise_nested_brackets` (#4312) ### Configuration diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 4e33457001a..56248874192 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -47,7 +47,7 @@ The unstable style additionally includes the following features: ([see below](labels/wrap-long-dict-values)) - `multiline_string_handling`: more compact formatting of expressions involving multiline strings ([see below](labels/multiline-string-handling)) -- `condence_nested_brackets`: more compact formatting of nested brackets +- `concise_nested_brackets`: more compact formatting of nested brackets ([see below](labels/hug-parens)) (labels/hug-parens)= diff --git a/src/black/linegen.py b/src/black/linegen.py index efad4fca205..6a9c8b57ca0 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -504,7 +504,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]: def visit_atom(self, node: Node) -> Iterator[Line]: """Visit any atom""" if ( - Preview.condence_nested_brackets in self.mode + Preview.concise_nested_brackets in self.mode and len(node.children) == 3 and node.children[0].type == token.LSQB and node.children[-1].type == token.RSQB @@ -824,7 +824,7 @@ def _first_right_hand_split( body: Optional[Line] = None if ( - Preview.condence_nested_brackets in line.mode + Preview.concise_nested_brackets in line.mode and tail_leaves[0].value and tail_leaves[0].opening_bracket is head_leaves[-1] ): @@ -896,25 +896,19 @@ def _maybe_split_omitting_optional_parens( features: Collection[Feature] = (), omit: Collection[LeafID] = (), ) -> Iterator[Line]: - both_optional_parens = ( + if ( Feature.FORCE_OPTIONAL_PARENTHESES not in features + # the opening bracket is an optional paren and rhs.opening_bracket.type == token.LPAR and not rhs.opening_bracket.value + # the closing bracket is an optional paren and rhs.closing_bracket.type == token.RPAR and not rhs.closing_bracket.value - ) - if ( - # If both brackets are optional parens - both_optional_parens # it's not an import (optional parens are the only thing we can split on # in this case; attempting a split without them is a waste of time) and not line.is_import # and we can actually remove the parens - and can_omit_invisible_parens( - rhs, - mode.line_length, - Preview.condence_nested_brackets in mode and line.inside_brackets, - ) + and can_omit_invisible_parens(rhs, mode.line_length) ): omit = {id(rhs.closing_bracket), *omit} try: diff --git a/src/black/lines.py b/src/black/lines.py index 76531c3332a..8f276c2dccb 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -926,11 +926,7 @@ def can_be_split(line: Line) -> bool: return True -def can_omit_invisible_parens( - rhs: RHSResult, - line_length: int, - inside_brackets: bool, -) -> bool: +def can_omit_invisible_parens(rhs: RHSResult, line_length: int) -> bool: """Does `rhs.body` have a shape safe to reformat without optional parens around it? Returns True for only a subset of potentially nice looking formattings but @@ -963,9 +959,8 @@ def can_omit_invisible_parens( max_priority = bt.max_delimiter_priority() delimiter_count = bt.delimiter_count_with_priority(max_priority) if delimiter_count > 1: - # With more than one delimiter of a kind the optional parentheses read - # better, but they're redundant if we're already inside brackets. - return inside_brackets + # With more than one delimiter of a kind the optional parentheses read better. + return False if delimiter_count == 1: if max_priority == COMMA_PRIORITY and rhs.head.is_with_or_async_with_stmt: diff --git a/src/black/mode.py b/src/black/mode.py index 88b6e76d30b..10e37ccc460 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -171,7 +171,7 @@ class Preview(Enum): # NOTE: string_processing requires wrap_long_dict_values_in_parens # for https://github.com/psf/black/issues/3117 to be fixed. string_processing = auto() - condence_nested_brackets = auto() + concise_nested_brackets = auto() unify_docstring_detection = auto() no_normalize_fmt_skip_whitespace = auto() wrap_long_dict_values_in_parens = auto() @@ -191,7 +191,7 @@ class Preview(Enum): # See issue #4159 Preview.multiline_string_handling, # See issue #4036 (crash), #4098, #4099 (proposed tweaks) - Preview.condence_nested_brackets, + Preview.concise_nested_brackets, } diff --git a/src/black/resources/black.schema.json b/src/black/resources/black.schema.json index 12ac1bb7068..bff1033a823 100644 --- a/src/black/resources/black.schema.json +++ b/src/black/resources/black.schema.json @@ -80,7 +80,7 @@ "enum": [ "hex_codes_in_unicode_sequences", "string_processing", - "condence_nested_brackets", + "concise_nested_brackets", "unify_docstring_detection", "no_normalize_fmt_skip_whitespace", "wrap_long_dict_values_in_parens", From fd49184c1e897de377ea4f3be4fd8432766556a3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Apr 2024 17:57:00 +0000 Subject: [PATCH 03/14] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- CHANGES.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGES.md b/CHANGES.md index 4708f41009a..0820670feb3 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,6 +13,7 @@ ### Preview style + - Remove parenthesis around sole list items and rename `hug_parens_with_braces_and_square_brackets` unstable style to `concise_nested_brackets` (#4312) From 40140e4232ed17fbaf59ef98f936ec7c58ce5b39 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+RedGuy12@users.noreply.github.com> Date: Wed, 17 Apr 2024 12:57:38 -0500 Subject: [PATCH 04/14] Discard changes to src/black/lines.py --- src/black/lines.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/black/lines.py b/src/black/lines.py index 8f276c2dccb..6b65372fb3f 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -926,7 +926,10 @@ def can_be_split(line: Line) -> bool: return True -def can_omit_invisible_parens(rhs: RHSResult, line_length: int) -> bool: +def can_omit_invisible_parens( + rhs: RHSResult, + line_length: int, +) -> bool: """Does `rhs.body` have a shape safe to reformat without optional parens around it? Returns True for only a subset of potentially nice looking formattings but From 5ceaf93fd9b30bc76ec2321c6f51e7574c4ec759 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+RedGuy12@users.noreply.github.com> Date: Wed, 17 Apr 2024 13:03:27 -0500 Subject: [PATCH 05/14] Add docs and tests for the simple cases lol Signed-off-by: cobalt <61329810+RedGuy12@users.noreply.github.com> --- docs/the_black_code_style/future_style.md | 10 ++++++++++ .../cases/preview_remove_sole_list_item_parens.py | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 56248874192..5496b0b05bd 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -128,6 +128,11 @@ Parenthesises around sole list items will also be removed for similar reasons. T commas are respected here as well. For example: ```python +items = [(123)] +items = [(True)] +items = [((True,))] +items = [(())] + items = [ ( long_variable_name @@ -148,6 +153,11 @@ items = [ will be changed to: ```python +items = [123] +items = [True] +items = [(True,)] +items = [()] + items = [ long_variable_name and even_longer_variable_name diff --git a/tests/data/cases/preview_remove_sole_list_item_parens.py b/tests/data/cases/preview_remove_sole_list_item_parens.py index 7cbd61e9b2a..cdd968aadb8 100644 --- a/tests/data/cases/preview_remove_sole_list_item_parens.py +++ b/tests/data/cases/preview_remove_sole_list_item_parens.py @@ -1,4 +1,10 @@ # flags: --unstable +items = [(123)] +items = [(True)] +items = [(((((True)))))] +items = [(((((True,)))))] +items = [((((()))))] + items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} @@ -84,6 +90,12 @@ # output +items = [123] +items = [True] +items = [True] +items = [(True,)] +items = [()] + items = [ {"key1": "val1", "key2": "val2", "key3": "val3"} if some_var == "longstring" From bdb0a8a580f90f538f5121486cc5620da63e36ed Mon Sep 17 00:00:00 2001 From: cobalt <61329810+RedGuy12@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:57:38 -0500 Subject: [PATCH 06/14] Split into multiple features Signed-off-by: cobalt <61329810+RedGuy12@users.noreply.github.com> --- CHANGES.md | 4 +- docs/the_black_code_style/future_style.md | 17 ++- src/black/linegen.py | 4 +- src/black/mode.py | 9 +- src/black/resources/black.schema.json | 2 +- ...> preview_remove_lone_list_item_parens.py} | 110 ++++++++---------- 6 files changed, 73 insertions(+), 73 deletions(-) rename tests/data/cases/{preview_remove_sole_list_item_parens.py => preview_remove_lone_list_item_parens.py} (53%) diff --git a/CHANGES.md b/CHANGES.md index a5933af55ba..7f52ade6615 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,9 +18,7 @@ -- Remove parenthesis around sole list items and rename - `hug_parens_with_braces_and_square_brackets` unstable style to - `concise_nested_brackets` (#4312) +- Remove parenthesis around sole list items (#4312) ### Configuration diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 5496b0b05bd..6677b606e5f 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -47,8 +47,10 @@ The unstable style additionally includes the following features: ([see below](labels/wrap-long-dict-values)) - `multiline_string_handling`: more compact formatting of expressions involving multiline strings ([see below](labels/multiline-string-handling)) -- `concise_nested_brackets`: more compact formatting of nested brackets - ([see below](labels/hug-parens)) +- `hug_parens_with_braces_and_square_brackets`: more compact formatting of nested + brackets ([see below](labels/hug-parens)) +- `remove_lone_list_item_parens`: remove redundant parenthesis around lone list items + ([see below](labels/lone-list-item-parens)) (labels/hug-parens)= @@ -124,7 +126,11 @@ foo( ) ``` -Parenthesises around sole list items will also be removed for similar reasons. Trailing +(labels/lone-list-item-parens)= + +### Remove keys around sole list item + +Parentheses around sole list items will also be removed for similar reasons. Trailing commas are respected here as well. For example: ```python @@ -150,7 +156,7 @@ items = [ ] ``` -will be changed to: +will be formatted as: ```python items = [123] @@ -173,6 +179,9 @@ items = [ ] ``` +This style depends on `hug_parens_with_braces_and_square_brackets` to remove parenthesis +in all cases. + (labels/string-processing)= ### Improved string processing diff --git a/src/black/linegen.py b/src/black/linegen.py index 98bffcc1366..8e2d2f1c654 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -509,7 +509,7 @@ def visit_NUMBER(self, leaf: Leaf) -> Iterator[Line]: def visit_atom(self, node: Node) -> Iterator[Line]: """Visit any atom""" if ( - Preview.concise_nested_brackets in self.mode + Preview.remove_lone_list_item_parens in self.mode and len(node.children) == 3 and node.children[0].type == token.LSQB and node.children[-1].type == token.RSQB @@ -868,7 +868,7 @@ def _first_right_hand_split( body: Optional[Line] = None if ( - Preview.concise_nested_brackets in line.mode + Preview.hug_parens_with_braces_and_square_brackets in line.mode and tail_leaves[0].value and tail_leaves[0].opening_bracket is head_leaves[-1] ): diff --git a/src/black/mode.py b/src/black/mode.py index bef2f43bb31..c8c48235fd2 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -173,7 +173,7 @@ class Preview(Enum): # NOTE: string_processing requires wrap_long_dict_values_in_parens # for https://github.com/psf/black/issues/3117 to be fixed. string_processing = auto() - concise_nested_brackets = auto() + hug_parens_with_braces_and_square_brackets = auto() unify_docstring_detection = auto() no_normalize_fmt_skip_whitespace = auto() wrap_long_dict_values_in_parens = auto() @@ -183,6 +183,9 @@ class Preview(Enum): docstring_check_for_newline = auto() remove_redundant_guard_parens = auto() parens_for_long_if_clauses_in_case_block = auto() + # NOTE: remove_lone_list_item_parens requires + # hug_parens_with_braces_and_square_brackets to remove parens in some cases + remove_lone_list_item_parens = auto() UNSTABLE_FEATURES: Set[Preview] = { @@ -193,7 +196,9 @@ class Preview(Enum): # See issue #4159 Preview.multiline_string_handling, # See issue #4036 (crash), #4098, #4099 (proposed tweaks) - Preview.concise_nested_brackets, + Preview.hug_parens_with_braces_and_square_brackets, + # Depends on hug_parens_with_braces_and_square_brackets + Preview.remove_lone_list_item_parens, } diff --git a/src/black/resources/black.schema.json b/src/black/resources/black.schema.json index bff1033a823..5c800775d57 100644 --- a/src/black/resources/black.schema.json +++ b/src/black/resources/black.schema.json @@ -80,7 +80,7 @@ "enum": [ "hex_codes_in_unicode_sequences", "string_processing", - "concise_nested_brackets", + "hug_parens_with_braces_and_square_brackets", "unify_docstring_detection", "no_normalize_fmt_skip_whitespace", "wrap_long_dict_values_in_parens", diff --git a/tests/data/cases/preview_remove_sole_list_item_parens.py b/tests/data/cases/preview_remove_lone_list_item_parens.py similarity index 53% rename from tests/data/cases/preview_remove_sole_list_item_parens.py rename to tests/data/cases/preview_remove_lone_list_item_parens.py index cdd968aadb8..10f36ad4b23 100644 --- a/tests/data/cases/preview_remove_sole_list_item_parens.py +++ b/tests/data/cases/preview_remove_lone_list_item_parens.py @@ -8,69 +8,66 @@ items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" - else { "key": "val" } + if some_var == "long strings" + else {"key": "val"} ) ] items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" - else { "key": "val" } + if some_var == "long strings" + else {"key": "val"} ), ] -items = [( - {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" - else { "key": "val" } -)] items = [ {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" + if some_var == "long strings" else {"key": "val"} ] items = [ ( - {"key1": "val1", "key2": "val2"} if some_var == "longstring" else { "key": "val" } + {"key1": "val1", "key2": "val2"} + if some_var == "" + else {"key": "val"} ) ] -items = [( - {"key1": "val1", "key2": "val2"} if some_var == "" else { "key": "val" } -)] -items = [ - {"key1": "val1", "key2": "val2"} if some_var == "longstring" else { "key": "val" } -] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] items = [ - ({"key1": "val1", "key2": "val2"} if some_var == "longstring" else { "key": "val" }) + ( + "123456890123457890123468901234567890" + if some_var == "long strings" + else "123467890123467890" + ) ] -items = [({"key1": "val1", "key2": "val2"} if some_var == "" else { "key": "val" })] -items = [{"key1": "val1", "key2": "val2"} if some_var == "" else { "key": "val" }] items = [ ( - "123456890123457890123468901234567890" - if some_var == "longstrings" - else "123467890123467890" + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} ) ] items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "longstring" - and {"key": "val"} + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} + ), ] items = [ ( "123456890123457890123468901234567890" - and some_var == "longstrings" + and some_var == "long strings" and "123467890123467890" ) ] -items = [( - {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "longstring" - and {"key": "val"} -)] - +items = [ + ( + "123456890123457890123468901234567890" + and some_var == "long strings" + and "123467890123467890" + ), +] items = [ ( @@ -79,7 +76,6 @@ and yet_another_very_long_variable_name ) ] - items = [ ( long_variable_name @@ -98,67 +94,59 @@ items = [ {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" + if some_var == "long strings" else {"key": "val"} ] items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" + if some_var == "long strings" else {"key": "val"} ), ] items = [ {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" + if some_var == "long strings" else {"key": "val"} ] -items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "longstring" - else {"key": "val"} -] -items = [ - {"key1": "val1", "key2": "val2"} if some_var == "longstring" else {"key": "val"} -] items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] -items = [ - {"key1": "val1", "key2": "val2"} if some_var == "longstring" else {"key": "val"} -] -items = [ - {"key1": "val1", "key2": "val2"} if some_var == "longstring" else {"key": "val"} -] items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] -items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] - items = [ "123456890123457890123468901234567890" - if some_var == "longstrings" + if some_var == "long strings" else "123467890123467890" ] + items = [ {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "longstring" + and some_var == "long strings" and {"key": "val"} ] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} + ), +] items = [ "123456890123457890123468901234567890" - and some_var == "longstrings" + and some_var == "long strings" and "123467890123467890" ] items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "longstring" - and {"key": "val"} + ( + "123456890123457890123468901234567890" + and some_var == "long strings" + and "123467890123467890" + ), ] - items = [ long_variable_name and even_longer_variable_name and yet_another_very_long_variable_name ] - items = [ ( long_variable_name From a7c9f5b601a8da986f0ea9d94230e9272738f4ab Mon Sep 17 00:00:00 2001 From: cobalt <61329810+RedGuy12@users.noreply.github.com> Date: Fri, 7 Jun 2024 16:11:57 -0500 Subject: [PATCH 07/14] regen schema Signed-off-by: cobalt <61329810+RedGuy12@users.noreply.github.com> --- src/black/resources/black.schema.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/black/resources/black.schema.json b/src/black/resources/black.schema.json index 5c800775d57..c81de1ca4bb 100644 --- a/src/black/resources/black.schema.json +++ b/src/black/resources/black.schema.json @@ -89,7 +89,8 @@ "is_simple_lookup_for_doublestar_expression", "docstring_check_for_newline", "remove_redundant_guard_parens", - "parens_for_long_if_clauses_in_case_block" + "parens_for_long_if_clauses_in_case_block", + "remove_lone_list_item_parens" ] }, "description": "Enable specific features included in the `--unstable` style. Requires `--preview`. No compatibility guarantees are provided on the behavior or existence of any unstable features." From a8515e3e4329ff072d13b2a211da3d3c694079d6 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Sat, 5 Oct 2024 20:12:43 -0500 Subject: [PATCH 08/14] Update future_style.md --- docs/the_black_code_style/future_style.md | 60 +---------------------- 1 file changed, 2 insertions(+), 58 deletions(-) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 328858875eb..8bb78c2655a 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -38,6 +38,8 @@ Currently, the following features are included in the preview style: blocks when the line is too long - `pep646_typed_star_arg_type_var_tuple`: fix type annotation spacing between * and more complex type variable tuple (i.e. `def fn(*args: *tuple[*Ts, T]) -> None: pass`) +- `remove_lone_list_item_parens`: remove redundant parenthesis around lone list items + (depends on unstable `hug_parens_with_braces_and_square_brackets` feature in some cases) (labels/unstable-features)= @@ -51,8 +53,6 @@ The unstable style additionally includes the following features: multiline strings ([see below](labels/multiline-string-handling)) - `hug_parens_with_braces_and_square_brackets`: more compact formatting of nested brackets ([see below](labels/hug-parens)) -- `remove_lone_list_item_parens`: remove redundant parenthesis around lone list items - ([see below](labels/lone-list-item-parens)) (labels/hug-parens)= @@ -128,62 +128,6 @@ foo( ) ``` -(labels/lone-list-item-parens)= - -### Remove keys around sole list item - -Parentheses around sole list items will also be removed for similar reasons. Trailing -commas are respected here as well. For example: - -```python -items = [(123)] -items = [(True)] -items = [((True,))] -items = [(())] - -items = [ - ( - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name - ) -] - -items = [ - ( - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name - ), -] -``` - -will be formatted as: - -```python -items = [123] -items = [True] -items = [(True,)] -items = [()] - -items = [ - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name -] - -items = [ - ( - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name - ), -] -``` - -This style depends on `hug_parens_with_braces_and_square_brackets` to remove parenthesis -in all cases. - (labels/string-processing)= ### Improved string processing From ee65f5ac1cf6209c32496d728600751e5ab40f39 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 6 Oct 2024 01:13:08 +0000 Subject: [PATCH 09/14] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/the_black_code_style/future_style.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 8bb78c2655a..9c22e82404c 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -39,7 +39,8 @@ Currently, the following features are included in the preview style: - `pep646_typed_star_arg_type_var_tuple`: fix type annotation spacing between * and more complex type variable tuple (i.e. `def fn(*args: *tuple[*Ts, T]) -> None: pass`) - `remove_lone_list_item_parens`: remove redundant parenthesis around lone list items - (depends on unstable `hug_parens_with_braces_and_square_brackets` feature in some cases) + (depends on unstable `hug_parens_with_braces_and_square_brackets` feature in some + cases) (labels/unstable-features)= From 693790234d3a29ccde39e6a5e344564067e477f9 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Sat, 5 Oct 2024 20:13:34 -0500 Subject: [PATCH 10/14] Remove from unstable style --- src/black/mode.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/black/mode.py b/src/black/mode.py index 109c7997f23..8ab71bce660 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -225,8 +225,6 @@ class Preview(Enum): Preview.multiline_string_handling, # See issue #4036 (crash), #4098, #4099 (proposed tweaks) Preview.hug_parens_with_braces_and_square_brackets, - # Depends on hug_parens_with_braces_and_square_brackets - Preview.remove_lone_list_item_parens, } From 42864d759789966296815ecf5cc9642ab3b408fa Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Fri, 8 Nov 2024 16:56:33 -0600 Subject: [PATCH 11/14] typos Signed-off-by: cobalt <61329810+cobaltt7@users.noreply.github.com> --- CHANGES.md | 3 ++- docs/the_black_code_style/future_style.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 20a90318ff9..8f374f30dd7 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -17,6 +17,8 @@ +- Remove parentheses around sole list items (#4312) + ### Configuration @@ -74,7 +76,6 @@ - Fix type annotation spacing between * and more complex type variable tuple (i.e. `def fn(*args: *tuple[*Ts, T]) -> None: pass`) (#4440) -- Remove parenthesis around sole list items (#4312) ### Caching diff --git a/docs/the_black_code_style/future_style.md b/docs/the_black_code_style/future_style.md index 9c22e82404c..0b2e5f8b02c 100644 --- a/docs/the_black_code_style/future_style.md +++ b/docs/the_black_code_style/future_style.md @@ -38,7 +38,7 @@ Currently, the following features are included in the preview style: blocks when the line is too long - `pep646_typed_star_arg_type_var_tuple`: fix type annotation spacing between * and more complex type variable tuple (i.e. `def fn(*args: *tuple[*Ts, T]) -> None: pass`) -- `remove_lone_list_item_parens`: remove redundant parenthesis around lone list items +- `remove_lone_list_item_parens`: remove redundant parentheses around lone list items (depends on unstable `hug_parens_with_braces_and_square_brackets` feature in some cases) From c87d2376d7a2397b067b1fae661227506a8c2f91 Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Sun, 10 Nov 2024 14:03:22 -0600 Subject: [PATCH 12/14] Update tests Signed-off-by: cobalt <61329810+cobaltt7@users.noreply.github.com> --- src/black/linegen.py | 1 + .../preview_remove_lone_list_item_parens.py | 162 ++++++------ ..._remove_multiline_lone_list_item_parens.py | 246 ++++++++++++++++++ 3 files changed, 326 insertions(+), 83 deletions(-) create mode 100644 tests/data/cases/preview_remove_multiline_lone_list_item_parens.py diff --git a/src/black/linegen.py b/src/black/linegen.py index 783bbed3f00..a11e2465b83 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -1659,6 +1659,7 @@ def maybe_make_parens_invisible_in_atom( if first.prefix.strip(): # Preserve comments before first paren middle.prefix = first.prefix + middle.prefix + first.prefix = "" last.value = "" maybe_make_parens_invisible_in_atom( middle, diff --git a/tests/data/cases/preview_remove_lone_list_item_parens.py b/tests/data/cases/preview_remove_lone_list_item_parens.py index 10f36ad4b23..4b296d29ea5 100644 --- a/tests/data/cases/preview_remove_lone_list_item_parens.py +++ b/tests/data/cases/preview_remove_lone_list_item_parens.py @@ -1,10 +1,13 @@ -# flags: --unstable +# flags: --preview items = [(123)] items = [(True)] items = [(((((True)))))] items = [(((((True,)))))] items = [((((()))))] +items = [(x for x in [1])] +# Requires `hug_parens_with_braces_and_square_brackets` unstable style to remove parentheses +# around multiline values items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} @@ -12,18 +15,6 @@ else {"key": "val"} ) ] -items = [ - ( - {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "long strings" - else {"key": "val"} - ), -] -items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "long strings" - else {"key": "val"} -] items = [ ( {"key1": "val1", "key2": "val2"} @@ -31,58 +22,60 @@ else {"key": "val"} ) ] -items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] + +# Comments should not cause crashes items = [ - ( - "123456890123457890123468901234567890" + ( # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} if some_var == "long strings" - else "123467890123467890" + else {"key": "val"} ) ] - items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "long strings" - and {"key": "val"} - ) + if some_var == "long strings" + else {"key": "val"} + ) # comment ] -items = [ + +items = [ # comment ( {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "long strings" - and {"key": "val"} - ), + if some_var == "long strings" + else {"key": "val"} + ) ] items = [ ( - "123456890123457890123468901234567890" - and some_var == "long strings" - and "123467890123467890" + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} ) -] +] # comment + items = [ ( - "123456890123457890123468901234567890" - and some_var == "long strings" - and "123467890123467890" - ), + {"key1": "val1", "key2": "val2", "key3": "val3"} # comment + if some_var == "long strings" + else {"key": "val"} + ) ] -items = [ - ( - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name +items = [ # comment + ( # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} ) ] items = [ ( - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name - ), -] + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) # comment +] # comment # output @@ -91,66 +84,69 @@ items = [True] items = [(True,)] items = [()] +items = [(x for x in [1])] -items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "long strings" - else {"key": "val"} -] +# Requires `hug_parens_with_braces_and_square_brackets` unstable style to remove parentheses +# around multiline values items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} if some_var == "long strings" else {"key": "val"} - ), -] -items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - if some_var == "long strings" - else {"key": "val"} + ) ] items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] -items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] -items = [ - "123456890123457890123468901234567890" - if some_var == "long strings" - else "123467890123467890" -] +# Comments should not cause crashes items = [ - {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "long strings" - and {"key": "val"} + ( # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) ] items = [ ( {"key1": "val1", "key2": "val2", "key3": "val3"} - and some_var == "long strings" - and {"key": "val"} - ), + if some_var == "long strings" + else {"key": "val"} + ) # comment ] -items = [ - "123456890123457890123468901234567890" - and some_var == "long strings" - and "123467890123467890" + +items = [ # comment + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) ] items = [ ( - "123456890123457890123468901234567890" - and some_var == "long strings" - and "123467890123467890" - ), -] + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) +] # comment items = [ - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} # comment + if some_var == "long strings" + else {"key": "val"} + ) +] + +items = [ # comment + ( # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) ] items = [ ( - long_variable_name - and even_longer_variable_name - and yet_another_very_long_variable_name - ), -] + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) # comment +] # comment diff --git a/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py b/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py new file mode 100644 index 00000000000..2acdd8bfdec --- /dev/null +++ b/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py @@ -0,0 +1,246 @@ +# flags: --unstable +items = [(x for x in [1])] + +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) +] +items = [ + ( + {"key1": "val1", "key2": "val2"} + if some_var == "" + else {"key": "val"} + ) +] +items = [ + ( + "123456890123457890123468901234567890" + if some_var == "long strings" + else "123467890123467890" + ) +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} + ) +] +items = [ + ( + "123456890123457890123468901234567890" + and some_var == "long strings" + and "123467890123467890" + ) +] +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ) +] + +# Shouldn't remove trailing commas +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ), +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} + ), +] +items = [ + ( + "123456890123457890123468901234567890" + and some_var == "long strings" + and "123467890123467890" + ), +] +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ), +] + +# Shouldn't add parentheses +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] + +# Shouldn't crash with commas +items = [ + ( # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) # comment +] + +items = [ # comment + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) +] # comment + +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} # comment + if some_var == "long strings" + else {"key": "val"} + ) +] + +items = [ # comment + ( # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ) # comment +] # comment + + +# output +items = [(x for x in [1])] + +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] +items = [ + "123456890123457890123468901234567890" + if some_var == "long strings" + else "123467890123467890" +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} +] +items = [ + "123456890123457890123468901234567890" + and some_var == "long strings" + and "123467890123467890" +] +items = [ + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name +] + +# Shouldn't remove trailing commas +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} + ), +] +items = [ + ( + {"key1": "val1", "key2": "val2", "key3": "val3"} + and some_var == "long strings" + and {"key": "val"} + ), +] +items = [ + ( + "123456890123457890123468901234567890" + and some_var == "long strings" + and "123467890123467890" + ), +] +items = [ + ( + long_variable_name + and even_longer_variable_name + and yet_another_very_long_variable_name + ), +] + +# Shouldn't add parentheses +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] +items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] + +# Shouldn't crash with commas +items = [ # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] # comment + +items = [ # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] # comment + +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} # comment + if some_var == "long strings" + else {"key": "val"} +] + +items = [ # comment # comment + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] +items = [ + {"key1": "val1", "key2": "val2", "key3": "val3"} + if some_var == "long strings" + else {"key": "val"} +] # comment # comment From 84c059c1388d15dca4f629a89445a3e813f7f96e Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Sun, 24 Nov 2024 18:47:08 -0600 Subject: [PATCH 13/14] Finish PR I think hopefully Signed-off-by: cobalt <61329810+cobaltt7@users.noreply.github.com> --- src/black/linegen.py | 11 +++++++---- .../preview_remove_multiline_lone_list_item_parens.py | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/black/linegen.py b/src/black/linegen.py index a11e2465b83..a868c885218 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -1656,10 +1656,6 @@ def maybe_make_parens_invisible_in_atom( not is_type_ignore_comment_string(middle.prefix.strip()) ): first.value = "" - if first.prefix.strip(): - # Preserve comments before first paren - middle.prefix = first.prefix + middle.prefix - first.prefix = "" last.value = "" maybe_make_parens_invisible_in_atom( middle, @@ -1671,6 +1667,13 @@ def maybe_make_parens_invisible_in_atom( # Strip the invisible parens from `middle` by replacing # it with the child in-between the invisible parens middle.replace(middle.children[1]) + + if middle.children[0].prefix.strip(): + # Preserve comments before first paren + middle.children[1].prefix = ( + middle.children[0].prefix + middle.children[1].prefix + ) + if middle.children[-1].prefix.strip(): # Preserve comments before last paren last.prefix = middle.children[-1].prefix + last.prefix diff --git a/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py b/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py index 2acdd8bfdec..08563026245 100644 --- a/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py +++ b/tests/data/cases/preview_remove_multiline_lone_list_item_parens.py @@ -82,7 +82,7 @@ ] items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] -# Shouldn't crash with commas +# Shouldn't crash with comments items = [ ( # comment {"key1": "val1", "key2": "val2", "key3": "val3"} @@ -205,7 +205,7 @@ ] items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}] -# Shouldn't crash with commas +# Shouldn't crash with comments items = [ # comment {"key1": "val1", "key2": "val2", "key3": "val3"} if some_var == "long strings" From 3e34a4cc0ce355ab0e17304808ff617470f8afbd Mon Sep 17 00:00:00 2001 From: cobalt <61329810+cobaltt7@users.noreply.github.com> Date: Wed, 27 Nov 2024 17:41:09 -0600 Subject: [PATCH 14/14] Support sets Signed-off-by: cobalt <61329810+cobaltt7@users.noreply.github.com> --- src/black/linegen.py | 11 +++++++---- .../cases/preview_remove_lone_list_item_parens.py | 6 ++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/black/linegen.py b/src/black/linegen.py index a868c885218..7bd018d31af 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -512,11 +512,14 @@ def visit_atom(self, node: Node) -> Iterator[Line]: if ( Preview.remove_lone_list_item_parens in self.mode and len(node.children) == 3 - and node.children[0].type == token.LSQB - and node.children[-1].type == token.RSQB ): - # Lists of one item - maybe_make_parens_invisible_in_atom(node.children[1], parent=node) + first = node.children[0] + last = node.children[-1] + if (first.type == token.LSQB and last.type == token.RSQB) or ( + first.type == token.LBRACE and last.type == token.RBRACE + ): + # Lists or sets of one item + maybe_make_parens_invisible_in_atom(node.children[1], parent=node) yield from self.visit_default(node) diff --git a/tests/data/cases/preview_remove_lone_list_item_parens.py b/tests/data/cases/preview_remove_lone_list_item_parens.py index 4b296d29ea5..ad7058ba179 100644 --- a/tests/data/cases/preview_remove_lone_list_item_parens.py +++ b/tests/data/cases/preview_remove_lone_list_item_parens.py @@ -5,6 +5,9 @@ items = [(((((True,)))))] items = [((((()))))] items = [(x for x in [1])] +items = {(123)} +items = {(True)} +items = {(((((True)))))} # Requires `hug_parens_with_braces_and_square_brackets` unstable style to remove parentheses # around multiline values @@ -85,6 +88,9 @@ items = [(True,)] items = [()] items = [(x for x in [1])] +items = {123} +items = {True} +items = {True} # Requires `hug_parens_with_braces_and_square_brackets` unstable style to remove parentheses # around multiline values