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 15 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
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

- 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)
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
- Remove parenthesis around sole list items (#4312)
- Remove parentheses around sole list items (#4312)


### Caching

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 parenthesis around lone list items
(depends on unstable `hug_parens_with_braces_and_square_brackets` feature in some
cases)

(labels/unstable-features)=

Expand Down
13 changes: 13 additions & 0 deletions 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.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
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
156 changes: 156 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,156 @@
# flags: --unstable
items = [(123)]
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a test containing a generator expression, to make sure we don't turn it into a listcomp:

>>> [(x for x in [1])]
[<generator object <genexpr> at 0x104277400>]
>>> [x for x in [1]]
[1]

Also add tests with comments in various places (e.g., after the opening paren, before the closing paren). Such cases tend to expose bugs in Black.

items = [(True)]
items = [(((((True)))))]
items = [(((((True,)))))]
items = [((((()))))]

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

items = [
(
{"key1": "val1", "key2": "val2", "key3": "val3"}
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 == "long strings"
and "123467890123467890"
)
]
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
)
]
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 == "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", "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"
]

items = [
{"key1": "val1", "key2": "val2", "key3": "val3"}
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 == "long strings"
and "123467890123467890"
]
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
]
items = [
(
long_variable_name
and even_longer_variable_name
and yet_another_very_long_variable_name
),
]
Loading