Handle more huggable immediately nested parens/brackets. (#4012)
Fixes #4011
This commit is contained in:
parent
d93a942a79
commit
11da02da72
@ -14,6 +14,9 @@
|
|||||||
|
|
||||||
<!-- Changes that affect Black's preview style -->
|
<!-- Changes that affect Black's preview style -->
|
||||||
|
|
||||||
|
- Additional cases of immediately nested tuples, lists, and dictionaries are now
|
||||||
|
indented less (#4012)
|
||||||
|
|
||||||
### Configuration
|
### Configuration
|
||||||
|
|
||||||
<!-- Changes to how Black can be configured -->
|
<!-- Changes to how Black can be configured -->
|
||||||
|
12
docs/conf.py
12
docs/conf.py
@ -149,15 +149,13 @@ def make_pypi_svg(version: str) -> None:
|
|||||||
# Grouping the document tree into LaTeX files. List of tuples
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
# (source start file, target name, title,
|
# (source start file, target name, title,
|
||||||
# author, documentclass [howto, manual, or own class]).
|
# author, documentclass [howto, manual, or own class]).
|
||||||
latex_documents = [
|
latex_documents = [(
|
||||||
(
|
|
||||||
master_doc,
|
master_doc,
|
||||||
"black.tex",
|
"black.tex",
|
||||||
"Documentation for Black",
|
"Documentation for Black",
|
||||||
"Łukasz Langa and contributors to Black",
|
"Łukasz Langa and contributors to Black",
|
||||||
"manual",
|
"manual",
|
||||||
)
|
)]
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for manual page output ------------------------------------------
|
# -- Options for manual page output ------------------------------------------
|
||||||
@ -172,8 +170,7 @@ def make_pypi_svg(version: str) -> None:
|
|||||||
# Grouping the document tree into Texinfo files. List of tuples
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
# (source start file, target name, title, author,
|
# (source start file, target name, title, author,
|
||||||
# dir menu entry, description, category)
|
# dir menu entry, description, category)
|
||||||
texinfo_documents = [
|
texinfo_documents = [(
|
||||||
(
|
|
||||||
master_doc,
|
master_doc,
|
||||||
"Black",
|
"Black",
|
||||||
"Documentation for Black",
|
"Documentation for Black",
|
||||||
@ -181,8 +178,7 @@ def make_pypi_svg(version: str) -> None:
|
|||||||
"Black",
|
"Black",
|
||||||
"The uncompromising Python code formatter",
|
"The uncompromising Python code formatter",
|
||||||
"Miscellaneous",
|
"Miscellaneous",
|
||||||
)
|
)]
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
# -- Options for Epub output -------------------------------------------------
|
# -- Options for Epub output -------------------------------------------------
|
||||||
|
@ -116,8 +116,7 @@ my_dict = {
|
|||||||
### Improved multiline dictionary and list indentation for sole function parameter
|
### Improved multiline dictionary and list indentation for sole function parameter
|
||||||
|
|
||||||
For better readability and less verticality, _Black_ now pairs parentheses ("(", ")")
|
For better readability and less verticality, _Black_ now pairs parentheses ("(", ")")
|
||||||
with braces ("{", "}") and square brackets ("[", "]") on the same line for single
|
with braces ("{", "}") and square brackets ("[", "]") on the same line. For example:
|
||||||
parameter function calls. For example:
|
|
||||||
|
|
||||||
```python
|
```python
|
||||||
foo(
|
foo(
|
||||||
@ -127,6 +126,14 @@ foo(
|
|||||||
3,
|
3,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
nested_array = [
|
||||||
|
[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
]
|
||||||
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
will be changed to:
|
will be changed to:
|
||||||
@ -137,6 +144,12 @@ foo([
|
|||||||
2,
|
2,
|
||||||
3,
|
3,
|
||||||
])
|
])
|
||||||
|
|
||||||
|
nested_array = [[
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
]]
|
||||||
```
|
```
|
||||||
|
|
||||||
This also applies to list and dictionary unpacking:
|
This also applies to list and dictionary unpacking:
|
||||||
|
@ -124,9 +124,9 @@ def filtered_cached(self, sources: Iterable[Path]) -> Tuple[Set[Path], Set[Path]
|
|||||||
|
|
||||||
def write(self, sources: Iterable[Path]) -> None:
|
def write(self, sources: Iterable[Path]) -> None:
|
||||||
"""Update the cache file data and write a new cache file."""
|
"""Update the cache file data and write a new cache file."""
|
||||||
self.file_data.update(**{
|
self.file_data.update(
|
||||||
str(src.resolve()): Cache.get_file_data(src) for src in sources
|
**{str(src.resolve()): Cache.get_file_data(src) for src in sources}
|
||||||
})
|
)
|
||||||
try:
|
try:
|
||||||
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
CACHE_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
with tempfile.NamedTemporaryFile(
|
with tempfile.NamedTemporaryFile(
|
||||||
|
@ -17,16 +17,13 @@
|
|||||||
from black.output import out
|
from black.output import out
|
||||||
from black.report import NothingChanged
|
from black.report import NothingChanged
|
||||||
|
|
||||||
TRANSFORMED_MAGICS = frozenset(
|
TRANSFORMED_MAGICS = frozenset((
|
||||||
(
|
|
||||||
"get_ipython().run_cell_magic",
|
"get_ipython().run_cell_magic",
|
||||||
"get_ipython().system",
|
"get_ipython().system",
|
||||||
"get_ipython().getoutput",
|
"get_ipython().getoutput",
|
||||||
"get_ipython().run_line_magic",
|
"get_ipython().run_line_magic",
|
||||||
)
|
))
|
||||||
)
|
TOKENS_TO_IGNORE = frozenset((
|
||||||
TOKENS_TO_IGNORE = frozenset(
|
|
||||||
(
|
|
||||||
"ENDMARKER",
|
"ENDMARKER",
|
||||||
"NL",
|
"NL",
|
||||||
"NEWLINE",
|
"NEWLINE",
|
||||||
@ -34,10 +31,8 @@
|
|||||||
"DEDENT",
|
"DEDENT",
|
||||||
"UNIMPORTANT_WS",
|
"UNIMPORTANT_WS",
|
||||||
"ESCAPED_NL",
|
"ESCAPED_NL",
|
||||||
)
|
))
|
||||||
)
|
PYTHON_CELL_MAGICS = frozenset((
|
||||||
PYTHON_CELL_MAGICS = frozenset(
|
|
||||||
(
|
|
||||||
"capture",
|
"capture",
|
||||||
"prun",
|
"prun",
|
||||||
"pypy",
|
"pypy",
|
||||||
@ -45,8 +40,7 @@
|
|||||||
"python3",
|
"python3",
|
||||||
"time",
|
"time",
|
||||||
"timeit",
|
"timeit",
|
||||||
)
|
))
|
||||||
)
|
|
||||||
TOKEN_HEX = secrets.token_hex
|
TOKEN_HEX = secrets.token_hex
|
||||||
|
|
||||||
|
|
||||||
|
@ -817,22 +817,63 @@ def _first_right_hand_split(
|
|||||||
body_leaves.reverse()
|
body_leaves.reverse()
|
||||||
head_leaves.reverse()
|
head_leaves.reverse()
|
||||||
|
|
||||||
if Preview.hug_parens_with_braces_and_square_brackets in line.mode:
|
body: Optional[Line] = None
|
||||||
is_unpacking = 1 if body_leaves[0].type in [token.STAR, token.DOUBLESTAR] else 0
|
|
||||||
if (
|
if (
|
||||||
tail_leaves[0].type == token.RPAR
|
Preview.hug_parens_with_braces_and_square_brackets in line.mode
|
||||||
and tail_leaves[0].value
|
and tail_leaves[0].value
|
||||||
and tail_leaves[0].opening_bracket is head_leaves[-1]
|
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[is_unpacking]
|
|
||||||
):
|
):
|
||||||
head_leaves = head_leaves + body_leaves[: 1 + is_unpacking]
|
inner_body_leaves = list(body_leaves)
|
||||||
tail_leaves = body_leaves[-1:] + tail_leaves
|
hugged_opening_leaves: List[Leaf] = []
|
||||||
body_leaves = body_leaves[1 + is_unpacking : -1]
|
hugged_closing_leaves: List[Leaf] = []
|
||||||
|
is_unpacking = body_leaves[0].type in [token.STAR, token.DOUBLESTAR]
|
||||||
|
unpacking_offset: int = 1 if is_unpacking else 0
|
||||||
|
while (
|
||||||
|
len(inner_body_leaves) >= 2 + unpacking_offset
|
||||||
|
and inner_body_leaves[-1].type in CLOSING_BRACKETS
|
||||||
|
and inner_body_leaves[-1].opening_bracket
|
||||||
|
is inner_body_leaves[unpacking_offset]
|
||||||
|
):
|
||||||
|
if unpacking_offset:
|
||||||
|
hugged_opening_leaves.append(inner_body_leaves.pop(0))
|
||||||
|
unpacking_offset = 0
|
||||||
|
hugged_opening_leaves.append(inner_body_leaves.pop(0))
|
||||||
|
hugged_closing_leaves.insert(0, inner_body_leaves.pop())
|
||||||
|
|
||||||
|
if hugged_opening_leaves and inner_body_leaves:
|
||||||
|
inner_body = bracket_split_build_line(
|
||||||
|
inner_body_leaves,
|
||||||
|
line,
|
||||||
|
hugged_opening_leaves[-1],
|
||||||
|
component=_BracketSplitComponent.body,
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
line.mode.magic_trailing_comma
|
||||||
|
and inner_body_leaves[-1].type == token.COMMA
|
||||||
|
):
|
||||||
|
should_hug = True
|
||||||
|
else:
|
||||||
|
line_length = line.mode.line_length - sum(
|
||||||
|
len(str(leaf))
|
||||||
|
for leaf in hugged_opening_leaves + hugged_closing_leaves
|
||||||
|
)
|
||||||
|
if is_line_short_enough(
|
||||||
|
inner_body, mode=replace(line.mode, line_length=line_length)
|
||||||
|
):
|
||||||
|
# Do not hug if it fits on a single line.
|
||||||
|
should_hug = False
|
||||||
|
else:
|
||||||
|
should_hug = True
|
||||||
|
if should_hug:
|
||||||
|
body_leaves = inner_body_leaves
|
||||||
|
head_leaves.extend(hugged_opening_leaves)
|
||||||
|
tail_leaves = hugged_closing_leaves + tail_leaves
|
||||||
|
body = inner_body # No need to re-calculate the body again later.
|
||||||
|
|
||||||
head = bracket_split_build_line(
|
head = bracket_split_build_line(
|
||||||
head_leaves, line, opening_bracket, component=_BracketSplitComponent.head
|
head_leaves, line, opening_bracket, component=_BracketSplitComponent.head
|
||||||
)
|
)
|
||||||
|
if body is None:
|
||||||
body = bracket_split_build_line(
|
body = bracket_split_build_line(
|
||||||
body_leaves, line, opening_bracket, component=_BracketSplitComponent.body
|
body_leaves, line, opening_bracket, component=_BracketSplitComponent.body
|
||||||
)
|
)
|
||||||
|
@ -128,6 +128,19 @@ def foo_square_brackets(request):
|
|||||||
func({"short 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"})
|
||||||
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"}})
|
||||||
|
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")))
|
||||||
|
func([["long line", "long long line", "long long long line", "long long long long line", "long long long long long line"]])
|
||||||
|
|
||||||
|
# Do not hug if the argument fits on a single line.
|
||||||
|
func({"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"})
|
||||||
|
func(("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"))
|
||||||
|
func(["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"])
|
||||||
|
func(**{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"})
|
||||||
|
func(*("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----"))
|
||||||
|
array = [{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}]
|
||||||
|
array = [("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")]
|
||||||
|
array = [["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]]
|
||||||
|
|
||||||
foooooooooooooooooooo(
|
foooooooooooooooooooo(
|
||||||
[{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size}
|
[{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size}
|
||||||
@ -137,6 +150,13 @@ def foo_square_brackets(request):
|
|||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
nested_mapping = {"key": [{"a very long key 1": "with a very long value", "a very long key 2": "with a very long value"}]}
|
||||||
|
nested_array = [[["long line", "long long line", "long long long line", "long long long long line", "long long long long long line"]]]
|
||||||
|
explicit_exploding = [[["short", "line",],],]
|
||||||
|
single_item_do_not_explode = Context({
|
||||||
|
"version": get_docs_version(),
|
||||||
|
})
|
||||||
|
|
||||||
foo(*["long long long long long line", "long long long long long line", "long long long long long line"])
|
foo(*["long long long long long line", "long long long long long line", "long long long long long line"])
|
||||||
|
|
||||||
foo(*[str(i) for i in range(100000000000000000000000000000000000000000000000000000000000)])
|
foo(*[str(i) for i in range(100000000000000000000000000000000000000000000000000000000000)])
|
||||||
@ -152,6 +172,9 @@ def foo_square_brackets(request):
|
|||||||
|
|
||||||
foo(**{x: y for x, y in enumerate(["long long long long line","long long long long line"])})
|
foo(**{x: y for x, y in enumerate(["long long long long line","long long long long line"])})
|
||||||
|
|
||||||
|
# Edge case when deciding whether to hug the brackets without inner content.
|
||||||
|
very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName([[]])
|
||||||
|
|
||||||
for foo in ["a", "b"]:
|
for foo in ["a", "b"]:
|
||||||
output.extend([
|
output.extend([
|
||||||
individual
|
individual
|
||||||
@ -276,9 +299,9 @@ def foo_square_brackets(request):
|
|||||||
)
|
)
|
||||||
|
|
||||||
func([x for x in "short line"])
|
func([x for x in "short line"])
|
||||||
func([
|
func(
|
||||||
x for x in "long line long line long line long line long line long line long line"
|
[x for x in "long line long line long line long line long line long line long line"]
|
||||||
])
|
)
|
||||||
func([
|
func([
|
||||||
x
|
x
|
||||||
for x in [
|
for x in [
|
||||||
@ -295,15 +318,60 @@ def foo_square_brackets(request):
|
|||||||
"long long long long line",
|
"long long long long line",
|
||||||
"long long long long long line",
|
"long long long long long line",
|
||||||
})
|
})
|
||||||
func({
|
func({{
|
||||||
{
|
|
||||||
"long line",
|
"long line",
|
||||||
"long long line",
|
"long long line",
|
||||||
"long long long line",
|
"long long long line",
|
||||||
"long long long long line",
|
"long long long long line",
|
||||||
"long 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",
|
||||||
|
))
|
||||||
|
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",
|
||||||
|
]])
|
||||||
|
|
||||||
|
# Do not hug if the argument fits on a single line.
|
||||||
|
func(
|
||||||
|
{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}
|
||||||
|
)
|
||||||
|
func(
|
||||||
|
("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")
|
||||||
|
)
|
||||||
|
func(
|
||||||
|
["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]
|
||||||
|
)
|
||||||
|
func(
|
||||||
|
**{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit---"}
|
||||||
|
)
|
||||||
|
func(
|
||||||
|
*("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit----")
|
||||||
|
)
|
||||||
|
array = [
|
||||||
|
{"fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"}
|
||||||
|
]
|
||||||
|
array = [
|
||||||
|
("fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line")
|
||||||
|
]
|
||||||
|
array = [
|
||||||
|
["fit line", "fit line", "fit line", "fit line", "fit line", "fit line", "fit line"]
|
||||||
|
]
|
||||||
|
|
||||||
foooooooooooooooooooo(
|
foooooooooooooooooooo(
|
||||||
[{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size}
|
[{c: n + 1 for c in range(256)} for n in range(100)] + [{}], {size}
|
||||||
@ -313,6 +381,31 @@ def foo_square_brackets(request):
|
|||||||
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], {x}, "a string", [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
nested_mapping = {
|
||||||
|
"key": [{
|
||||||
|
"a very long key 1": "with a very long value",
|
||||||
|
"a very long key 2": "with a very long value",
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
nested_array = [[[
|
||||||
|
"long line",
|
||||||
|
"long long line",
|
||||||
|
"long long long line",
|
||||||
|
"long long long long line",
|
||||||
|
"long long long long long line",
|
||||||
|
]]]
|
||||||
|
explicit_exploding = [
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"short",
|
||||||
|
"line",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
]
|
||||||
|
single_item_do_not_explode = Context({
|
||||||
|
"version": get_docs_version(),
|
||||||
|
})
|
||||||
|
|
||||||
foo(*[
|
foo(*[
|
||||||
"long long long long long line",
|
"long long long long long line",
|
||||||
"long long long long long line",
|
"long long long long long line",
|
||||||
@ -334,6 +427,11 @@ def foo_square_brackets(request):
|
|||||||
x: y for x, y in enumerate(["long long long long line", "long long long long line"])
|
x: y for x, y in enumerate(["long long long long line", "long long long long line"])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Edge case when deciding whether to hug the brackets without inner content.
|
||||||
|
very_very_very_long_variable = very_very_very_long_module.VeryVeryVeryVeryLongClassName(
|
||||||
|
[[]]
|
||||||
|
)
|
||||||
|
|
||||||
for foo in ["a", "b"]:
|
for foo in ["a", "b"]:
|
||||||
output.extend([
|
output.extend([
|
||||||
individual
|
individual
|
||||||
|
@ -611,14 +611,13 @@ def foo():
|
|||||||
|
|
||||||
class A:
|
class A:
|
||||||
def foo():
|
def foo():
|
||||||
XXXXXXXXXXXX.append(
|
XXXXXXXXXXXX.append((
|
||||||
(
|
"xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})".format(
|
||||||
"xxx_xxxxxxxxxx(xxxxx={}, xxxx={}, xxxxx, xxxx_xxxx_xxxxxxxxxx={})"
|
xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx
|
||||||
.format(xxxxx, xxxx, xxxx_xxxx_xxxxxxxxxx),
|
),
|
||||||
my_var,
|
my_var,
|
||||||
my_other_var,
|
my_other_var,
|
||||||
)
|
))
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class A:
|
class A:
|
||||||
|
Loading…
Reference in New Issue
Block a user