Skip to content

Commit b40b01f

Browse files
Blank line between nested and function def in stub files. (#3862)
The idea behind this change is that we stop looking into previous body to determine if there should be a blank before a function or class definition. Input: ```python import sys if sys.version_info > (3, 7): class Nested1: assignment = 1 def function_definition(self): ... def f1(self) -> str: ... class Nested2: def function_definition(self): ... assignment = 1 def f2(self) -> str: ... if sys.version_info > (3, 7): def nested1(): assignment = 1 def function_definition(self): ... def f1(self) -> str: ... def nested2(): def function_definition(self): ... assignment = 1 def f2(self) -> str: ... ``` Stable style ```python import sys if sys.version_info > (3, 7): class Nested1: assignment = 1 def function_definition(self): ... def f1(self) -> str: ... class Nested2: def function_definition(self): ... assignment = 1 def f2(self) -> str: ... if sys.version_info > (3, 7): def nested1(): assignment = 1 def function_definition(self): ... def f1(self) -> str: ... def nested2(): def function_definition(self): ... assignment = 1 def f2(self) -> str: ... ``` In the stable formatting, we have a blank line sometimes, not depending on the previous statement on the same level, but on the last (potentially nested) statement in the previous body. #2783/#3564 fixes this for classes in preview style: ```python import sys if sys.version_info > (3, 7): class Nested1: assignment = 1 def function_definition(self): ... def f1(self) -> str: ... class Nested2: def function_definition(self): ... assignment = 1 def f2(self) -> str: ... if sys.version_info > (3, 7): def nested1(): assignment = 1 def function_definition(self): ... def f1(self) -> str: ... def nested2(): def function_definition(self): ... assignment = 1 def f2(self) -> str: ... ``` This PR additionally fixes this for function definitions: ```python if sys.version_info > (3, 7): if sys.platform == "win32": assignment = 1 def function_definition(self): ... def f1(self) -> str: ... if sys.platform != "win32": def function_definition(self): ... assignment = 1 def f2(self) -> str: ... if sys.version_info > (3, 8): if sys.platform == "win32": assignment = 1 def function_definition(self): ... class F1: ... if sys.platform != "win32": def function_definition(self): ... assignment = 1 class F2: ... ``` You can see the effect of this change on typeshed in https://github.com/konstin/typeshed/pull/1/files. As baseline, the preview mode changes without this PR are at konstin/typeshed#2. Co-authored-by: Jelle Zijlstra <[email protected]>
1 parent a20338c commit b40b01f

File tree

6 files changed

+59
-18
lines changed

6 files changed

+59
-18
lines changed

CHANGES.md

+2
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,8 @@ expected to become part of Black's stable style in January 2024.
171171
- For stubs, enforce one blank line after a nested class with a body other than just
172172
`...` (#3564)
173173
- Improve handling of multiline strings by changing line split behavior (#1879)
174+
- In stub files, add a blank line between a statement with a body (e.g an
175+
`if sys.version_info > (3, x):`) and a function definition on the same level. (#3862)
174176

175177
### Parser
176178

src/black/lines.py

+11
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,17 @@ def _maybe_empty_lines_for_class_or_def( # noqa: C901
711711
newlines = 0
712712
else:
713713
newlines = 1
714+
# Remove case `self.previous_line.depth > current_line.depth` below when
715+
# this becomes stable.
716+
#
717+
# Don't inspect the previous line if it's part of the body of the previous
718+
# statement in the same level, we always want a blank line if there's
719+
# something with a body preceding.
720+
elif (
721+
Preview.blank_line_between_nested_and_def_stub_file in current_line.mode
722+
and self.previous_line.depth > current_line.depth
723+
):
724+
newlines = 1
714725
elif (
715726
current_line.is_def or current_line.is_decorator
716727
) and not self.previous_line.is_def:

src/black/mode.py

+1
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ class Preview(Enum):
170170

171171
add_trailing_comma_consistently = auto()
172172
blank_line_after_nested_stub_class = auto()
173+
blank_line_between_nested_and_def_stub_file = auto()
173174
hex_codes_in_unicode_sequences = auto()
174175
improved_async_statements_handling = auto()
175176
multiline_string_handling = auto()

tests/data/miscellaneous/nested_class_stub.pyi

-16
This file was deleted.
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import sys
2+
3+
class Outer:
4+
class InnerStub: ...
5+
outer_attr_after_inner_stub: int
6+
class Inner:
7+
inner_attr: int
8+
outer_attr: int
9+
10+
if sys.version_info > (3, 7):
11+
if sys.platform == "win32":
12+
assignment = 1
13+
def function_definition(self): ...
14+
def f1(self) -> str: ...
15+
if sys.platform != "win32":
16+
def function_definition(self): ...
17+
assignment = 1
18+
def f2(self) -> str: ...
19+
20+
# output
21+
22+
import sys
23+
24+
class Outer:
25+
class InnerStub: ...
26+
outer_attr_after_inner_stub: int
27+
28+
class Inner:
29+
inner_attr: int
30+
31+
outer_attr: int
32+
33+
if sys.version_info > (3, 7):
34+
if sys.platform == "win32":
35+
assignment = 1
36+
def function_definition(self): ...
37+
38+
def f1(self) -> str: ...
39+
if sys.platform != "win32":
40+
def function_definition(self): ...
41+
assignment = 1
42+
43+
def f2(self) -> str: ...

tests/test_format.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,9 @@ def test_stub() -> None:
201201
assert_format(source, expected, mode)
202202

203203

204-
def test_nested_class_stub() -> None:
204+
def test_nested_stub() -> None:
205205
mode = replace(DEFAULT_MODE, is_pyi=True, preview=True)
206-
source, expected = read_data("miscellaneous", "nested_class_stub.pyi")
206+
source, expected = read_data("miscellaneous", "nested_stub.pyi")
207207
assert_format(source, expected, mode)
208208

209209

0 commit comments

Comments
 (0)