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

fix: Remove parenthesis around sole list items #4312

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@

<!-- Changes that affect Black's 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

<!-- Changes to how Black can be configured -->
Expand Down
53 changes: 51 additions & 2 deletions docs/the_black_code_style/future_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -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))
- `concise_nested_brackets`: more compact formatting of nested brackets
([see below](labels/hug-parens))

(labels/hug-parens)=

Expand Down Expand Up @@ -124,6 +124,55 @@ foo(
)
```

Parenthesises around sole list items will also be removed for similar reasons. Trailing
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Parenthesises around sole list items will also be removed for similar reasons. Trailing
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 changed to:

```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
),
]
```

(labels/string-processing)=

### Improved string processing
Expand Down
15 changes: 14 additions & 1 deletion src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,19 @@ def visit_NUMBER(self, leaf: Leaf) -> Iterator[Line]:
normalize_numeric_literal(leaf)
yield from self.visit_default(leaf)

def visit_atom(self, node: Node) -> Iterator[Line]:
"""Visit any atom"""
if (
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
):
# Lists of one item
maybe_make_parens_invisible_in_atom(node.children[1], parent=node)

yield from self.visit_default(node)

def visit_fstring(self, node: Node) -> Iterator[Line]:
# currently we don't want to format and split f-strings at all.
string_leaf = fstring_to_string(node)
Expand Down Expand Up @@ -855,7 +868,7 @@ def _first_right_hand_split(

body: Optional[Line] = None
if (
Preview.hug_parens_with_braces_and_square_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]
):
Expand Down
4 changes: 2 additions & 2 deletions src/black/mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
hug_parens_with_braces_and_square_brackets = auto()
concise_nested_brackets = auto()
unify_docstring_detection = auto()
no_normalize_fmt_skip_whitespace = auto()
wrap_long_dict_values_in_parens = auto()
Expand All @@ -193,7 +193,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.concise_nested_brackets,
}


Expand Down
2 changes: 1 addition & 1 deletion src/black/resources/black.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"enum": [
"hex_codes_in_unicode_sequences",
"string_processing",
"hug_parens_with_braces_and_square_brackets",
"concise_nested_brackets",
"unify_docstring_detection",
"no_normalize_fmt_skip_whitespace",
"wrap_long_dict_values_in_parens",
Expand Down
168 changes: 168 additions & 0 deletions tests/data/cases/preview_remove_sole_list_item_parens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# flags: --unstable
items = [(123)]
items = [(True)]
items = [(((((True)))))]
items = [(((((True,)))))]
items = [((((()))))]

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 = [123]
items = [True]
items = [True]
items = [(True,)]
items = [()]

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
),
]