```py3
# in:
-l = [[n for n in list_bosses()], [n for n in list_employees()]]
+TracebackException.from_exception(exc, limit, lookup_lines, capture_locals)
# out:
-l = [
- [n for n in list_bosses()], [n for n in list_employees()]
-]
+TracebackException.from_exception(
+ exc, limit, lookup_lines, capture_locals
+)
```
If that still doesn't fit the bill, it will decompose the internal
indentation level (like the arguments list and the docstring in the
example above).
-If a line of "from" imports cannot fit in the allotted length, it's always split
-into one per line. Imports tend to change often and this minimizes diffs, as well
-as enables readers of code to easily find which commit introduced a particular
-import. This exception also makes *Black* compatible with
-[isort](https://pypi.org/p/isort/). Use `multi_line_output=3`,
-`include_trailing_comma=True`, `force_grid_wrap=0`, and `line_length=88` in your
-isort config.
+If a data structure literal (tuple, list, set, dict) or a line of "from"
+imports cannot fit in the allotted length, it's always split into one
+per line. This minimizes diffs as well as enables readers of code to
+find which commit introduced a particular entry. This also makes
+*Black* compatible with [isort](https://pypi.org/p/isort/). Use
+`multi_line_output=3`, `include_trailing_comma=True`,
+`force_grid_wrap=0`, and `line_length=88` in your isort config.
### Line length
### 18.5a0 (unreleased)
-* call chains are now formatted according to the [fluent interfaces](https://en.wikipedia.org/wiki/Fluent_interface) style (#67)
+* call chains are now formatted according to the
+ [fluent interfaces](https://en.wikipedia.org/wiki/Fluent_interface)
+ style (#67)
+
+* data structure literals (tuples, lists, dictionaries, and sets) are
+ now also always exploded like imports when they don't fit in a single
+ line (#152)
* slices are now formatted according to PEP 8 (#178)
comments: List[Tuple[Index, Leaf]] = Factory(list)
bracket_tracker: BracketTracker = Factory(BracketTracker)
inside_brackets: bool = False
+ should_explode: bool = False
def append(self, leaf: Leaf, preformatted: bool = False) -> None:
"""Add a new `leaf` to the end of the line.
assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
if t == token.COLON and p.type not in {
- syms.subscript, syms.subscriptlist, syms.sliceop
+ syms.subscript,
+ syms.subscriptlist,
+ syms.sliceop,
}:
return NO
if prevp.type == token.EQUAL:
if prevp.parent:
if prevp.parent.type in {
- syms.arglist, syms.argument, syms.parameters, syms.varargslist
+ syms.arglist,
+ syms.argument,
+ syms.parameters,
+ syms.varargslist,
}:
return NO
prevp_parent = prevp.parent
assert prevp_parent is not None
if prevp.type == token.COLON and prevp_parent.type in {
- syms.subscript, syms.sliceop
+ syms.subscript,
+ syms.sliceop,
}:
return NO
return
line_str = str(line).strip("\n")
- if is_line_short_enough(line, line_length=line_length, line_str=line_str):
+ if not line.should_explode and is_line_short_enough(
+ line, line_length=line_length, line_str=line_str
+ ):
yield line
return
split_funcs: List[SplitFunc]
if line.is_def:
split_funcs = [left_hand_split]
- elif line.is_import:
- split_funcs = [explode_split]
else:
def rhs(line: Line, py36: bool = False) -> Iterator[Line]:
ensure_visible(opening_bracket)
ensure_visible(closing_bracket)
+ body.should_explode = should_explode(body, opening_bracket)
for result in (head, body, tail):
if result:
yield result
yield current_line
-def explode_split(
- line: Line, py36: bool = False, omit: Collection[LeafID] = ()
-) -> Iterator[Line]:
- """Split by rightmost bracket and immediately split contents by a delimiter."""
- new_lines = list(right_hand_split(line, py36, omit))
- if len(new_lines) != 3:
- yield from new_lines
- return
-
- yield new_lines[0]
-
- try:
- yield from delimiter_split(new_lines[1], py36)
-
- except CannotSplit:
- yield new_lines[1]
-
- yield new_lines[2]
-
-
def is_import(leaf: Leaf) -> bool:
"""Return True if the given leaf starts an import statement."""
p = leaf.parent
leaf.value = ")"
+def should_explode(line: Line, opening_bracket: Leaf) -> bool:
+ """Should `line` immediately be split with `delimiter_split()` after RHS?"""
+ return bool(
+ opening_bracket.parent
+ and opening_bracket.parent.type in {syms.atom, syms.import_from}
+ and opening_bracket.value in "[{("
+ and line.bracket_tracker.delimiters
+ and line.bracket_tracker.max_delimiter_priority() == COMMA_PRIORITY
+ )
+
+
def is_python36(node: Node) -> bool:
"""Return True if the current file is using Python 3.6+ features.
PYTHON_EXTENSIONS = {".py", ".pyi"}
BLACKLISTED_DIRECTORIES = {
- "build", "buck-out", "dist", "_build", ".git", ".hg", ".mypy_cache", ".tox", ".venv"
+ "build",
+ "buck-out",
+ "dist",
+ "_build",
+ ".git",
+ ".hg",
+ ".mypy_cache",
+ ".tox",
+ ".venv",
}
.. autofunction:: black.delimiter_split
-.. autofunction:: black.explode_split
-
.. autofunction:: black.left_hand_split
.. autofunction:: black.right_hand_split
1
) # with a comment
this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = [
- 1, 2, 3
+ 1,
+ 2,
+ 3,
]
this_is_a_ridiculously_long_name_and_nobody_in_their_right_mind_would_use_one_like_it = (
function()
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
parameters.children = [
- parameters.children[0], # (1
+ children[0], # (1
body,
- parameters.children[-1], # )1
+ children[-1], # )1
]
else:
parameters.children = [
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
- parameters.children = [
- parameters.children[0], body, parameters.children[-1] # (1 # )1
- ]
+ parameters.children = [children[0], body, children[-1]] # (1 # )1
else:
parameters.children = [
parameters.children[0], # (2 what if this was actually long
True
False
1
-@@ -29,62 +29,82 @@
+@@ -29,62 +29,83 @@
~great
+value
-1
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
-foo = (lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[port_id])
+foo = lambda port_id, ignore_missing: {
-+ "port1": port1_resource, "port2": port2_resource
++ "port1": port1_resource,
++ "port2": port2_resource,
+}[port_id]
1 if True else 2
str or None if True else str or bytes or None
call(**self.screen_kwargs)
call(b, **self.screen_kwargs)
lukasz.langa.pl
-@@ -93,11 +113,11 @@
+@@ -93,11 +114,11 @@
1.0 .real
....__class__
list[str]
]
slice[0]
slice[0:1]
-@@ -124,107 +144,159 @@
+@@ -124,107 +145,159 @@
numpy[-(c + 1) :, d]
numpy[:, l[-2]]
numpy[:, ::-1]
lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
foo = lambda port_id, ignore_missing: {
- "port1": port1_resource, "port2": port2_resource
+ "port1": port1_resource,
+ "port2": port2_resource,
}[port_id]
1 if True else 2
str or None if True else str or bytes or None