Repository: psf/black

Issue:
Blank lines at top level code in stubs should be the same inside an if
**Describe the style change**

Blank lines should be treated the same in top-level code under an if-statement as in top-level code proper

**Examples in the current _Black_ style**

<!-- Think of some short code snippets that show
how the current _Black_ style is not great: -->

```python
class A:
    def f(self): ...

class B:
    def f(self): ...

if sys.version_info >= (3, 8):
    class C:
        def f(self): ...
    class D:
        def f(self): ...
```

**Desired style**

<!-- How do you think _Black_ should format the above snippets: -->

```python
class A:
    def f(self): ...

class B:
    def f(self): ...

if sys.version_info >= (3, 8):
    class C:
        def f(self): ...

    class D:
        def f(self): ...
```

**Additional context**

<!-- Add any other context about the problem here. -->

[Playground link](https://black.vercel.app/?version=stable&state=_Td6WFoAAATm1rRGAgAhARYAAAB0L-Wj4AD8AIRdAD2IimZxl1N_WlXnON2nzNApqtITJJee2SMStFF7KJQ8b5tLWLTPF97YwrFIbsO2CJkraBrsaGIFFxZyS8cW-bxi-KzgtfNZt0bUoUnR71oEBfdQhSZgYLHjXKPdI-W9GBft7c-sf-zudh3LWYfAsj7EDjUuebHXI_AiVpD5OuhIJSCPsAC6Ox7BianITQABoAH9AQAAzkjnkrHEZ_sCAAAAAARZWg==)

Similar to / discussed in https://github.com/psf/black/issues/2783


Discussion:
Let's do it.

Resolving patch:
diff --git a/src/black/lines.py b/src/black/lines.py
--- a/src/black/lines.py
+++ b/src/black/lines.py
@@ -530,11 +530,11 @@ def _maybe_empty_lines_for_class_or_def(
             return 0, 0
 
         if self.is_pyi:
-            if self.previous_line.depth > current_line.depth:
-                newlines = 0 if current_line.depth else 1
-            elif current_line.is_class or self.previous_line.is_class:
-                if current_line.depth:
+            if current_line.is_class or self.previous_line.is_class:
+                if self.previous_line.depth < current_line.depth:
                     newlines = 0
+                elif self.previous_line.depth > current_line.depth:
+                    newlines = 1
                 elif current_line.is_stub_class and self.previous_line.is_stub_class:
                     # No blank line between classes with an empty body
                     newlines = 0
@@ -551,6 +551,8 @@ def _maybe_empty_lines_for_class_or_def(
                     # Blank line between a block of functions (maybe with preceding
                     # decorators) and a block of non-functions
                     newlines = 1
+            elif self.previous_line.depth > current_line.depth:
+                newlines = 1
             else:
                 newlines = 0
         else:


Test patch:
diff --git a/tests/data/stub.pyi b/tests/data/stub.pyi
--- a/tests/data/stub.pyi
+++ b/tests/data/stub.pyi
@@ -32,6 +32,48 @@ def g():
 
 def h(): ...
 
+if sys.version_info >= (3, 8):
+    class E:
+        def f(self): ...
+    class F:
+
+        def f(self): ...
+    class G: ...
+    class H: ...
+else:
+    class I: ...
+    class J: ...
+    def f(): ...
+
+    class K:
+        def f(self): ...
+    def f(): ...
+
+class Nested:
+    class dirty: ...
+    class little: ...
+    class secret:
+        def who_has_to_know(self): ...
+    def verse(self): ...
+
+class Conditional:
+    def f(self): ...
+    if sys.version_info >= (3, 8):
+        def g(self): ...
+    else:
+        def g(self): ...
+    def h(self): ...
+    def i(self): ...
+    if sys.version_info >= (3, 8):
+        def j(self): ...
+    def k(self): ...
+    if sys.version_info >= (3, 8):
+        class A: ...
+        class B: ...
+        class C:
+            def l(self): ...
+            def m(self): ...
+
 
 # output
 X: int
@@ -56,3 +98,54 @@ class A:
 
 def g(): ...
 def h(): ...
+
+if sys.version_info >= (3, 8):
+    class E:
+        def f(self): ...
+
+    class F:
+        def f(self): ...
+
+    class G: ...
+    class H: ...
+
+else:
+    class I: ...
+    class J: ...
+
+    def f(): ...
+
+    class K:
+        def f(self): ...
+
+    def f(): ...
+
+class Nested:
+    class dirty: ...
+    class little: ...
+
+    class secret:
+        def who_has_to_know(self): ...
+
+    def verse(self): ...
+
+class Conditional:
+    def f(self): ...
+    if sys.version_info >= (3, 8):
+        def g(self): ...
+    else:
+        def g(self): ...
+
+    def h(self): ...
+    def i(self): ...
+    if sys.version_info >= (3, 8):
+        def j(self): ...
+
+    def k(self): ...
+    if sys.version_info >= (3, 8):
+        class A: ...
+        class B: ...
+
+        class C:
+            def l(self): ...
+            def m(self): ...