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

Allow empty line after block open before a comment or compound statement #3967

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Expand Up @@ -13,6 +13,7 @@
### Preview style

- Fix merging implicit multiline strings that have inline comments (#3956)
- Allow empty first line after block open before a comment or compound statement (#3967)

### Configuration

Expand Down
27 changes: 26 additions & 1 deletion src/black/lines.py
Expand Up @@ -24,6 +24,8 @@
STANDALONE_COMMENT,
TEST_DESCENDANTS,
child_towards,
is_docstring,
is_funcdef,
is_import,
is_multiline_string,
is_one_sequence_between,
Expand Down Expand Up @@ -686,7 +688,30 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
return 0, 1
return before, 1

if self.previous_line and self.previous_line.opens_block:
is_empty_first_line_ok = (
Preview.allow_empty_first_line_before_new_block_or_comment
in current_line.mode
and (
# If it's a standalone comment
current_line.leaves[0].type == STANDALONE_COMMENT
# If it opens a new block
or current_line.opens_block
# If it's a triple quote comment (but not at the start of a funcdef)
or (
is_docstring(current_line.leaves[0])
and self.previous_line
and self.previous_line.leaves[0]
and self.previous_line.leaves[0].parent
and not is_funcdef(self.previous_line.leaves[0].parent)
)
)
)

if (
self.previous_line
and self.previous_line.opens_block
and not is_empty_first_line_ok
):
return 0, 0
return before, 0

Expand Down
1 change: 1 addition & 0 deletions src/black/mode.py
Expand Up @@ -190,6 +190,7 @@ class Preview(Enum):
module_docstring_newlines = auto()
accept_raw_docstrings = auto()
fix_power_op_line_length = auto()
allow_empty_first_line_before_new_block_or_comment = auto()


class Deprecated(UserWarning):
Expand Down
4 changes: 4 additions & 0 deletions src/black/nodes.py
Expand Up @@ -718,6 +718,10 @@ def is_multiline_string(leaf: Leaf) -> bool:
return has_triple_quotes(leaf.value) and "\n" in leaf.value


def is_funcdef(node: Node) -> bool:
return node.type == syms.funcdef


def is_stub_suite(node: Node) -> bool:
"""Return True if `node` is a suite with a stub body."""

Expand Down
106 changes: 106 additions & 0 deletions tests/data/cases/preview_allow_empty_first_line_in_special_cases.py
@@ -0,0 +1,106 @@
# flags: --preview
def foo():
"""
Docstring
"""

# Here we go
if x:

# This is also now fine
a = 123

else:
# But not necessary
a = 123

if y:

while True:

"""
Long comment here
"""
a = 123

if z:

for _ in range(100):
a = 123
else:

try:

# this should be ok
a = 123
except:

"""also this"""
a = 123


def bar():

if x:
a = 123


def baz():

# OK
if x:
a = 123

# output

def foo():
"""
Docstring
"""

# Here we go
if x:

# This is also now fine
a = 123

else:
# But not necessary
a = 123

if y:

while True:

"""
Long comment here
"""
a = 123

if z:

for _ in range(100):
a = 123
else:

try:

# this should be ok
a = 123
except:

"""also this"""
a = 123


def bar():

if x:
a = 123


def baz():

# OK
if x:
a = 123