Add formatting of type parameters in class and function definitions (#6161)

Part of #5062 
Closes https://github.com/astral-sh/ruff/issues/5931

Implements formatting of a sequence of type parameters in a dedicated
struct for reuse by classes, functions, and type aliases (preparing for
#5929). Adds formatting of type parameters in class and function
definitions — previously, they were just elided.
This commit is contained in:
Zanie Blue 2023-08-02 15:29:28 -05:00 committed by GitHub
parent 9425ed72a0
commit 1a60d1e3c6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 825 additions and 172 deletions

View file

@ -1,159 +0,0 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/py_312/type_params.py
---
## Input
```py
def func [T ](): pass
async def func [ T ] (): pass
class C[ T ] : pass
def all_in[T : int,U : (bytes, str),* Ts,**P](): pass
def really_long[WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine](): pass
def even_longer[WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine: WhatIfItHadABound](): pass
def it_gets_worse[WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine, ItCouldBeGenericOverMultipleTypeVars](): pass
def magic[Trailing, Comma,](): pass
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,40 +1,30 @@
-def func[T]():
+def func():
pass
-async def func[T]():
+async def func():
pass
-class C[T]:
+class C:
pass
-def all_in[T: int, U: (bytes, str), *Ts, **P]():
+def all_in():
pass
-def really_long[
- WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine
-]():
+def really_long():
pass
-def even_longer[
- WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine: WhatIfItHadABound
-]():
+def even_longer():
pass
-def it_gets_worse[
- WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine,
- ItCouldBeGenericOverMultipleTypeVars,
-]():
+def it_gets_worse():
pass
-def magic[
- Trailing,
- Comma,
-]():
+def magic():
pass
```
## Ruff Output
```py
def func():
pass
async def func():
pass
class C:
pass
def all_in():
pass
def really_long():
pass
def even_longer():
pass
def it_gets_worse():
pass
def magic():
pass
```
## Black Output
```py
def func[T]():
pass
async def func[T]():
pass
class C[T]:
pass
def all_in[T: int, U: (bytes, str), *Ts, **P]():
pass
def really_long[
WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine
]():
pass
def even_longer[
WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine: WhatIfItHadABound
]():
pass
def it_gets_worse[
WhatIsTheLongestTypeVarNameYouCanThinkOfEnoughToMakeBlackSplitThisLine,
ItCouldBeGenericOverMultipleTypeVars,
]():
pass
def magic[
Trailing,
Comma,
]():
pass
```

View file

@ -27,6 +27,17 @@ b3 = [
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
]
# Comment placement in non-empty lists
c1 = [ # trailing open bracket
# leading item
1,
# between
2, # trailing item
# leading close bracket
] # trailing close bracket
```
## Output
@ -53,6 +64,16 @@ b3 = [
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa,
]
# Comment placement in non-empty lists
c1 = [
# trailing open bracket
# leading item
1,
# between
2, # trailing item
# leading close bracket
] # trailing close bracket
```

View file

@ -49,6 +49,14 @@ class TestTrailingComment2: # trailing comment
pass
class TestTrailingComment3[T]: # trailing comment
pass
class TestTrailingComment4[T](A): # trailing comment
pass
class Test:
"""Docstring"""
@ -150,6 +158,60 @@ class AltCLIPOutput(
# Copied from transformers.models.clip.modeling_clip.CLIPOutput with CLIP->AltCLIP
):
...
class TestTypeParams[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, Cccccccccccccccccccccc]:
pass
class TestTypeParams[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, *Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, **Cccccccccccccccccccccc]:
pass
class TestTypeParams[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]:
pass
class TestTypeParams[*Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]:
pass
class TestTypeParams[**Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa]:
pass
class TestTypeParams[**P, *Ts, T]:
pass
class TestTypeParams[ # trailing bracket comment
# leading comment
A,
# in between comment
B,
# another leading comment
C,
D, # trailing comment
# leading bracket comment
]:
pass
class TestTypeParams[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa](B, C, D):
pass
class TestTypeParams[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa](Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, Cccccccccccccccccccccccc, Ddddddddddddddddddddddddd):
pass
class TestTypeParams[A, B, C](meta=Aaaaaaaaaaaaaaaaaaaaaa):
pass
```
## Output
@ -216,6 +278,14 @@ class TestTrailingComment2: # trailing comment
pass
class TestTrailingComment3[T]: # trailing comment
pass
class TestTrailingComment4[T](A): # trailing comment
pass
class Test:
"""Docstring"""
@ -318,6 +388,77 @@ class AltCLIPOutput(
# Copied from transformers.models.clip.modeling_clip.CLIPOutput with CLIP->AltCLIP
):
...
class TestTypeParams[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
Cccccccccccccccccccccc,
]:
pass
class TestTypeParams[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
*Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
**Cccccccccccccccccccccc,
]:
pass
class TestTypeParams[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
]:
pass
class TestTypeParams[
*Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
]:
pass
class TestTypeParams[
**Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
]:
pass
class TestTypeParams[**P, *Ts, T]:
pass
class TestTypeParams[ # trailing bracket comment
# leading comment
A,
# in between comment
B,
# another leading comment
C,
D, # trailing comment
# leading bracket comment
]:
pass
class TestTypeParams[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
](B, C, D):
pass
class TestTypeParams[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
](
Bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
Cccccccccccccccccccccccc,
Ddddddddddddddddddddddddd,
):
pass
class TestTypeParams[A, B, C](meta=Aaaaaaaaaaaaaaaaaaaaaa):
pass
```

View file

@ -72,6 +72,52 @@ def argument_with_long_type_annotation(
def test(): ...
# Type parameter empty line spacing
def test[
# comment
A,
# another
B,
](): ...
# Type parameter comments
def type_param_comments[ # trailing bracket comment
# leading comment
A,
# in between comment
B,
# another leading comment
C,
D, # trailing comment
# leading bracket comment
]():
# body comment
pass
# Note empty type parameters is not valid syntax, e.g.
# def test[](): ...
# Different type parameter wrappings
def single_line[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbbbb, Ccccccccccccccccc]():
pass
def params_on_their_own_line[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbbbb, Ccccccccccc, Ddddddddddddd, Eeeeeeee]():
pass
def param_per_line[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbbbb, Ccccccccccccccccc, Ddddddddddddd, Eeeeeeeeeeeeeeeee, ffffffffffff]():
pass
def single_line_trailing_comma[A, B, C,]():
pass
# Comment
def with_leading_comment(): ...
@ -353,6 +399,70 @@ def test():
...
# Type parameter empty line spacing
def test[
# comment
A,
# another
B,
]():
...
# Type parameter comments
def type_param_comments[ # trailing bracket comment
# leading comment
A,
# in between comment
B,
# another leading comment
C,
D, # trailing comment
# leading bracket comment
]():
# body comment
pass
# Note empty type parameters is not valid syntax, e.g.
# def test[](): ...
# Different type parameter wrappings
def single_line[Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, Bbbbbbbbbbbbbbb, Ccccccccccccccccc]():
pass
def params_on_their_own_line[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
Bbbbbbbbbbbbbbb,
Ccccccccccc,
Ddddddddddddd,
Eeeeeeee,
]():
pass
def param_per_line[
Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
Bbbbbbbbbbbbbbb,
Ccccccccccccccccc,
Ddddddddddddd,
Eeeeeeeeeeeeeeeee,
ffffffffffff,
]():
pass
def single_line_trailing_comma[
A,
B,
C,
]():
pass
# Comment
def with_leading_comment():
...