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 18 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

<!-- Changes that affect Black's preview style -->

- Remove parentheses around sole list items (#4312)

### Configuration

<!-- Changes to how Black can be configured -->
Expand Down
3 changes: 3 additions & 0 deletions docs/the_black_code_style/future_style.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ 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 parentheses around lone list items
(depends on unstable `hug_parens_with_braces_and_square_brackets` feature in some
cases)

(labels/unstable-features)=

Expand Down
14 changes: 14 additions & 0 deletions src/black/linegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,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.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)

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 @@ -1646,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,
Expand Down
3 changes: 3 additions & 0 deletions src/black/mode.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,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()
pep646_typed_star_arg_type_var_tuple = auto()


Expand Down
1 change: 1 addition & 0 deletions src/black/resources/black.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
"docstring_check_for_newline",
"remove_redundant_guard_parens",
"parens_for_long_if_clauses_in_case_block",
"remove_lone_list_item_parens",
"pep646_typed_star_arg_type_var_tuple"
]
},
Expand Down
152 changes: 152 additions & 0 deletions tests/data/cases/preview_remove_lone_list_item_parens.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
# flags: --preview
items = [(123)]
cobaltt7 marked this conversation as resolved.
Show resolved Hide resolved
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"}
if some_var == "long strings"
else {"key": "val"}
)
]
items = [
(
{"key1": "val1", "key2": "val2"}
if some_var == ""
else {"key": "val"}
)
]

# Comments should not cause crashes
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 = [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"}
if some_var == "long strings"
else {"key": "val"}
)
]
items = [{"key1": "val1", "key2": "val2"} if some_var == "" else {"key": "val"}]

# Comments should not cause crashes
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
Loading
Loading