Skip to content

Commit

Permalink
Enforce a blank line after a nested class in stubs (#3564)
Browse files Browse the repository at this point in the history
  • Loading branch information
WMOkiishi committed Mar 18, 2023
1 parent a3e8247 commit d7a28dd
Show file tree
Hide file tree
Showing 5 changed files with 34 additions and 3 deletions.
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -23,6 +23,8 @@
compared to their non-async version. (#3609)
- `with` statements that contain two context managers will be consistently wrapped in
parentheses (#3589)
- For stubs, enforce one blank line after a nested class with a body other than just
`...` (#3564)

### Configuration

Expand Down
12 changes: 9 additions & 3 deletions src/black/lines.py
Expand Up @@ -521,7 +521,7 @@ class EmptyLineTracker:
mode: Mode
previous_line: Optional[Line] = None
previous_block: Optional[LinesBlock] = None
previous_defs: List[int] = field(default_factory=list)
previous_defs: List[Line] = field(default_factory=list)
semantic_leading_comment: Optional[LinesBlock] = None

def maybe_empty_lines(self, current_line: Line) -> LinesBlock:
Expand Down Expand Up @@ -577,12 +577,18 @@ def _maybe_empty_lines(self, current_line: Line) -> Tuple[int, int]:
else:
before = 0
depth = current_line.depth
while self.previous_defs and self.previous_defs[-1] >= depth:
while self.previous_defs and self.previous_defs[-1].depth >= depth:
if self.mode.is_pyi:
assert self.previous_line is not None
if depth and not current_line.is_def and self.previous_line.is_def:
# Empty lines between attributes and methods should be preserved.
before = min(1, before)
elif (
Preview.blank_line_after_nested_stub_class in self.mode
and self.previous_defs[-1].is_class
and not self.previous_defs[-1].is_stub_class
):
before = 1
elif depth:
before = 0
else:
Expand Down Expand Up @@ -637,7 +643,7 @@ def _maybe_empty_lines_for_class_or_def(
self, current_line: Line, before: int
) -> Tuple[int, int]:
if not current_line.is_decorator:
self.previous_defs.append(current_line.depth)
self.previous_defs.append(current_line)
if self.previous_line is None:
# Don't insert empty lines before the first line in the file.
return 0, 0
Expand Down
1 change: 1 addition & 0 deletions src/black/mode.py
Expand Up @@ -154,6 +154,7 @@ class Preview(Enum):
"""Individual preview style features."""

add_trailing_comma_consistently = auto()
blank_line_after_nested_stub_class = auto()
hex_codes_in_unicode_sequences = auto()
improved_async_statements_handling = auto()
multiline_string_handling = auto()
Expand Down
16 changes: 16 additions & 0 deletions tests/data/miscellaneous/nested_class_stub.pyi
@@ -0,0 +1,16 @@
class Outer:
class InnerStub: ...
outer_attr_after_inner_stub: int
class Inner:
inner_attr: int
outer_attr: int

# output
class Outer:
class InnerStub: ...
outer_attr_after_inner_stub: int

class Inner:
inner_attr: int

outer_attr: int
6 changes: 6 additions & 0 deletions tests/test_format.py
Expand Up @@ -186,6 +186,12 @@ def test_stub() -> None:
assert_format(source, expected, mode)


def test_nested_class_stub() -> None:
mode = replace(DEFAULT_MODE, is_pyi=True, preview=True)
source, expected = read_data("miscellaneous", "nested_class_stub.pyi")
assert_format(source, expected, mode)


def test_power_op_newline() -> None:
# requires line_length=0
source, expected = read_data("miscellaneous", "power_op_newline")
Expand Down

0 comments on commit d7a28dd

Please sign in to comment.