### 18.3a3
+* don't remove single empty lines outside of bracketed expressions
+ (#19)
+
* added ability to pipe formatting from stdin to stdin (#25)
* restored ability to format code with legacy usage of `async` as
def visit_default(self, node: LN) -> Iterator[Line]:
if isinstance(node, Leaf):
+ any_open_brackets = self.current_line.bracket_tracker.any_open_brackets()
for comment in generate_comments(node):
- if self.current_line.bracket_tracker.any_open_brackets():
+ if any_open_brackets:
# any comment within brackets is subject to splitting
self.current_line.append(comment)
elif comment.type == token.COMMENT:
# regular standalone comment, to be processed later (see
# docstring in `generate_comments()`
self.standalone_comments.append(comment)
- normalize_prefix(node)
+ normalize_prefix(node, inside_brackets=any_open_brackets)
if node.type not in WHITESPACE:
for comment in self.standalone_comments:
yield from self.line()
current_leaves = body_leaves
# Since body is a new indent level, remove spurious leading whitespace.
if body_leaves:
- normalize_prefix(body_leaves[0])
+ normalize_prefix(body_leaves[0], inside_brackets=True)
# Build the new lines.
for result, leaves in (
(head, head_leaves), (body, body_leaves), (tail, tail_leaves)
head_leaves.reverse()
# Since body is a new indent level, remove spurious leading whitespace.
if body_leaves:
- normalize_prefix(body_leaves[0])
+ normalize_prefix(body_leaves[0], inside_brackets=True)
# Build the new lines.
for result, leaves in (
(head, head_leaves), (body, body_leaves), (tail, tail_leaves)
trailing_comma_safe = trailing_comma_safe and py36
leaf_priority = delimiters.get(id(leaf))
if leaf_priority == delimiter_priority:
- normalize_prefix(current_line.leaves[0])
+ normalize_prefix(current_line.leaves[0], inside_brackets=True)
yield current_line
current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets)
and trailing_comma_safe
):
current_line.append(Leaf(token.COMMA, ','))
- normalize_prefix(current_line.leaves[0])
+ normalize_prefix(current_line.leaves[0], inside_brackets=True)
yield current_line
)
-def normalize_prefix(leaf: Leaf) -> None:
- """Leave existing extra newlines for imports. Remove everything else."""
- if is_import(leaf):
+def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None:
+ """Leave existing extra newlines if not `inside_brackets`.
+
+ Remove everything else. Note: don't use backslashes for formatting or
+ you'll lose your voting rights.
+ """
+ if not inside_brackets:
spl = leaf.prefix.split('#', 1)
- nl_count = spl[0].count('\n')
- leaf.prefix = '\n' * nl_count
- return
+ if '\\' not in spl[0]:
+ nl_count = spl[0].count('\n')
+ leaf.prefix = '\n' * nl_count
+ return
leaf.prefix = ''
""",
arg3=True,
)
+
############################################################################
call2(
# short
--- /dev/null
+def f():
+ NO = ''
+ SPACE = ' '
+ DOUBLESPACE = ' '
+
+ t = leaf.type
+ p = leaf.parent # trailing comment
+ v = leaf.value
+
+ if t in ALWAYS_NO_SPACE:
+ pass
+ if t == token.COMMENT: # another trailing comment
+ return DOUBLESPACE
+
+ assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
+
+ prev = leaf.prev_sibling
+ if not prev:
+ prevp = preceding_leaf(p)
+ if not prevp or prevp.type in OPENING_BRACKETS:
+
+ return NO
+
+ if prevp.type == token.EQUAL:
+ if prevp.parent and prevp.parent.type in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.argument,
+ }:
+ return NO
+
+ elif prevp.type == token.DOUBLESTAR:
+ if prevp.parent and prevp.parent.type in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.dictsetmaker,
+ }:
+ return NO
+
+
+###############################################################################
+# SECTION BECAUSE SECTIONS
+###############################################################################
+
+
+def g():
+ NO = ''
+ SPACE = ' '
+ DOUBLESPACE = ' '
+
+ t = leaf.type
+ p = leaf.parent
+ v = leaf.value
+
+ # Comment because comments
+
+ if t in ALWAYS_NO_SPACE:
+ pass
+ if t == token.COMMENT:
+ return DOUBLESPACE
+
+ # Another comment because more comments
+ assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
+
+ prev = leaf.prev_sibling
+ if not prev:
+ prevp = preceding_leaf(p)
+
+ if not prevp or prevp.type in OPENING_BRACKETS:
+ # Start of the line or a bracketed expression.
+ # More than one line for the comment.
+ return NO
+
+ if prevp.type == token.EQUAL:
+ if prevp.parent and prevp.parent.type in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.argument,
+ }:
+ return NO
+
+
+# output
+
+
+def f():
+ NO = ''
+ SPACE = ' '
+ DOUBLESPACE = ' '
+
+ t = leaf.type
+ p = leaf.parent # trailing comment
+ v = leaf.value
+
+ if t in ALWAYS_NO_SPACE:
+ pass
+ if t == token.COMMENT: # another trailing comment
+ return DOUBLESPACE
+
+ assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
+
+ prev = leaf.prev_sibling
+ if not prev:
+ prevp = preceding_leaf(p)
+ if not prevp or prevp.type in OPENING_BRACKETS:
+ return NO
+
+ if prevp.type == token.EQUAL:
+ if prevp.parent and prevp.parent.type in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.argument,
+ }:
+ return NO
+
+ elif prevp.type == token.DOUBLESTAR:
+ if prevp.parent and prevp.parent.type in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.dictsetmaker,
+ }:
+ return NO
+
+
+###############################################################################
+# SECTION BECAUSE SECTIONS
+###############################################################################
+def g():
+ NO = ''
+ SPACE = ' '
+ DOUBLESPACE = ' '
+
+ t = leaf.type
+ p = leaf.parent
+ v = leaf.value
+
+ # Comment because comments
+ if t in ALWAYS_NO_SPACE:
+ pass
+ if t == token.COMMENT:
+ return DOUBLESPACE
+
+ # Another comment because more comments
+ assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
+
+ prev = leaf.prev_sibling
+ if not prev:
+ prevp = preceding_leaf(p)
+
+ if not prevp or prevp.type in OPENING_BRACKETS:
+ # Start of the line or a bracketed expression.
+ # More than one line for the comment.
+ return NO
+
+ if prevp.type == token.EQUAL:
+ if prevp.parent and prevp.parent.type in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.argument,
+ }:
+ return NO
black.assert_equivalent(source, actual)
black.assert_stable(source, actual, line_length=ll)
+ @patch("black.dump_to_file", dump_to_stderr)
+ def test_empty_lines(self) -> None:
+ source, expected = read_data('empty_lines')
+ actual = fs(source)
+ self.assertFormatEqual(expected, actual)
+ black.assert_equivalent(source, actual)
+ black.assert_stable(source, actual, line_length=ll)
+
def test_report(self) -> None:
report = black.Report()
out_lines = []