Implement Black's rules around newlines before and after class docstrings (#6209)

## Summary

Black allows up to one blank line _before_ a class docstring, and
enforces one blank line _after_ a class docstring. This PR implements
that handling. The cases in
`crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/class_definition.py`
match Black identically.
This commit is contained in:
Charlie Marsh 2023-08-01 13:33:01 -04:00 committed by GitHub
parent 5e41f2fc7d
commit a82eb9544c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 224 additions and 503 deletions

View file

@ -1,485 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py
---
## Input
```py
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -31,7 +31,6 @@
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
-
cls_var = 100
def __init__(self):
@@ -54,7 +53,6 @@
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
-
cls_var = 100
@deco
@@ -109,7 +107,6 @@
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
-
cls_var = 100
class Inner:
@@ -141,7 +138,6 @@
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
-
cls_var = 100
class Inner:
```
## Ruff Output
```py
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
```
## Black Output
```py
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
```

View file

@ -49,6 +49,55 @@ class TestTrailingComment2: # trailing comment
pass
class Test:
"""Docstring"""
class Test:
# comment
"""Docstring"""
class Test:
"""Docstring"""
x = 1
class Test:
"""Docstring"""
# comment
x = 1
class Test:
"""Docstring"""
class Test:
# comment
"""Docstring"""
class Test:
# comment
"""Docstring"""
class Test:
"""Docstring"""
x = 1
class Test:
"""Docstring"""
# comment
x = 1
```
## Output
@ -114,6 +163,60 @@ class TestTrailingComment1(Aaaa): # trailing comment
class TestTrailingComment2: # trailing comment
pass
class Test:
"""Docstring"""
class Test:
# comment
"""Docstring"""
class Test:
"""Docstring"""
x = 1
class Test:
"""Docstring"""
# comment
x = 1
class Test:
"""Docstring"""
class Test:
# comment
"""Docstring"""
class Test:
# comment
"""Docstring"""
class Test:
"""Docstring"""
x = 1
class Test:
"""Docstring"""
# comment
x = 1
```