From 895695b87cf0e953ffd42d715efba8a31e3ae4fc Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Thu, 2 Sep 2021 13:45:46 -0400 Subject: [PATCH 1/4] Treat functions/classes in blocks as if they're nested One curveball is that we still want two preceding newlines before blocks that are probably logically disconnected. In other words: if condition: def foo(): return "hi" # <- aside: this is the goal of this commit else: def foo(): return "cya" # <- the two newlines spacing here should stay # since this probably isn't related with open("db.json", encoding="utf-8") as f: data = f.read() Unfortunately that means we have to special case specific clause types instead of just being able to just for a colon leaf. The hack used here is to check whether we're adding preceding newlines for a standalone or dependent clause. "Standalone" being a clause that doesn't need another clause to be valid (eg. if) and vice versa. --- CHANGES.md | 4 +++ src/black/lines.py | 23 +++++++++++++-- tests/data/function2.py | 63 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 2 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ef0a57d6142..0d9ffb20729 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,10 @@ ## Unreleased +### _Black_ + +- Functions and classes in blocks now have more consistent surrounding spacing (#2472) + ### Packaging - Fix missing modules in self-contained binaries (#2466) diff --git a/src/black/lines.py b/src/black/lines.py index 63225c0e6d3..67ac0c02e68 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -447,11 +447,30 @@ 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") + ) + ): + # We shouldn't add two newlines between an indented function and + # 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 + # worsen by that these functions only get *one* preceding 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) diff --git a/tests/data/function2.py b/tests/data/function2.py index cfc259ea7bd..5bb36c26318 100644 --- a/tests/data/function2.py +++ b/tests/data/function2.py @@ -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( @@ -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 From fe9d927f8cb54ee017117671f0a54e7dc80e09ae Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Sat, 25 Sep 2021 18:56:06 -0400 Subject: [PATCH 2/4] Minor edits to comment Co-authored-by: Jelle Zijlstra --- src/black/lines.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/black/lines.py b/src/black/lines.py index 67ac0c02e68..9ca34c7cceb 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -462,11 +462,12 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: ) ): # We shouldn't add two newlines between an indented function and - # and a dependent non-indented clause. This is to avoid issues with + # 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 - # worsen by that these functions only get *one* preceding already. + # worse because these functions only get *one* preceding newline + # already. before = 1 else: before = 2 From 4f81c1d8f5f869778562d444e3950bc6fc23377f Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Wed, 1 Dec 2021 16:22:59 -0500 Subject: [PATCH 3/4] Add match statement --- src/black/lines.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/black/lines.py b/src/black/lines.py index 9ca34c7cceb..f2bdada008a 100644 --- a/src/black/lines.py +++ b/src/black/lines.py @@ -458,7 +458,7 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]: and current_line.leaves[-1].type == token.COLON and ( current_line.leaves[0].value - not in ("with", "try", "for", "while", "if") + not in ("with", "try", "for", "while", "if", "match") ) ): # We shouldn't add two newlines between an indented function and From 4253c26094980962120e866607de3039c6045fe0 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Wed, 1 Dec 2021 17:38:59 -0500 Subject: [PATCH 4/4] primer: pyanalyze will now be reformatted --- src/black_primer/primer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/black_primer/primer.json b/src/black_primer/primer.json index 2290d1df005..8fe61e889f8 100644 --- a/src/black_primer/primer.json +++ b/src/black_primer/primer.json @@ -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"]