Improve with statement comment handling and expression breaking (#6621)

## Summary

The motivating code here was:

```python
with test as (
    # test
foo):
    pass
```

Which we were formatting as:

```python
with test as
# test
(foo):
    pass
```

`with` statements are oddly difficult. This PR makes a bunch of subtle
modifications and adds a more extensive test suite. For example, we now
only preserve parentheses if there's more than one `WithItem` _or_ a
trailing comma; before, we always preserved.

Our formatting is_not_ the same as Black, but here's a diff of our
formatted code vs. Black's for the `with.py` test suite. The primary
difference is that we tend to break parentheses when they contain
comments rather than move them to the end of the life (this is a
consistent difference that we make across the codebase):

```diff
diff --git a/crates/ruff_python_formatter/foo.py b/crates/ruff_python_formatter/foo.py
index 85e761080..31625c876 100644
--- a/crates/ruff_python_formatter/foo.py
+++ b/crates/ruff_python_formatter/foo.py
@@ -1,6 +1,4 @@
-with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-), aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
+with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:
     ...
     # trailing
 
@@ -16,28 +14,33 @@ with (
     # trailing
 
 
-with a, b:  # a  # comma  # c  # colon
+with (
+    a,  # a  # comma
+    b,  # c
+):  # colon
     ...
 
 
 with (
-    a as  # a  # as
-    # own line
-    b,  # b  # comma
+    a as (  # a  # as
+        # own line
+        b
+    ),  # b  # comma
     c,  # c
 ):  # colon
     ...  # body
     # body trailing own
 
-with (
-    a as  # a  # as
+with a as (  # a  # as
     # own line
-    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb  # b
-):
+    bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+):  # b
     pass
 
 
-with (a,):  # magic trailing comma
+with (
+    a,
+):  # magic trailing comma
     ...
 
 
@@ -47,6 +50,7 @@ with a:  # should remove brackets
 with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as c:
     ...
 
+
 with (
     # leading comment
     a
@@ -74,8 +78,7 @@ with (
 with (
     a  # trailing same line comment
     # trailing own line comment
-    as b
-):
+) as b:
     ...
 
 with (
@@ -87,7 +90,9 @@ with (
 with (
     a
     # trailing own line comment
-) as b:  # trailing as same line comment  # trailing b same line comment
+) as (  # trailing as same line comment
+    b
+):  # trailing b same line comment
     ...
 
 with (
@@ -124,18 +129,24 @@ with (  # comment
     ...
 
 with (  # outer comment
-    CtxManager1() as example1,  # inner comment
+    (  # inner comment
+        CtxManager1()
+    ) as example1,
     CtxManager2() as example2,
     CtxManager3() as example3,
 ):
     ...
 
-with CtxManager() as example:  # outer comment
+with (  # outer comment
+    CtxManager()
+) as example:
     ...
 
 with (  # outer comment
     CtxManager()
-) as example, CtxManager2() as example2:  # inner comment
+) as example, (  # inner comment
+    CtxManager2()
+) as example2:
     ...
 
 with (  # outer comment
@@ -145,7 +156,9 @@ with (  # outer comment
     ...
 
 with (  # outer comment
-    (CtxManager1()),  # inner comment
+    (  # inner comment
+        CtxManager1()
+    ),
     CtxManager2(),
 ) as example:
     ...
@@ -179,7 +192,9 @@ with (
 ):
     pass
 
-with a as (b):  # foo
+with a as (  # foo
+    b
+):
     pass
 
 with f(
@@ -209,17 +224,13 @@ with f(
 ) as b, c as d:
     pass
 
-with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-) as b:
+with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
     pass
 
 with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
     pass
 
-with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-) as b, c as d:
+with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b, c as d:
     pass
 
 with (
@@ -230,6 +241,8 @@ with (
     pass
 
 with (
-    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
-) as b, c as d:
+    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+    + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b,
+    c as d,
+):
     pass
```

Closes https://github.com/astral-sh/ruff/issues/6600.
## Test Plan

Before:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75473          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74292          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

After:

| project      | similarity index |
|--------------|------------------|
| cpython      | 0.75473          |
| django       | 0.99804          |
| transformers | 0.99618          |
| twine        | 0.99876          |
| typeshed     | 0.74292          |
| warehouse    | 0.99601          |
| zulip        | 0.99727          |

`cargo test`
This commit is contained in:
Charlie Marsh 2023-08-17 23:30:38 -04:00 committed by GitHub
parent 26bba11be6
commit 1811312722
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 472 additions and 98 deletions

View file

@ -33,6 +33,10 @@ def g(a,): pass
x1 = lambda y: 1
x2 = lambda y,: 1
# Ignore trailing comma.
with (a,): # magic trailing comma
...
```
## Outputs
@ -78,6 +82,12 @@ def g(
x1 = lambda y: 1
x2 = lambda y,: 1
# Ignore trailing comma.
with (
a,
): # magic trailing comma
...
```
@ -117,6 +127,10 @@ def g(a):
x1 = lambda y: 1
x2 = lambda y,: 1
# Ignore trailing comma.
with a: # magic trailing comma
...
```

View file

@ -73,6 +73,24 @@ with (
a as b
): ...
with (
a as b
# trailing comment
): ...
with (
a as (
# leading comment
b
)
): ...
with (
a as (
b
# trailing comment
)
): ...
with (a # trailing same line comment
# trailing own line comment
@ -84,7 +102,6 @@ with (
as b
): ...
with (a # trailing same line comment
# trailing own line comment
) as b: ...
@ -164,6 +181,85 @@ with ( # outer comment
CtxManager2(),
) as example:
...
# Breaking of with items.
with (test # bar
as # foo
(
# test
foo)):
pass
with test as (
# test
foo):
pass
with (test # bar
as # foo
( # baz
# test
foo)):
pass
with (a as b, c as d):
pass
with (
a as b,
# foo
c as d
):
pass
with (
a as ( # foo
b
)
):
pass
with (
f(a, ) as b
):
pass
with (x := 1) as d:
pass
with (x[1, 2,] as d):
pass
with (f(a, ) as b, c as d):
pass
with f(a, ) as b, c as d:
pass
with (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
) as b:
pass
with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
pass
with (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
) as b, c as d:
pass
with (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b, c as d):
pass
with (
(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) as b, c as d):
pass
with (foo() as bar, baz() as bop):
pass
```
## Output
@ -192,19 +288,19 @@ with (
with (
a as # a # as
# own line
b, # b # comma
a as ( # a # as
# own line
b
), # b # comma
c, # c
): # colon
... # body
# body trailing own
with (
a as # a # as
with a as ( # a # as
# own line
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb # b
):
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
): # b
pass
@ -239,34 +335,50 @@ with (
):
...
with (
a # trailing same line comment
# trailing own line comment
) as b:
...
with (
a # trailing same line comment
# trailing own line comment
) as b:
...
with (
a # trailing same line comment
# trailing own line comment
) as b:
...
with (
(
a
# trailing own line comment
) as b # trailing as same line comment # trailing b same line comment
a as b
# trailing comment
):
...
with a as (
# leading comment
b
):
...
with a as (
b
# trailing comment
):
...
with (
a # trailing same line comment
# trailing own line comment
) as b:
...
with (
a # trailing same line comment
# trailing own line comment
) as b:
...
with (
a # trailing same line comment
# trailing own line comment
) as b:
...
with (
a
# trailing own line comment
) as ( # trailing as same line comment
b
): # trailing b same line comment
...
with (
[
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
@ -334,6 +446,93 @@ with ( # outer comment
CtxManager2(),
) as example:
...
# Breaking of with items.
with test as ( # bar # foo
# test
foo
):
pass
with test as (
# test
foo
):
pass
with test as ( # bar # foo # baz
# test
foo
):
pass
with a as b, c as d:
pass
with (
a as b,
# foo
c as d,
):
pass
with a as ( # foo
b
):
pass
with f(
a,
) as b:
pass
with (x := 1) as d:
pass
with x[
1,
2,
] as d:
pass
with (
f(
a,
) as b,
c as d,
):
pass
with f(
a,
) as b, c as d:
pass
with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
pass
with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b:
pass
with aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b, c as d:
pass
with (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b,
c as d,
):
pass
with (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb as b,
c as d,
):
pass
with foo() as bar, baz() as bop:
pass
```