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

Treat functions/classes in blocks as if they're nested #2472

Merged
merged 6 commits into from Dec 1, 2021
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 @@ -17,6 +17,7 @@
- Add `flake8-simplify` and `flake8-comprehensions` plugins (#2653)
- Fix determination of f-string expression spans (#2654)
- Fix parser error location on invalid syntax in a `match` statement (#2649)
- Functions and classes in blocks now have more consistent surrounding spacing (#2472)

## 21.11b1

Expand Down
24 changes: 22 additions & 2 deletions src/black/lines.py
Expand Up @@ -447,11 +447,31 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
before = 0
depth = current_line.depth
while self.previous_defs and self.previous_defs[-1] >= depth:
self.previous_defs.pop()
if self.is_pyi:
before = 0 if depth else 1
else:
before = 1 if depth else 2
if depth:
before = 1
elif (
not depth
and self.previous_defs[-1]
and current_line.leaves[-1].type == token.COLON
and (
current_line.leaves[0].value
not in ("with", "try", "for", "while", "if", "match")
)
):
# We shouldn't add two newlines between an indented function and
# a dependent non-indented clause. This is to avoid issues with
# conditional function definitions that are technically top-level
# and therefore get two trailing newlines, but look weird and
# inconsistent when they're followed by elif, else, etc. This is
# worse because these functions only get *one* preceding newline
# already.
before = 1
else:
before = 2
self.previous_defs.pop()
if current_line.is_decorator or current_line.is_def or current_line.is_class:
return self._maybe_empty_lines_for_class_or_def(current_line, before)

Expand Down
2 changes: 1 addition & 1 deletion src/black_primer/primer.json
Expand Up @@ -116,7 +116,7 @@
},
"pyanalyze": {
"cli_arguments": ["--experimental-string-processing"],
"expect_formatting_changes": false,
"expect_formatting_changes": true,
"git_clone_url": "https://github.com/quora/pyanalyze.git",
"long_checkout": false,
"py_versions": ["all"]
Expand Down
63 changes: 63 additions & 0 deletions tests/data/function2.py
Expand Up @@ -23,6 +23,35 @@ def inner():
pass
print("Inner defs should breathe a little.")


if os.name == "posix":
import termios
def i_should_be_followed_by_only_one_newline():
pass
elif os.name == "nt":
try:
import msvcrt
def i_should_be_followed_by_only_one_newline():
pass

except ImportError:

def i_should_be_followed_by_only_one_newline():
pass

elif False:

class IHopeYouAreHavingALovelyDay:
def __call__(self):
print("i_should_be_followed_by_only_one_newline")
else:

def foo():
pass

with hmm_but_this_should_get_two_preceding_newlines():
pass

# output

def f(
Expand Down Expand Up @@ -56,3 +85,37 @@ def inner():
pass

print("Inner defs should breathe a little.")


if os.name == "posix":
import termios

def i_should_be_followed_by_only_one_newline():
pass

elif os.name == "nt":
try:
import msvcrt

def i_should_be_followed_by_only_one_newline():
pass

except ImportError:

def i_should_be_followed_by_only_one_newline():
pass

elif False:

class IHopeYouAreHavingALovelyDay:
def __call__(self):
print("i_should_be_followed_by_only_one_newline")

else:

def foo():
pass


with hmm_but_this_should_get_two_preceding_newlines():
pass