Implement no_blank_line_before_class_docstring preview style (#9154)

## Summary

This PR implements the `no_blank_line_before_class_docstring` preview
style.

## Test Plan

Update existing snapshots.

### Formatter ecosystem

`main`

| project | similarity index | total files | changed files |
|----------------|------------------:|------------------:|------------------:|
| cpython | 0.75804 | 1799 | 1648 |
| django | 0.99984 | 2772 | 34 |
| home-assistant | 0.99955 | 10596 | 213 |
| poetry | 0.99905 | 321 | 15 |
| transformers | 0.99967 | 2657 | 324 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99980 | 3669 | 18 |
| warehouse | 0.99976 | 654 | 14 |
| zulip | 0.99958 | 1459 | 36 |

`dhruv/no-blank-line-docstring`

| project | similarity index | total files | changed files |
|----------------|------------------:|------------------:|------------------:|
| cpython | 0.75804 | 1799 | 1648 |
| django | 0.99984 | 2772 | 34 |
| home-assistant | 0.99955 | 10596 | 213 |
| poetry | 0.99905 | 321 | 15 |
| transformers | 0.99967 | 2657 | 324 |
| twine | 1.00000 | 33 | 0 |
| typeshed | 0.99980 | 3669 | 18 |
| warehouse | 0.99976 | 654 | 14 |
| zulip | 0.99958 | 1459 | 36 |

fixes: #8888
This commit is contained in:
Dhruv Manilawala 2023-12-19 00:43:20 -06:00 committed by GitHub
parent 7c894921df
commit 09296e3e3c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 184 additions and 148 deletions

View file

@ -0,0 +1,5 @@
[
{
"preview": "enabled"
}
]

View file

@ -0,0 +1,38 @@
class NormalDocstring:
"""This is a docstring."""
class DocstringWithComment0:
# This is a comment
"""This is a docstring."""
class DocstringWithComment1:
# This is a comment
"""This is a docstring."""
class DocstringWithComment2:
# This is a comment
"""This is a docstring."""
class DocstringWithComment3:
# This is a comment
"""This is a docstring."""
class DocstringWithComment4:
# This is a comment
"""This is a docstring."""

View file

@ -24,3 +24,12 @@ pub(crate) const fn is_prefer_splitting_right_hand_side_of_assignments_enabled(
) -> bool {
context.is_preview()
}
/// Returns `true` if the [`no_blank_line_before_class_docstring`] preview style is enabled.
///
/// [`no_blank_line_before_class_docstring`]: https://github.com/astral-sh/ruff/issues/8888
pub(crate) const fn is_no_blank_line_before_class_docstring_enabled(
context: &PyFormatContext,
) -> bool {
context.is_preview()
}

View file

@ -11,6 +11,7 @@ use crate::comments::{
use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, WithNodeLevel};
use crate::expression::expr_string_literal::ExprStringLiteralKind;
use crate::prelude::*;
use crate::preview::is_no_blank_line_before_class_docstring_enabled;
use crate::statement::stmt_expr::FormatStmtExpr;
use crate::verbatim::{
suppressed_node, write_suppressed_statements_starting_with_leading_comment,
@ -108,14 +109,24 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
if !comments.has_leading(first)
&& lines_before(first.start(), source) > 1
&& !source_type.is_stub()
&& !is_no_blank_line_before_class_docstring_enabled(f.context())
{
// Allow up to one empty line before a class docstring, e.g., this is
// stable formatting:
//
// ```python
// class Test:
//
// """Docstring"""
// ```
//
// But, in preview mode, we don't want to allow any empty lines before a
// class docstring, e.g., this is preview formatting:
//
// ```python
// class Test:
// """Docstring"""
// ```
empty_line().fmt(f)?;
}

View file

@ -1,134 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/preview_no_blank_line_before_docstring.py
---
## Input
```python
def line_before_docstring():
"""Please move me up"""
class LineBeforeDocstring:
"""Please move me up"""
class EvenIfThereIsAMethodAfter:
"""I'm the docstring"""
def method(self):
pass
class TwoLinesBeforeDocstring:
"""I want to be treated the same as if I were closer"""
class MultilineDocstringsAsWell:
"""I'm so far
and on so many lines...
"""
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -3,10 +3,12 @@
class LineBeforeDocstring:
+
"""Please move me up"""
class EvenIfThereIsAMethodAfter:
+
"""I'm the docstring"""
def method(self):
@@ -14,10 +16,12 @@
class TwoLinesBeforeDocstring:
+
"""I want to be treated the same as if I were closer"""
class MultilineDocstringsAsWell:
+
"""I'm so far
and on so many lines...
```
## Ruff Output
```python
def line_before_docstring():
"""Please move me up"""
class LineBeforeDocstring:
"""Please move me up"""
class EvenIfThereIsAMethodAfter:
"""I'm the docstring"""
def method(self):
pass
class TwoLinesBeforeDocstring:
"""I want to be treated the same as if I were closer"""
class MultilineDocstringsAsWell:
"""I'm so far
and on so many lines...
"""
```
## Black Output
```python
def line_before_docstring():
"""Please move me up"""
class LineBeforeDocstring:
"""Please move me up"""
class EvenIfThereIsAMethodAfter:
"""I'm the docstring"""
def method(self):
pass
class TwoLinesBeforeDocstring:
"""I want to be treated the same as if I were closer"""
class MultilineDocstringsAsWell:
"""I'm so far
and on so many lines...
"""
```

View file

@ -27,30 +27,21 @@ class UpperCaseR:
```diff
--- Black
+++ Ruff
@@ -1,4 +1,5 @@
class C:
+
r"""Raw"""
@@ -7,8 +8,9 @@
@@ -7,7 +7,7 @@
class SingleQuotes:
- r'''Raw'''
+ r"""Raw"""
+
class UpperCaseR:
R"""Raw"""
```
## Ruff Output
```python
class C:
r"""Raw"""
@ -59,7 +50,6 @@ def f():
class SingleQuotes:
r"""Raw"""

View file

@ -0,0 +1,95 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/blank_line_before_class_docstring.py
---
## Input
```python
class NormalDocstring:
"""This is a docstring."""
class DocstringWithComment0:
# This is a comment
"""This is a docstring."""
class DocstringWithComment1:
# This is a comment
"""This is a docstring."""
class DocstringWithComment2:
# This is a comment
"""This is a docstring."""
class DocstringWithComment3:
# This is a comment
"""This is a docstring."""
class DocstringWithComment4:
# This is a comment
"""This is a docstring."""
```
## Outputs
### Output 1
```
indent-style = space
line-width = 88
indent-width = 4
quote-style = Double
line-ending = LineFeed
magic-trailing-comma = Respect
docstring-code = Disabled
docstring-code-line-width = "dynamic"
preview = Enabled
```
```python
class NormalDocstring:
"""This is a docstring."""
class DocstringWithComment0:
# This is a comment
"""This is a docstring."""
class DocstringWithComment1:
# This is a comment
"""This is a docstring."""
class DocstringWithComment2:
# This is a comment
"""This is a docstring."""
class DocstringWithComment3:
# This is a comment
"""This is a docstring."""
class DocstringWithComment4:
# This is a comment
"""This is a docstring."""
```

View file

@ -198,7 +198,6 @@ def reference_docstring_newlines():
class RemoveNewlineBeforeClassDocstring:
"""Black's `Preview.no_blank_line_before_class_docstring`"""

View file

@ -513,7 +513,30 @@ class QuerySet(AltersData):
class Test(
@@ -159,20 +158,17 @@
@@ -94,7 +93,6 @@
class Test:
-
"""Docstring"""
@@ -111,14 +109,12 @@
class Test:
-
"""Docstring"""
x = 1
class Test:
-
"""Docstring"""
# comment
@@ -159,20 +155,17 @@
@dataclass
# Copied from transformers.models.clip.modeling_clip.CLIPOutput with CLIP->AltCLIP