### 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 = []