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 https://github.com/konstin/typeshed/pull/2.
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
- For stubs, enforce one blank line after a nested class with a body other than just
`...` (#3564)
- Improve handling of multiline strings by changing line split behavior (#1879)
+- In stub files, add a blank line between a statement with a body (e.g an
+ `if sys.version_info > (3, x):`) and a function definition on the same level. (#3862)
### Parser
newlines = 0
else:
newlines = 1
+ # Remove case `self.previous_line.depth > current_line.depth` below when
+ # this becomes stable.
+ #
+ # Don't inspect the previous line if it's part of the body of the previous
+ # statement in the same level, we always want a blank line if there's
+ # something with a body preceding.
+ elif (
+ Preview.blank_line_between_nested_and_def_stub_file in current_line.mode
+ and self.previous_line.depth > current_line.depth
+ ):
+ newlines = 1
elif (
current_line.is_def or current_line.is_decorator
) and not self.previous_line.is_def:
add_trailing_comma_consistently = auto()
blank_line_after_nested_stub_class = auto()
+ blank_line_between_nested_and_def_stub_file = auto()
hex_codes_in_unicode_sequences = auto()
improved_async_statements_handling = auto()
multiline_string_handling = auto()
+++ /dev/null
-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
--- /dev/null
+import sys
+
+class Outer:
+ class InnerStub: ...
+ outer_attr_after_inner_stub: int
+ class Inner:
+ inner_attr: int
+ outer_attr: int
+
+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: ...
+
+# output
+
+import sys
+
+class Outer:
+ class InnerStub: ...
+ outer_attr_after_inner_stub: int
+
+ class Inner:
+ inner_attr: int
+
+ outer_attr: int
+
+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: ...
\ No newline at end of file
assert_format(source, expected, mode)
-def test_nested_class_stub() -> None:
+def test_nested_stub() -> None:
mode = replace(DEFAULT_MODE, is_pyi=True, preview=True)
- source, expected = read_data("miscellaneous", "nested_class_stub.pyi")
+ source, expected = read_data("miscellaneous", "nested_stub.pyi")
assert_format(source, expected, mode)