mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-03 02:12:22 +00:00
Enable more non-panicking formatter tests (#3262)
This commit is contained in:
parent
270015865b
commit
16be691712
9 changed files with 3282 additions and 7 deletions
|
@ -75,13 +75,7 @@ mod tests {
|
||||||
pattern = "resources/test/fixtures/black/**/*.py",
|
pattern = "resources/test/fixtures/black/**/*.py",
|
||||||
// Excluded tests because they reach unreachable when attaching tokens
|
// Excluded tests because they reach unreachable when attaching tokens
|
||||||
exclude = [
|
exclude = [
|
||||||
"*comments.py",
|
"*comments8.py",
|
||||||
"*comments[3,5,8].py",
|
|
||||||
"*comments_non_breaking_space.py",
|
|
||||||
"*docstring_preview.py",
|
|
||||||
"*docstring.py",
|
|
||||||
"*fmtonoff.py",
|
|
||||||
"*fmtskip8.py",
|
|
||||||
])
|
])
|
||||||
]
|
]
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
# The percent-percent comments are Spyder IDE cells.
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
def func():
|
||||||
|
x = """
|
||||||
|
a really long string
|
||||||
|
"""
|
||||||
|
lcomp3 = [
|
||||||
|
# This one is actually too long to fit in a single line.
|
||||||
|
element.split("\n", 1)[0]
|
||||||
|
# yup
|
||||||
|
for element in collection.select_elements()
|
||||||
|
# right
|
||||||
|
if element is not None
|
||||||
|
]
|
||||||
|
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
|
||||||
|
if isinstance(exc_value, MultiError):
|
||||||
|
embedded = []
|
||||||
|
for exc in exc_value.exceptions:
|
||||||
|
if exc not in _seen:
|
||||||
|
embedded.append(
|
||||||
|
# This should be left alone (before)
|
||||||
|
traceback.TracebackException.from_exception(
|
||||||
|
exc,
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
_seen=set(_seen),
|
||||||
|
)
|
||||||
|
# This should be left alone (after)
|
||||||
|
)
|
||||||
|
|
||||||
|
# everything is fine if the expression isn't nested
|
||||||
|
traceback.TracebackException.from_exception(
|
||||||
|
exc,
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
_seen=set(_seen),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -9,10 +9,11 @@
|
||||||
|
lcomp3 = [
|
||||||
|
# This one is actually too long to fit in a single line.
|
||||||
|
element.split("\n", 1)[0]
|
||||||
|
- # yup
|
||||||
|
- for element in collection.select_elements()
|
||||||
|
- # right
|
||||||
|
- if element is not None
|
||||||
|
+ for # yup
|
||||||
|
+ element in collection.select_elements()
|
||||||
|
+ if # right
|
||||||
|
+ element
|
||||||
|
+ is not None
|
||||||
|
]
|
||||||
|
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
|
||||||
|
if isinstance(exc_value, MultiError):
|
||||||
|
@@ -26,9 +27,9 @@
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
- # copy the set of _seen exceptions so that duplicates
|
||||||
|
+ _seen=# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
- _seen=set(_seen),
|
||||||
|
+ set(_seen),
|
||||||
|
)
|
||||||
|
# This should be left alone (after)
|
||||||
|
)
|
||||||
|
@@ -39,9 +40,9 @@
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
- # copy the set of _seen exceptions so that duplicates
|
||||||
|
+ _seen=# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
- _seen=set(_seen),
|
||||||
|
+ set(_seen),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
# The percent-percent comments are Spyder IDE cells.
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
def func():
|
||||||
|
x = """
|
||||||
|
a really long string
|
||||||
|
"""
|
||||||
|
lcomp3 = [
|
||||||
|
# This one is actually too long to fit in a single line.
|
||||||
|
element.split("\n", 1)[0]
|
||||||
|
for # yup
|
||||||
|
element in collection.select_elements()
|
||||||
|
if # right
|
||||||
|
element
|
||||||
|
is not None
|
||||||
|
]
|
||||||
|
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
|
||||||
|
if isinstance(exc_value, MultiError):
|
||||||
|
embedded = []
|
||||||
|
for exc in exc_value.exceptions:
|
||||||
|
if exc not in _seen:
|
||||||
|
embedded.append(
|
||||||
|
# This should be left alone (before)
|
||||||
|
traceback.TracebackException.from_exception(
|
||||||
|
exc,
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
_seen=# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
set(_seen),
|
||||||
|
)
|
||||||
|
# This should be left alone (after)
|
||||||
|
)
|
||||||
|
|
||||||
|
# everything is fine if the expression isn't nested
|
||||||
|
traceback.TracebackException.from_exception(
|
||||||
|
exc,
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
_seen=# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
set(_seen),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
# The percent-percent comments are Spyder IDE cells.
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
def func():
|
||||||
|
x = """
|
||||||
|
a really long string
|
||||||
|
"""
|
||||||
|
lcomp3 = [
|
||||||
|
# This one is actually too long to fit in a single line.
|
||||||
|
element.split("\n", 1)[0]
|
||||||
|
# yup
|
||||||
|
for element in collection.select_elements()
|
||||||
|
# right
|
||||||
|
if element is not None
|
||||||
|
]
|
||||||
|
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
|
||||||
|
if isinstance(exc_value, MultiError):
|
||||||
|
embedded = []
|
||||||
|
for exc in exc_value.exceptions:
|
||||||
|
if exc not in _seen:
|
||||||
|
embedded.append(
|
||||||
|
# This should be left alone (before)
|
||||||
|
traceback.TracebackException.from_exception(
|
||||||
|
exc,
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
_seen=set(_seen),
|
||||||
|
)
|
||||||
|
# This should be left alone (after)
|
||||||
|
)
|
||||||
|
|
||||||
|
# everything is fine if the expression isn't nested
|
||||||
|
traceback.TracebackException.from_exception(
|
||||||
|
exc,
|
||||||
|
limit=limit,
|
||||||
|
lookup_lines=lookup_lines,
|
||||||
|
capture_locals=capture_locals,
|
||||||
|
# copy the set of _seen exceptions so that duplicates
|
||||||
|
# shared between sub-exceptions are not omitted
|
||||||
|
_seen=set(_seen),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# %%
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,279 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
while True:
|
||||||
|
if something.changed:
|
||||||
|
do.stuff() # trailing comment
|
||||||
|
# Comment belongs to the `if` block.
|
||||||
|
# This one belongs to the `while` block.
|
||||||
|
|
||||||
|
# Should this one, too? I guess so.
|
||||||
|
|
||||||
|
# This one is properly standalone now.
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
# first we do this
|
||||||
|
if i % 33 == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# then we do this
|
||||||
|
print(i)
|
||||||
|
# and finally we loop around
|
||||||
|
|
||||||
|
with open(some_temp_file) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(some_other_file) as w:
|
||||||
|
w.write(data)
|
||||||
|
|
||||||
|
except OSError:
|
||||||
|
print("problems")
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# leading function comment
|
||||||
|
def wat():
|
||||||
|
...
|
||||||
|
# trailing function comment
|
||||||
|
|
||||||
|
|
||||||
|
# SECTION COMMENT
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
# leading 2
|
||||||
|
@deco2(with_args=True)
|
||||||
|
# leading 3
|
||||||
|
@deco3
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
# leading 2
|
||||||
|
@deco2(with_args=True)
|
||||||
|
# leading function comment
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# Note: this is fixed in
|
||||||
|
# Preview.empty_lines_before_class_or_def_with_leading_comments.
|
||||||
|
# In the current style, the user will have to split those lines by hand.
|
||||||
|
some_instruction
|
||||||
|
|
||||||
|
|
||||||
|
# This comment should be split from `some_instruction` by two lines but isn't.
|
||||||
|
def g():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -23,7 +23,6 @@
|
||||||
|
try:
|
||||||
|
with open(some_other_file) as w:
|
||||||
|
w.write(data)
|
||||||
|
-
|
||||||
|
except OSError:
|
||||||
|
print("problems")
|
||||||
|
|
||||||
|
@@ -41,18 +40,18 @@
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
-# leading 2
|
||||||
|
-@deco2(with_args=True)
|
||||||
|
-# leading 3
|
||||||
|
-@deco3
|
||||||
|
+@# leading 2
|
||||||
|
+deco2(with_args=True)
|
||||||
|
+@# leading 3
|
||||||
|
+deco3
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
-# leading 2
|
||||||
|
-@deco2(with_args=True)
|
||||||
|
+@# leading 2
|
||||||
|
+deco2(with_args=True)
|
||||||
|
# leading function comment
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
while True:
|
||||||
|
if something.changed:
|
||||||
|
do.stuff() # trailing comment
|
||||||
|
# Comment belongs to the `if` block.
|
||||||
|
# This one belongs to the `while` block.
|
||||||
|
|
||||||
|
# Should this one, too? I guess so.
|
||||||
|
|
||||||
|
# This one is properly standalone now.
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
# first we do this
|
||||||
|
if i % 33 == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# then we do this
|
||||||
|
print(i)
|
||||||
|
# and finally we loop around
|
||||||
|
|
||||||
|
with open(some_temp_file) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(some_other_file) as w:
|
||||||
|
w.write(data)
|
||||||
|
except OSError:
|
||||||
|
print("problems")
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# leading function comment
|
||||||
|
def wat():
|
||||||
|
...
|
||||||
|
# trailing function comment
|
||||||
|
|
||||||
|
|
||||||
|
# SECTION COMMENT
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
@# leading 2
|
||||||
|
deco2(with_args=True)
|
||||||
|
@# leading 3
|
||||||
|
deco3
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
@# leading 2
|
||||||
|
deco2(with_args=True)
|
||||||
|
# leading function comment
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# Note: this is fixed in
|
||||||
|
# Preview.empty_lines_before_class_or_def_with_leading_comments.
|
||||||
|
# In the current style, the user will have to split those lines by hand.
|
||||||
|
some_instruction
|
||||||
|
|
||||||
|
|
||||||
|
# This comment should be split from `some_instruction` by two lines but isn't.
|
||||||
|
def g():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
while True:
|
||||||
|
if something.changed:
|
||||||
|
do.stuff() # trailing comment
|
||||||
|
# Comment belongs to the `if` block.
|
||||||
|
# This one belongs to the `while` block.
|
||||||
|
|
||||||
|
# Should this one, too? I guess so.
|
||||||
|
|
||||||
|
# This one is properly standalone now.
|
||||||
|
|
||||||
|
for i in range(100):
|
||||||
|
# first we do this
|
||||||
|
if i % 33 == 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
# then we do this
|
||||||
|
print(i)
|
||||||
|
# and finally we loop around
|
||||||
|
|
||||||
|
with open(some_temp_file) as f:
|
||||||
|
data = f.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(some_other_file) as w:
|
||||||
|
w.write(data)
|
||||||
|
|
||||||
|
except OSError:
|
||||||
|
print("problems")
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
# leading function comment
|
||||||
|
def wat():
|
||||||
|
...
|
||||||
|
# trailing function comment
|
||||||
|
|
||||||
|
|
||||||
|
# SECTION COMMENT
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
# leading 2
|
||||||
|
@deco2(with_args=True)
|
||||||
|
# leading 3
|
||||||
|
@deco3
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# leading 1
|
||||||
|
@deco1
|
||||||
|
# leading 2
|
||||||
|
@deco2(with_args=True)
|
||||||
|
# leading function comment
|
||||||
|
def decorated1():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
# Note: this is fixed in
|
||||||
|
# Preview.empty_lines_before_class_or_def_with_leading_comments.
|
||||||
|
# In the current style, the user will have to split those lines by hand.
|
||||||
|
some_instruction
|
||||||
|
|
||||||
|
|
||||||
|
# This comment should be split from `some_instruction` by two lines but isn't.
|
||||||
|
def g():
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments_non_breaking_space.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
from .config import ( ConfigTypeAttributes, Int, Path, # String,
|
||||||
|
# DEFAULT_TYPE_ATTRIBUTES,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = 1 # A simple comment
|
||||||
|
result = ( 1, ) # Another one
|
||||||
|
|
||||||
|
result = 1 # type: ignore
|
||||||
|
result = 1# This comment is talking about type: ignore
|
||||||
|
square = Square(4) # type: Optional[Square]
|
||||||
|
|
||||||
|
def function(a:int=42):
|
||||||
|
""" This docstring is already formatted
|
||||||
|
a
|
||||||
|
b
|
||||||
|
"""
|
||||||
|
# There's a NBSP + 3 spaces before
|
||||||
|
# And 4 spaces on the next line
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -1,23 +1,22 @@
|
||||||
|
from .config import (
|
||||||
|
ConfigTypeAttributes,
|
||||||
|
Int,
|
||||||
|
- Path, # String,
|
||||||
|
- # DEFAULT_TYPE_ATTRIBUTES,
|
||||||
|
+ Path, # String,
|
||||||
|
)
|
||||||
|
|
||||||
|
-result = 1 # A simple comment
|
||||||
|
-result = (1,) # Another one
|
||||||
|
+result = 1 # A simple comment
|
||||||
|
+result = (1,) # Another one
|
||||||
|
|
||||||
|
-result = 1 # type: ignore
|
||||||
|
-result = 1 # This comment is talking about type: ignore
|
||||||
|
-square = Square(4) # type: Optional[Square]
|
||||||
|
+result = 1 # type: ignore
|
||||||
|
+result = 1 # This comment is talking about type: ignore
|
||||||
|
+square = Square(4) # type: Optional[Square]
|
||||||
|
|
||||||
|
|
||||||
|
def function(a: int = 42):
|
||||||
|
- """This docstring is already formatted
|
||||||
|
- a
|
||||||
|
- b
|
||||||
|
+ """ This docstring is already formatted
|
||||||
|
+ a
|
||||||
|
+ b
|
||||||
|
"""
|
||||||
|
- # There's a NBSP + 3 spaces before
|
||||||
|
+ # There's a NBSP + 3 spaces before
|
||||||
|
# And 4 spaces on the next line
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
from .config import (
|
||||||
|
ConfigTypeAttributes,
|
||||||
|
Int,
|
||||||
|
Path, # String,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = 1 # A simple comment
|
||||||
|
result = (1,) # Another one
|
||||||
|
|
||||||
|
result = 1 # type: ignore
|
||||||
|
result = 1 # This comment is talking about type: ignore
|
||||||
|
square = Square(4) # type: Optional[Square]
|
||||||
|
|
||||||
|
|
||||||
|
def function(a: int = 42):
|
||||||
|
""" This docstring is already formatted
|
||||||
|
a
|
||||||
|
b
|
||||||
|
"""
|
||||||
|
# There's a NBSP + 3 spaces before
|
||||||
|
# And 4 spaces on the next line
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
from .config import (
|
||||||
|
ConfigTypeAttributes,
|
||||||
|
Int,
|
||||||
|
Path, # String,
|
||||||
|
# DEFAULT_TYPE_ATTRIBUTES,
|
||||||
|
)
|
||||||
|
|
||||||
|
result = 1 # A simple comment
|
||||||
|
result = (1,) # Another one
|
||||||
|
|
||||||
|
result = 1 # type: ignore
|
||||||
|
result = 1 # This comment is talking about type: ignore
|
||||||
|
square = Square(4) # type: Optional[Square]
|
||||||
|
|
||||||
|
|
||||||
|
def function(a: int = 42):
|
||||||
|
"""This docstring is already formatted
|
||||||
|
a
|
||||||
|
b
|
||||||
|
"""
|
||||||
|
# There's a NBSP + 3 spaces before
|
||||||
|
# And 4 spaces on the next line
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,322 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# fmt: on
|
||||||
|
# Some license here.
|
||||||
|
#
|
||||||
|
# Has many lines. Many, many lines.
|
||||||
|
# Many, many, many lines.
|
||||||
|
"""Module docstring.
|
||||||
|
|
||||||
|
Possibly also many, many lines.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import a
|
||||||
|
from b.c import X # some noqa comment
|
||||||
|
|
||||||
|
try:
|
||||||
|
import fast
|
||||||
|
except ImportError:
|
||||||
|
import slow as fast
|
||||||
|
|
||||||
|
|
||||||
|
# Some comment before a function.
|
||||||
|
y = 1
|
||||||
|
(
|
||||||
|
# some strings
|
||||||
|
y # type: ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def function(default=None):
|
||||||
|
"""Docstring comes first.
|
||||||
|
|
||||||
|
Possibly many lines.
|
||||||
|
"""
|
||||||
|
# FIXME: Some comment about why this function is crap but still in production.
|
||||||
|
import inner_imports
|
||||||
|
|
||||||
|
if inner_imports.are_evil():
|
||||||
|
# Explains why we have this if.
|
||||||
|
# In great detail indeed.
|
||||||
|
x = X()
|
||||||
|
return x.method1() # type: ignore
|
||||||
|
|
||||||
|
# This return is also commented for some reason.
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
# Explains why we use global state.
|
||||||
|
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
|
||||||
|
|
||||||
|
|
||||||
|
# Another comment!
|
||||||
|
# This time two lines.
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
"""Docstring for class Foo. Example from Sphinx docs."""
|
||||||
|
|
||||||
|
#: Doc comment for class attribute Foo.bar.
|
||||||
|
#: It can have multiple lines.
|
||||||
|
bar = 1
|
||||||
|
|
||||||
|
flox = 1.5 #: Doc comment for Foo.flox. One line only.
|
||||||
|
|
||||||
|
baz = 2
|
||||||
|
"""Docstring for class attribute Foo.baz."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#: Doc comment for instance attribute qux.
|
||||||
|
self.qux = 3
|
||||||
|
|
||||||
|
self.spam = 4
|
||||||
|
"""Docstring for instance attribute spam."""
|
||||||
|
|
||||||
|
|
||||||
|
#' <h1>This is pweave!</h1>
|
||||||
|
|
||||||
|
|
||||||
|
@fast(really=True)
|
||||||
|
async def wat():
|
||||||
|
# This comment, for some reason \
|
||||||
|
# contains a trailing backslash.
|
||||||
|
async with X.open_async() as x: # Some more comments
|
||||||
|
result = await x.method1()
|
||||||
|
# Comment after ending a block.
|
||||||
|
if result:
|
||||||
|
print("A OK", file=sys.stdout)
|
||||||
|
# Comment between things.
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# Some closing comments.
|
||||||
|
# Maybe Vim or Emacs directives for formatting.
|
||||||
|
# Who knows.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -93,4 +93,4 @@
|
||||||
|
|
||||||
|
# Some closing comments.
|
||||||
|
# Maybe Vim or Emacs directives for formatting.
|
||||||
|
-# Who knows.
|
||||||
|
\ No newline at end of file
|
||||||
|
+# Who knows.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# fmt: on
|
||||||
|
# Some license here.
|
||||||
|
#
|
||||||
|
# Has many lines. Many, many lines.
|
||||||
|
# Many, many, many lines.
|
||||||
|
"""Module docstring.
|
||||||
|
|
||||||
|
Possibly also many, many lines.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import a
|
||||||
|
from b.c import X # some noqa comment
|
||||||
|
|
||||||
|
try:
|
||||||
|
import fast
|
||||||
|
except ImportError:
|
||||||
|
import slow as fast
|
||||||
|
|
||||||
|
|
||||||
|
# Some comment before a function.
|
||||||
|
y = 1
|
||||||
|
(
|
||||||
|
# some strings
|
||||||
|
y # type: ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def function(default=None):
|
||||||
|
"""Docstring comes first.
|
||||||
|
|
||||||
|
Possibly many lines.
|
||||||
|
"""
|
||||||
|
# FIXME: Some comment about why this function is crap but still in production.
|
||||||
|
import inner_imports
|
||||||
|
|
||||||
|
if inner_imports.are_evil():
|
||||||
|
# Explains why we have this if.
|
||||||
|
# In great detail indeed.
|
||||||
|
x = X()
|
||||||
|
return x.method1() # type: ignore
|
||||||
|
|
||||||
|
# This return is also commented for some reason.
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
# Explains why we use global state.
|
||||||
|
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
|
||||||
|
|
||||||
|
|
||||||
|
# Another comment!
|
||||||
|
# This time two lines.
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
"""Docstring for class Foo. Example from Sphinx docs."""
|
||||||
|
|
||||||
|
#: Doc comment for class attribute Foo.bar.
|
||||||
|
#: It can have multiple lines.
|
||||||
|
bar = 1
|
||||||
|
|
||||||
|
flox = 1.5 #: Doc comment for Foo.flox. One line only.
|
||||||
|
|
||||||
|
baz = 2
|
||||||
|
"""Docstring for class attribute Foo.baz."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#: Doc comment for instance attribute qux.
|
||||||
|
self.qux = 3
|
||||||
|
|
||||||
|
self.spam = 4
|
||||||
|
"""Docstring for instance attribute spam."""
|
||||||
|
|
||||||
|
|
||||||
|
#' <h1>This is pweave!</h1>
|
||||||
|
|
||||||
|
|
||||||
|
@fast(really=True)
|
||||||
|
async def wat():
|
||||||
|
# This comment, for some reason \
|
||||||
|
# contains a trailing backslash.
|
||||||
|
async with X.open_async() as x: # Some more comments
|
||||||
|
result = await x.method1()
|
||||||
|
# Comment after ending a block.
|
||||||
|
if result:
|
||||||
|
print("A OK", file=sys.stdout)
|
||||||
|
# Comment between things.
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# Some closing comments.
|
||||||
|
# Maybe Vim or Emacs directives for formatting.
|
||||||
|
# Who knows.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# fmt: on
|
||||||
|
# Some license here.
|
||||||
|
#
|
||||||
|
# Has many lines. Many, many lines.
|
||||||
|
# Many, many, many lines.
|
||||||
|
"""Module docstring.
|
||||||
|
|
||||||
|
Possibly also many, many lines.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import a
|
||||||
|
from b.c import X # some noqa comment
|
||||||
|
|
||||||
|
try:
|
||||||
|
import fast
|
||||||
|
except ImportError:
|
||||||
|
import slow as fast
|
||||||
|
|
||||||
|
|
||||||
|
# Some comment before a function.
|
||||||
|
y = 1
|
||||||
|
(
|
||||||
|
# some strings
|
||||||
|
y # type: ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def function(default=None):
|
||||||
|
"""Docstring comes first.
|
||||||
|
|
||||||
|
Possibly many lines.
|
||||||
|
"""
|
||||||
|
# FIXME: Some comment about why this function is crap but still in production.
|
||||||
|
import inner_imports
|
||||||
|
|
||||||
|
if inner_imports.are_evil():
|
||||||
|
# Explains why we have this if.
|
||||||
|
# In great detail indeed.
|
||||||
|
x = X()
|
||||||
|
return x.method1() # type: ignore
|
||||||
|
|
||||||
|
# This return is also commented for some reason.
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
# Explains why we use global state.
|
||||||
|
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
|
||||||
|
|
||||||
|
|
||||||
|
# Another comment!
|
||||||
|
# This time two lines.
|
||||||
|
|
||||||
|
|
||||||
|
class Foo:
|
||||||
|
"""Docstring for class Foo. Example from Sphinx docs."""
|
||||||
|
|
||||||
|
#: Doc comment for class attribute Foo.bar.
|
||||||
|
#: It can have multiple lines.
|
||||||
|
bar = 1
|
||||||
|
|
||||||
|
flox = 1.5 #: Doc comment for Foo.flox. One line only.
|
||||||
|
|
||||||
|
baz = 2
|
||||||
|
"""Docstring for class attribute Foo.baz."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
#: Doc comment for instance attribute qux.
|
||||||
|
self.qux = 3
|
||||||
|
|
||||||
|
self.spam = 4
|
||||||
|
"""Docstring for instance attribute spam."""
|
||||||
|
|
||||||
|
|
||||||
|
#' <h1>This is pweave!</h1>
|
||||||
|
|
||||||
|
|
||||||
|
@fast(really=True)
|
||||||
|
async def wat():
|
||||||
|
# This comment, for some reason \
|
||||||
|
# contains a trailing backslash.
|
||||||
|
async with X.open_async() as x: # Some more comments
|
||||||
|
result = await x.method1()
|
||||||
|
# Comment after ending a block.
|
||||||
|
if result:
|
||||||
|
print("A OK", file=sys.stdout)
|
||||||
|
# Comment between things.
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# Some closing comments.
|
||||||
|
# Maybe Vim or Emacs directives for formatting.
|
||||||
|
# Who knows.```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,225 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_preview.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring..............................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit():
|
||||||
|
"""first line-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit_with_prefix():
|
||||||
|
f"""first line----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit():
|
||||||
|
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit2():
|
||||||
|
'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -1,9 +1,13 @@
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
- """long docstring................................................................."""
|
||||||
|
+ """long docstring.................................................................
|
||||||
|
+ """
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit_with_prefix():
|
||||||
|
- f"""long docstring................................................................"""
|
||||||
|
+ (
|
||||||
|
+ f"""long docstring................................................................
|
||||||
|
+ """
|
||||||
|
+ )
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit():
|
||||||
|
@@ -14,10 +18,12 @@
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit_with_prefix():
|
||||||
|
- f"""long docstring................................................................
|
||||||
|
+ (
|
||||||
|
+ f"""long docstring................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
+ )
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
@@ -35,9 +41,11 @@
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit_with_prefix():
|
||||||
|
- f"""first line----------------------------------------------------------------------
|
||||||
|
+ (
|
||||||
|
+ f"""first line----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
+ )
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit():
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit_with_prefix():
|
||||||
|
(
|
||||||
|
f"""long docstring................................................................
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit_with_prefix():
|
||||||
|
(
|
||||||
|
f"""long docstring................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring..............................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit():
|
||||||
|
"""first line-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit_with_prefix():
|
||||||
|
(
|
||||||
|
f"""first line----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit():
|
||||||
|
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit2():
|
||||||
|
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
"""long docstring................................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def mulitline_docstring_almost_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit_with_prefix():
|
||||||
|
f"""long docstring..............................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit():
|
||||||
|
"""first line-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit_with_prefix():
|
||||||
|
f"""first line----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit():
|
||||||
|
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
|
||||||
|
|
||||||
|
|
||||||
|
def single_quote_docstring_over_line_limit2():
|
||||||
|
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,925 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
class MyClass:
|
||||||
|
""" Multiline
|
||||||
|
class docstring
|
||||||
|
"""
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
"""Multiline
|
||||||
|
method docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
"""This is a docstring with
|
||||||
|
some lines of text here
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def bar():
|
||||||
|
'''This is another docstring
|
||||||
|
with more lines of text
|
||||||
|
'''
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
'''"This" is a string with some
|
||||||
|
embedded "quotes"'''
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def troz():
|
||||||
|
'''Indentation with tabs
|
||||||
|
is just as OK
|
||||||
|
'''
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def zort():
|
||||||
|
"""Another
|
||||||
|
multiline
|
||||||
|
docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def poit():
|
||||||
|
"""
|
||||||
|
Lorem ipsum dolor sit amet.
|
||||||
|
|
||||||
|
Consectetur adipiscing elit:
|
||||||
|
- sed do eiusmod tempor incididunt ut labore
|
||||||
|
- dolore magna aliqua
|
||||||
|
- enim ad minim veniam
|
||||||
|
- quis nostrud exercitation ullamco laboris nisi
|
||||||
|
- aliquip ex ea commodo consequat
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def under_indent():
|
||||||
|
"""
|
||||||
|
These lines are indented in a way that does not
|
||||||
|
make sense.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def over_indent():
|
||||||
|
"""
|
||||||
|
This has a shallow indent
|
||||||
|
- But some lines are deeper
|
||||||
|
- And the closing quote is too deep
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def single_line():
|
||||||
|
"""But with a newline after it!
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def this():
|
||||||
|
r"""
|
||||||
|
'hey ho'
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def that():
|
||||||
|
""" "hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_that():
|
||||||
|
"""
|
||||||
|
"hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_this():
|
||||||
|
'''
|
||||||
|
"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_whitespace():
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def oneline_whitespace():
|
||||||
|
''' '''
|
||||||
|
|
||||||
|
|
||||||
|
def empty():
|
||||||
|
""""""
|
||||||
|
|
||||||
|
|
||||||
|
def single_quotes():
|
||||||
|
'testing'
|
||||||
|
|
||||||
|
|
||||||
|
def believe_it_or_not_this_is_in_the_py_stdlib(): '''
|
||||||
|
"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def ignored_docstring():
|
||||||
|
"""a => \
|
||||||
|
b"""
|
||||||
|
|
||||||
|
def single_line_docstring_with_whitespace():
|
||||||
|
""" This should be stripped """
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_space_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
tab at start of line and then a tab separated value
|
||||||
|
multiple tabs at the beginning and inline
|
||||||
|
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
|
||||||
|
line ends with some tabs
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_tab_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
tab at start of line and then a tab separated value
|
||||||
|
multiple tabs at the beginning and inline
|
||||||
|
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
|
||||||
|
line ends with some tabs
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def backslash_space():
|
||||||
|
"""\ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_1():
|
||||||
|
'''
|
||||||
|
hey\there\
|
||||||
|
\ '''
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_2():
|
||||||
|
'''
|
||||||
|
hey there \ '''
|
||||||
|
|
||||||
|
# Regression test for #3425
|
||||||
|
def multiline_backslash_really_long_dont_crash():
|
||||||
|
"""
|
||||||
|
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_3():
|
||||||
|
'''
|
||||||
|
already escaped \\ '''
|
||||||
|
|
||||||
|
|
||||||
|
def my_god_its_full_of_stars_1():
|
||||||
|
"I'm sorry Dave\u2001"
|
||||||
|
|
||||||
|
|
||||||
|
# the space below is actually a \u2001, removed in output
|
||||||
|
def my_god_its_full_of_stars_2():
|
||||||
|
"I'm sorry Dave "
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
"""long docstring................................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit2():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit():
|
||||||
|
"""first line-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def stable_quote_normalization_with_immediate_inner_single_quote(self):
|
||||||
|
''''<text here>
|
||||||
|
|
||||||
|
<text here, since without another non-empty line black is stable>
|
||||||
|
'''
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -1,83 +1,85 @@
|
||||||
|
class MyClass:
|
||||||
|
- """Multiline
|
||||||
|
- class docstring
|
||||||
|
- """
|
||||||
|
+ """ Multiline
|
||||||
|
+ class docstring
|
||||||
|
+ """
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
"""Multiline
|
||||||
|
- method docstring
|
||||||
|
- """
|
||||||
|
+ method docstring
|
||||||
|
+ """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
- """This is a docstring with
|
||||||
|
- some lines of text here
|
||||||
|
- """
|
||||||
|
+ """This is a docstring with
|
||||||
|
+ some lines of text here
|
||||||
|
+ """
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def bar():
|
||||||
|
"""This is another docstring
|
||||||
|
- with more lines of text
|
||||||
|
- """
|
||||||
|
+ with more lines of text
|
||||||
|
+ """
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
'''"This" is a string with some
|
||||||
|
- embedded "quotes"'''
|
||||||
|
+ embedded "quotes"'''
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def troz():
|
||||||
|
"""Indentation with tabs
|
||||||
|
- is just as OK
|
||||||
|
- """
|
||||||
|
+ is just as OK
|
||||||
|
+ """
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def zort():
|
||||||
|
"""Another
|
||||||
|
- multiline
|
||||||
|
- docstring
|
||||||
|
- """
|
||||||
|
+ multiline
|
||||||
|
+ docstring
|
||||||
|
+ """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def poit():
|
||||||
|
"""
|
||||||
|
- Lorem ipsum dolor sit amet.
|
||||||
|
+ Lorem ipsum dolor sit amet.
|
||||||
|
|
||||||
|
- Consectetur adipiscing elit:
|
||||||
|
- - sed do eiusmod tempor incididunt ut labore
|
||||||
|
- - dolore magna aliqua
|
||||||
|
- - enim ad minim veniam
|
||||||
|
- - quis nostrud exercitation ullamco laboris nisi
|
||||||
|
- - aliquip ex ea commodo consequat
|
||||||
|
- """
|
||||||
|
+ Consectetur adipiscing elit:
|
||||||
|
+ - sed do eiusmod tempor incididunt ut labore
|
||||||
|
+ - dolore magna aliqua
|
||||||
|
+ - enim ad minim veniam
|
||||||
|
+ - quis nostrud exercitation ullamco laboris nisi
|
||||||
|
+ - aliquip ex ea commodo consequat
|
||||||
|
+ """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def under_indent():
|
||||||
|
"""
|
||||||
|
- These lines are indented in a way that does not
|
||||||
|
- make sense.
|
||||||
|
- """
|
||||||
|
+ These lines are indented in a way that does not
|
||||||
|
+make sense.
|
||||||
|
+ """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def over_indent():
|
||||||
|
"""
|
||||||
|
- This has a shallow indent
|
||||||
|
- - But some lines are deeper
|
||||||
|
- - And the closing quote is too deep
|
||||||
|
+ This has a shallow indent
|
||||||
|
+ - But some lines are deeper
|
||||||
|
+ - And the closing quote is too deep
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def single_line():
|
||||||
|
- """But with a newline after it!"""
|
||||||
|
+ """But with a newline after it!
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@@ -93,20 +95,25 @@
|
||||||
|
|
||||||
|
def and_that():
|
||||||
|
"""
|
||||||
|
- "hey yah" """
|
||||||
|
+ "hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_this():
|
||||||
|
- '''
|
||||||
|
- "hey yah"'''
|
||||||
|
+ '''
|
||||||
|
+ "hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_whitespace():
|
||||||
|
- """ """
|
||||||
|
+ """
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ """
|
||||||
|
|
||||||
|
|
||||||
|
def oneline_whitespace():
|
||||||
|
- """ """
|
||||||
|
+ """ """
|
||||||
|
|
||||||
|
|
||||||
|
def empty():
|
||||||
|
@@ -118,8 +125,8 @@
|
||||||
|
|
||||||
|
|
||||||
|
def believe_it_or_not_this_is_in_the_py_stdlib():
|
||||||
|
- '''
|
||||||
|
- "hey yah"'''
|
||||||
|
+ '''
|
||||||
|
+"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def ignored_docstring():
|
||||||
|
@@ -128,31 +135,31 @@
|
||||||
|
|
||||||
|
|
||||||
|
def single_line_docstring_with_whitespace():
|
||||||
|
- """This should be stripped"""
|
||||||
|
+ """ This should be stripped """
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_space_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
- tab at start of line and then a tab separated value
|
||||||
|
- multiple tabs at the beginning and inline
|
||||||
|
- mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
-
|
||||||
|
- line ends with some tabs
|
||||||
|
+ tab at start of line and then a tab separated value
|
||||||
|
+ multiple tabs at the beginning and inline
|
||||||
|
+ mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
+
|
||||||
|
+ line ends with some tabs
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_tab_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
- tab separated value
|
||||||
|
- tab at start of line and then a tab separated value
|
||||||
|
- multiple tabs at the beginning and inline
|
||||||
|
- mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
-
|
||||||
|
- line ends with some tabs
|
||||||
|
- """
|
||||||
|
+ tab separated value
|
||||||
|
+ tab at start of line and then a tab separated value
|
||||||
|
+ multiple tabs at the beginning and inline
|
||||||
|
+ mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
+
|
||||||
|
+ line ends with some tabs
|
||||||
|
+ """
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@@ -168,7 +175,7 @@
|
||||||
|
|
||||||
|
def multiline_backslash_2():
|
||||||
|
"""
|
||||||
|
- hey there \ """
|
||||||
|
+ hey there \ """
|
||||||
|
|
||||||
|
|
||||||
|
# Regression test for #3425
|
||||||
|
@@ -179,7 +186,7 @@
|
||||||
|
|
||||||
|
def multiline_backslash_3():
|
||||||
|
"""
|
||||||
|
- already escaped \\"""
|
||||||
|
+ already escaped \\ """
|
||||||
|
|
||||||
|
|
||||||
|
def my_god_its_full_of_stars_1():
|
||||||
|
@@ -188,7 +195,7 @@
|
||||||
|
|
||||||
|
# the space below is actually a \u2001, removed in output
|
||||||
|
def my_god_its_full_of_stars_2():
|
||||||
|
- "I'm sorry Dave"
|
||||||
|
+ "I'm sorry Dave "
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
class MyClass:
|
||||||
|
""" Multiline
|
||||||
|
class docstring
|
||||||
|
"""
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
"""Multiline
|
||||||
|
method docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
"""This is a docstring with
|
||||||
|
some lines of text here
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def bar():
|
||||||
|
"""This is another docstring
|
||||||
|
with more lines of text
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
'''"This" is a string with some
|
||||||
|
embedded "quotes"'''
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def troz():
|
||||||
|
"""Indentation with tabs
|
||||||
|
is just as OK
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def zort():
|
||||||
|
"""Another
|
||||||
|
multiline
|
||||||
|
docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def poit():
|
||||||
|
"""
|
||||||
|
Lorem ipsum dolor sit amet.
|
||||||
|
|
||||||
|
Consectetur adipiscing elit:
|
||||||
|
- sed do eiusmod tempor incididunt ut labore
|
||||||
|
- dolore magna aliqua
|
||||||
|
- enim ad minim veniam
|
||||||
|
- quis nostrud exercitation ullamco laboris nisi
|
||||||
|
- aliquip ex ea commodo consequat
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def under_indent():
|
||||||
|
"""
|
||||||
|
These lines are indented in a way that does not
|
||||||
|
make sense.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def over_indent():
|
||||||
|
"""
|
||||||
|
This has a shallow indent
|
||||||
|
- But some lines are deeper
|
||||||
|
- And the closing quote is too deep
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def single_line():
|
||||||
|
"""But with a newline after it!
|
||||||
|
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def this():
|
||||||
|
r"""
|
||||||
|
'hey ho'
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def that():
|
||||||
|
""" "hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_that():
|
||||||
|
"""
|
||||||
|
"hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_this():
|
||||||
|
'''
|
||||||
|
"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_whitespace():
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def oneline_whitespace():
|
||||||
|
""" """
|
||||||
|
|
||||||
|
|
||||||
|
def empty():
|
||||||
|
""""""
|
||||||
|
|
||||||
|
|
||||||
|
def single_quotes():
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
|
||||||
|
def believe_it_or_not_this_is_in_the_py_stdlib():
|
||||||
|
'''
|
||||||
|
"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def ignored_docstring():
|
||||||
|
"""a => \
|
||||||
|
b"""
|
||||||
|
|
||||||
|
|
||||||
|
def single_line_docstring_with_whitespace():
|
||||||
|
""" This should be stripped """
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_space_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
tab at start of line and then a tab separated value
|
||||||
|
multiple tabs at the beginning and inline
|
||||||
|
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
|
||||||
|
line ends with some tabs
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_tab_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
tab at start of line and then a tab separated value
|
||||||
|
multiple tabs at the beginning and inline
|
||||||
|
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
|
||||||
|
line ends with some tabs
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def backslash_space():
|
||||||
|
"""\ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_1():
|
||||||
|
"""
|
||||||
|
hey\there\
|
||||||
|
\ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_2():
|
||||||
|
"""
|
||||||
|
hey there \ """
|
||||||
|
|
||||||
|
|
||||||
|
# Regression test for #3425
|
||||||
|
def multiline_backslash_really_long_dont_crash():
|
||||||
|
"""
|
||||||
|
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_3():
|
||||||
|
"""
|
||||||
|
already escaped \\ """
|
||||||
|
|
||||||
|
|
||||||
|
def my_god_its_full_of_stars_1():
|
||||||
|
"I'm sorry Dave\u2001"
|
||||||
|
|
||||||
|
|
||||||
|
# the space below is actually a \u2001, removed in output
|
||||||
|
def my_god_its_full_of_stars_2():
|
||||||
|
"I'm sorry Dave "
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
"""long docstring................................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit2():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit():
|
||||||
|
"""first line-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def stable_quote_normalization_with_immediate_inner_single_quote(self):
|
||||||
|
"""'<text here>
|
||||||
|
|
||||||
|
<text here, since without another non-empty line black is stable>
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
class MyClass:
|
||||||
|
"""Multiline
|
||||||
|
class docstring
|
||||||
|
"""
|
||||||
|
|
||||||
|
def method(self):
|
||||||
|
"""Multiline
|
||||||
|
method docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def foo():
|
||||||
|
"""This is a docstring with
|
||||||
|
some lines of text here
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def bar():
|
||||||
|
"""This is another docstring
|
||||||
|
with more lines of text
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def baz():
|
||||||
|
'''"This" is a string with some
|
||||||
|
embedded "quotes"'''
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def troz():
|
||||||
|
"""Indentation with tabs
|
||||||
|
is just as OK
|
||||||
|
"""
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def zort():
|
||||||
|
"""Another
|
||||||
|
multiline
|
||||||
|
docstring
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def poit():
|
||||||
|
"""
|
||||||
|
Lorem ipsum dolor sit amet.
|
||||||
|
|
||||||
|
Consectetur adipiscing elit:
|
||||||
|
- sed do eiusmod tempor incididunt ut labore
|
||||||
|
- dolore magna aliqua
|
||||||
|
- enim ad minim veniam
|
||||||
|
- quis nostrud exercitation ullamco laboris nisi
|
||||||
|
- aliquip ex ea commodo consequat
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def under_indent():
|
||||||
|
"""
|
||||||
|
These lines are indented in a way that does not
|
||||||
|
make sense.
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def over_indent():
|
||||||
|
"""
|
||||||
|
This has a shallow indent
|
||||||
|
- But some lines are deeper
|
||||||
|
- And the closing quote is too deep
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def single_line():
|
||||||
|
"""But with a newline after it!"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def this():
|
||||||
|
r"""
|
||||||
|
'hey ho'
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def that():
|
||||||
|
""" "hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_that():
|
||||||
|
"""
|
||||||
|
"hey yah" """
|
||||||
|
|
||||||
|
|
||||||
|
def and_this():
|
||||||
|
'''
|
||||||
|
"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_whitespace():
|
||||||
|
""" """
|
||||||
|
|
||||||
|
|
||||||
|
def oneline_whitespace():
|
||||||
|
""" """
|
||||||
|
|
||||||
|
|
||||||
|
def empty():
|
||||||
|
""""""
|
||||||
|
|
||||||
|
|
||||||
|
def single_quotes():
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
|
||||||
|
def believe_it_or_not_this_is_in_the_py_stdlib():
|
||||||
|
'''
|
||||||
|
"hey yah"'''
|
||||||
|
|
||||||
|
|
||||||
|
def ignored_docstring():
|
||||||
|
"""a => \
|
||||||
|
b"""
|
||||||
|
|
||||||
|
|
||||||
|
def single_line_docstring_with_whitespace():
|
||||||
|
"""This should be stripped"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_space_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
tab at start of line and then a tab separated value
|
||||||
|
multiple tabs at the beginning and inline
|
||||||
|
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
|
||||||
|
line ends with some tabs
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_with_inline_tabs_and_tab_indentation():
|
||||||
|
"""hey
|
||||||
|
|
||||||
|
tab separated value
|
||||||
|
tab at start of line and then a tab separated value
|
||||||
|
multiple tabs at the beginning and inline
|
||||||
|
mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
|
||||||
|
|
||||||
|
line ends with some tabs
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def backslash_space():
|
||||||
|
"""\ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_1():
|
||||||
|
"""
|
||||||
|
hey\there\
|
||||||
|
\ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_2():
|
||||||
|
"""
|
||||||
|
hey there \ """
|
||||||
|
|
||||||
|
|
||||||
|
# Regression test for #3425
|
||||||
|
def multiline_backslash_really_long_dont_crash():
|
||||||
|
"""
|
||||||
|
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_backslash_3():
|
||||||
|
"""
|
||||||
|
already escaped \\"""
|
||||||
|
|
||||||
|
|
||||||
|
def my_god_its_full_of_stars_1():
|
||||||
|
"I'm sorry Dave\u2001"
|
||||||
|
|
||||||
|
|
||||||
|
# the space below is actually a \u2001, removed in output
|
||||||
|
def my_god_its_full_of_stars_2():
|
||||||
|
"I'm sorry Dave"
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit():
|
||||||
|
"""long docstring................................................................."""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_almost_at_line_limit2():
|
||||||
|
"""long docstring.................................................................
|
||||||
|
|
||||||
|
..................................................................................
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def docstring_at_line_limit():
|
||||||
|
"""long docstring................................................................"""
|
||||||
|
|
||||||
|
|
||||||
|
def multiline_docstring_at_line_limit():
|
||||||
|
"""first line-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
second line----------------------------------------------------------------------"""
|
||||||
|
|
||||||
|
|
||||||
|
def stable_quote_normalization_with_immediate_inner_single_quote(self):
|
||||||
|
"""'<text here>
|
||||||
|
|
||||||
|
<text here, since without another non-empty line black is stable>
|
||||||
|
"""
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,898 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from third_party import X, Y, Z
|
||||||
|
|
||||||
|
from library import some_connection, \
|
||||||
|
some_decorator
|
||||||
|
# fmt: off
|
||||||
|
from third_party import (X,
|
||||||
|
Y, Z)
|
||||||
|
# fmt: on
|
||||||
|
f'trigger 3.6 mode'
|
||||||
|
# Comment 1
|
||||||
|
|
||||||
|
# Comment 2
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
def func_no_args():
|
||||||
|
a; b; c
|
||||||
|
if True: raise RuntimeError
|
||||||
|
if False: ...
|
||||||
|
for i in range(10):
|
||||||
|
print(i)
|
||||||
|
continue
|
||||||
|
exec('new-style exec', {}, {})
|
||||||
|
return None
|
||||||
|
async def coroutine(arg, exec=False):
|
||||||
|
'Single-line docstring. Multiline is harder to reformat.'
|
||||||
|
async with some_connection() as conn:
|
||||||
|
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
@asyncio.coroutine
|
||||||
|
@some_decorator(
|
||||||
|
with_args=True,
|
||||||
|
many_args=[1,2,3]
|
||||||
|
)
|
||||||
|
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
|
||||||
|
return text[number:-1]
|
||||||
|
# fmt: on
|
||||||
|
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
|
||||||
|
offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2)))
|
||||||
|
assert task._cancel_stack[:len(old_stack)] == old_stack
|
||||||
|
def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
|
||||||
|
def spaces2(result= _core.Value(None)):
|
||||||
|
...
|
||||||
|
something = {
|
||||||
|
# fmt: off
|
||||||
|
key: 'value',
|
||||||
|
}
|
||||||
|
|
||||||
|
def subscriptlist():
|
||||||
|
atom[
|
||||||
|
# fmt: off
|
||||||
|
'some big and',
|
||||||
|
'complex subscript',
|
||||||
|
# fmt: on
|
||||||
|
goes + here, andhere,
|
||||||
|
]
|
||||||
|
|
||||||
|
def import_as_names():
|
||||||
|
# fmt: off
|
||||||
|
from hello import a, b
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
def testlist_star_expr():
|
||||||
|
# fmt: off
|
||||||
|
a , b = *hello
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
def yield_expr():
|
||||||
|
# fmt: off
|
||||||
|
yield hello
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
'formatted'
|
||||||
|
# fmt: off
|
||||||
|
( yield hello )
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
def example(session):
|
||||||
|
# fmt: off
|
||||||
|
result = session\
|
||||||
|
.query(models.Customer.id)\
|
||||||
|
.filter(models.Customer.account_id == account_id,
|
||||||
|
models.Customer.email == email_address)\
|
||||||
|
.order_by(models.Customer.id.asc())\
|
||||||
|
.all()
|
||||||
|
# fmt: on
|
||||||
|
def off_and_on_without_data():
|
||||||
|
"""All comments here are technically on the same prefix.
|
||||||
|
|
||||||
|
The comments between will be formatted. This is a known limitation.
|
||||||
|
"""
|
||||||
|
# fmt: off
|
||||||
|
|
||||||
|
|
||||||
|
#hey, that won't work
|
||||||
|
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
pass
|
||||||
|
def on_and_off_broken():
|
||||||
|
"""Another known limitation."""
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
this=should.not_be.formatted()
|
||||||
|
and_=indeed . it is not formatted
|
||||||
|
because . the . handling . inside . generate_ignored_nodes()
|
||||||
|
now . considers . multiple . fmt . directives . within . one . prefix
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
# ...but comments still get reformatted even though they should not be
|
||||||
|
# fmt: on
|
||||||
|
def long_lines():
|
||||||
|
if True:
|
||||||
|
typedargslist.extend(
|
||||||
|
gen_annotated_params(ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True)
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
a = (
|
||||||
|
unnecessary_bracket()
|
||||||
|
)
|
||||||
|
# fmt: on
|
||||||
|
_type_comment_re = re.compile(
|
||||||
|
r"""
|
||||||
|
^
|
||||||
|
[\t ]*
|
||||||
|
\#[ ]type:[ ]*
|
||||||
|
(?P<type>
|
||||||
|
[^#\t\n]+?
|
||||||
|
)
|
||||||
|
(?<!ignore) # note: this will force the non-greedy + in <type> to match
|
||||||
|
# a trailing space which is why we need the silliness below
|
||||||
|
(?<!ignore[ ]{1})(?<!ignore[ ]{2})(?<!ignore[ ]{3})(?<!ignore[ ]{4})
|
||||||
|
(?<!ignore[ ]{5})(?<!ignore[ ]{6})(?<!ignore[ ]{7})(?<!ignore[ ]{8})
|
||||||
|
(?<!ignore[ ]{9})(?<!ignore[ ]{10})
|
||||||
|
[\t ]*
|
||||||
|
(?P<nl>
|
||||||
|
(?:\#[^\n]*)?
|
||||||
|
\n?
|
||||||
|
)
|
||||||
|
$
|
||||||
|
""",
|
||||||
|
# fmt: off
|
||||||
|
re.MULTILINE|re.VERBOSE
|
||||||
|
# fmt: on
|
||||||
|
)
|
||||||
|
def single_literal_yapf_disable():
|
||||||
|
"""Black does not support this."""
|
||||||
|
BAZ = {
|
||||||
|
(1, 2, 3, 4),
|
||||||
|
(5, 6, 7, 8),
|
||||||
|
(9, 10, 11, 12)
|
||||||
|
} # yapf: disable
|
||||||
|
cfg.rule(
|
||||||
|
"Default", "address",
|
||||||
|
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
|
||||||
|
xxxxxx="xx_xxxxx", xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||||
|
xxxxxxxxx_xxxx=True, xxxxxxxx_xxxxxxxxxx=False,
|
||||||
|
xxxxxx_xxxxxx=2, xxxxxx_xxxxx_xxxxxxxx=70, xxxxxx_xxxxxx_xxxxx=True,
|
||||||
|
# fmt: off
|
||||||
|
xxxxxxx_xxxxxxxxxxxx={
|
||||||
|
"xxxxxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": False,
|
||||||
|
"xxxx_xxxxxx": "xxxxx",
|
||||||
|
},
|
||||||
|
"xxxxxxxx-xxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": True,
|
||||||
|
"xxxx_xxxxxx": "xxxxxx",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# fmt: on
|
||||||
|
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
yield 'hello'
|
||||||
|
# No formatting to the end of the file
|
||||||
|
l=[1,2,3]
|
||||||
|
d={'a':1,
|
||||||
|
'b':2}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -5,39 +5,53 @@
|
||||||
|
from third_party import X, Y, Z
|
||||||
|
|
||||||
|
from library import some_connection, some_decorator
|
||||||
|
+# fmt: off
|
||||||
|
+from third_party import X, Y, Z
|
||||||
|
|
||||||
|
-# fmt: off
|
||||||
|
-from third_party import (X,
|
||||||
|
- Y, Z)
|
||||||
|
# fmt: on
|
||||||
|
-f"trigger 3.6 mode"
|
||||||
|
+f'trigger 3.6 mode'
|
||||||
|
+
|
||||||
|
+
|
||||||
|
# Comment 1
|
||||||
|
|
||||||
|
# Comment 2
|
||||||
|
-
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
def func_no_args():
|
||||||
|
- a; b; c
|
||||||
|
- if True: raise RuntimeError
|
||||||
|
- if False: ...
|
||||||
|
- for i in range(10):
|
||||||
|
- print(i)
|
||||||
|
- continue
|
||||||
|
- exec('new-style exec', {}, {})
|
||||||
|
- return None
|
||||||
|
+ a
|
||||||
|
+ b
|
||||||
|
+ c
|
||||||
|
+ if True:
|
||||||
|
+ raise RuntimeError
|
||||||
|
+ if False:
|
||||||
|
+ ...
|
||||||
|
+ for i in range(10):
|
||||||
|
+ print(i)
|
||||||
|
+ continue
|
||||||
|
+ exec("new-style exec", {}, {})
|
||||||
|
+ return None
|
||||||
|
+
|
||||||
|
+
|
||||||
|
async def coroutine(arg, exec=False):
|
||||||
|
- 'Single-line docstring. Multiline is harder to reformat.'
|
||||||
|
- async with some_connection() as conn:
|
||||||
|
- await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
|
||||||
|
- await asyncio.sleep(1)
|
||||||
|
+ "Single-line docstring. Multiline is harder to reformat."
|
||||||
|
+ async with some_connection() as conn:
|
||||||
|
+ await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
|
||||||
|
+ await asyncio.sleep(1)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
@asyncio.coroutine
|
||||||
|
-@some_decorator(
|
||||||
|
-with_args=True,
|
||||||
|
-many_args=[1,2,3]
|
||||||
|
-)
|
||||||
|
-def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
|
||||||
|
- return text[number:-1]
|
||||||
|
+@some_decorator(with_args=True, many_args=[1, 2, 3])
|
||||||
|
+def function_signature_stress_test(
|
||||||
|
+ number: int,
|
||||||
|
+ no_annotation=None,
|
||||||
|
+ text: str = "default",
|
||||||
|
+ *,
|
||||||
|
+ debug: bool = False,
|
||||||
|
+ **kwargs,
|
||||||
|
+) -> str:
|
||||||
|
+ return text[number:-1]
|
||||||
|
+
|
||||||
|
+
|
||||||
|
# fmt: on
|
||||||
|
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
|
||||||
|
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
|
||||||
|
@@ -64,55 +78,55 @@
|
||||||
|
|
||||||
|
something = {
|
||||||
|
# fmt: off
|
||||||
|
- key: 'value',
|
||||||
|
+ key: "value",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def subscriptlist():
|
||||||
|
atom[
|
||||||
|
# fmt: off
|
||||||
|
- 'some big and',
|
||||||
|
- 'complex subscript',
|
||||||
|
+ "some big and",
|
||||||
|
+ "complex subscript",
|
||||||
|
# fmt: on
|
||||||
|
- goes + here,
|
||||||
|
+ goes
|
||||||
|
+ + here,
|
||||||
|
andhere,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def import_as_names():
|
||||||
|
# fmt: off
|
||||||
|
- from hello import a, b
|
||||||
|
- 'unformatted'
|
||||||
|
+ from hello import a, b
|
||||||
|
+
|
||||||
|
+ "unformatted"
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def testlist_star_expr():
|
||||||
|
# fmt: off
|
||||||
|
- a , b = *hello
|
||||||
|
- 'unformatted'
|
||||||
|
+ a, b = *hello
|
||||||
|
+ "unformatted"
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def yield_expr():
|
||||||
|
# fmt: off
|
||||||
|
yield hello
|
||||||
|
- 'unformatted'
|
||||||
|
+ "unformatted"
|
||||||
|
# fmt: on
|
||||||
|
"formatted"
|
||||||
|
# fmt: off
|
||||||
|
- ( yield hello )
|
||||||
|
- 'unformatted'
|
||||||
|
+ (yield hello)
|
||||||
|
+ "unformatted"
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def example(session):
|
||||||
|
# fmt: off
|
||||||
|
- result = session\
|
||||||
|
- .query(models.Customer.id)\
|
||||||
|
- .filter(models.Customer.account_id == account_id,
|
||||||
|
- models.Customer.email == email_address)\
|
||||||
|
- .order_by(models.Customer.id.asc())\
|
||||||
|
- .all()
|
||||||
|
+ result = session.query(models.Customer.id).filter(
|
||||||
|
+ models.Customer.account_id == account_id,
|
||||||
|
+ models.Customer.email == email_address,
|
||||||
|
+ ).order_by(models.Customer.id.asc()).all()
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
@@ -123,7 +137,7 @@
|
||||||
|
"""
|
||||||
|
# fmt: off
|
||||||
|
|
||||||
|
- # hey, that won't work
|
||||||
|
+ #hey, that won't work
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
pass
|
||||||
|
@@ -133,10 +147,10 @@
|
||||||
|
"""Another known limitation."""
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
- this=should.not_be.formatted()
|
||||||
|
- and_=indeed . it is not formatted
|
||||||
|
- because . the . handling . inside . generate_ignored_nodes()
|
||||||
|
- now . considers . multiple . fmt . directives . within . one . prefix
|
||||||
|
+ this = should.not_be.formatted()
|
||||||
|
+ and_ = indeed.it is not formatted
|
||||||
|
+ because.the.handling.inside.generate_ignored_nodes()
|
||||||
|
+ now.considers.multiple.fmt.directives.within.one.prefix
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
# ...but comments still get reformatted even though they should not be
|
||||||
|
@@ -154,9 +168,7 @@
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
- a = (
|
||||||
|
- unnecessary_bracket()
|
||||||
|
- )
|
||||||
|
+ a = unnecessary_bracket()
|
||||||
|
# fmt: on
|
||||||
|
_type_comment_re = re.compile(
|
||||||
|
r"""
|
||||||
|
@@ -179,7 +191,8 @@
|
||||||
|
$
|
||||||
|
""",
|
||||||
|
# fmt: off
|
||||||
|
- re.MULTILINE|re.VERBOSE
|
||||||
|
+ re.MULTILINE
|
||||||
|
+ | re.VERBOSE,
|
||||||
|
# fmt: on
|
||||||
|
)
|
||||||
|
|
||||||
|
@@ -200,8 +213,8 @@
|
||||||
|
xxxxxx_xxxxxx=2,
|
||||||
|
xxxxxx_xxxxx_xxxxxxxx=70,
|
||||||
|
xxxxxx_xxxxxx_xxxxx=True,
|
||||||
|
- # fmt: off
|
||||||
|
- xxxxxxx_xxxxxxxxxxxx={
|
||||||
|
+ xxxxxxx_xxxxxxxxxxxx=# fmt: off
|
||||||
|
+ {
|
||||||
|
"xxxxxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": False,
|
||||||
|
@@ -213,12 +226,11 @@
|
||||||
|
"xxxx_xxxxxx": "xxxxxx",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
- # fmt: on
|
||||||
|
- xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||||
|
+ xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=# fmt: on
|
||||||
|
+ 5,
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
-yield 'hello'
|
||||||
|
+yield "hello"
|
||||||
|
# No formatting to the end of the file
|
||||||
|
-l=[1,2,3]
|
||||||
|
-d={'a':1,
|
||||||
|
- 'b':2}
|
||||||
|
+l = [1, 2, 3]
|
||||||
|
+d = {"a": 1, "b": 2}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from third_party import X, Y, Z
|
||||||
|
|
||||||
|
from library import some_connection, some_decorator
|
||||||
|
# fmt: off
|
||||||
|
from third_party import X, Y, Z
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
f'trigger 3.6 mode'
|
||||||
|
|
||||||
|
|
||||||
|
# Comment 1
|
||||||
|
|
||||||
|
# Comment 2
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
def func_no_args():
|
||||||
|
a
|
||||||
|
b
|
||||||
|
c
|
||||||
|
if True:
|
||||||
|
raise RuntimeError
|
||||||
|
if False:
|
||||||
|
...
|
||||||
|
for i in range(10):
|
||||||
|
print(i)
|
||||||
|
continue
|
||||||
|
exec("new-style exec", {}, {})
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
async def coroutine(arg, exec=False):
|
||||||
|
"Single-line docstring. Multiline is harder to reformat."
|
||||||
|
async with some_connection() as conn:
|
||||||
|
await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
@asyncio.coroutine
|
||||||
|
@some_decorator(with_args=True, many_args=[1, 2, 3])
|
||||||
|
def function_signature_stress_test(
|
||||||
|
number: int,
|
||||||
|
no_annotation=None,
|
||||||
|
text: str = "default",
|
||||||
|
*,
|
||||||
|
debug: bool = False,
|
||||||
|
**kwargs,
|
||||||
|
) -> str:
|
||||||
|
return text[number:-1]
|
||||||
|
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
|
||||||
|
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
|
||||||
|
assert task._cancel_stack[: len(old_stack)] == old_stack
|
||||||
|
|
||||||
|
|
||||||
|
def spaces_types(
|
||||||
|
a: int = 1,
|
||||||
|
b: tuple = (),
|
||||||
|
c: list = [],
|
||||||
|
d: dict = {},
|
||||||
|
e: bool = True,
|
||||||
|
f: int = -1,
|
||||||
|
g: int = 1 if False else 2,
|
||||||
|
h: str = "",
|
||||||
|
i: str = r"",
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def spaces2(result=_core.Value(None)):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
something = {
|
||||||
|
# fmt: off
|
||||||
|
key: "value",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def subscriptlist():
|
||||||
|
atom[
|
||||||
|
# fmt: off
|
||||||
|
"some big and",
|
||||||
|
"complex subscript",
|
||||||
|
# fmt: on
|
||||||
|
goes
|
||||||
|
+ here,
|
||||||
|
andhere,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def import_as_names():
|
||||||
|
# fmt: off
|
||||||
|
from hello import a, b
|
||||||
|
|
||||||
|
"unformatted"
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def testlist_star_expr():
|
||||||
|
# fmt: off
|
||||||
|
a, b = *hello
|
||||||
|
"unformatted"
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def yield_expr():
|
||||||
|
# fmt: off
|
||||||
|
yield hello
|
||||||
|
"unformatted"
|
||||||
|
# fmt: on
|
||||||
|
"formatted"
|
||||||
|
# fmt: off
|
||||||
|
(yield hello)
|
||||||
|
"unformatted"
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def example(session):
|
||||||
|
# fmt: off
|
||||||
|
result = session.query(models.Customer.id).filter(
|
||||||
|
models.Customer.account_id == account_id,
|
||||||
|
models.Customer.email == email_address,
|
||||||
|
).order_by(models.Customer.id.asc()).all()
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def off_and_on_without_data():
|
||||||
|
"""All comments here are technically on the same prefix.
|
||||||
|
|
||||||
|
The comments between will be formatted. This is a known limitation.
|
||||||
|
"""
|
||||||
|
# fmt: off
|
||||||
|
|
||||||
|
#hey, that won't work
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def on_and_off_broken():
|
||||||
|
"""Another known limitation."""
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
this = should.not_be.formatted()
|
||||||
|
and_ = indeed.it is not formatted
|
||||||
|
because.the.handling.inside.generate_ignored_nodes()
|
||||||
|
now.considers.multiple.fmt.directives.within.one.prefix
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
# ...but comments still get reformatted even though they should not be
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def long_lines():
|
||||||
|
if True:
|
||||||
|
typedargslist.extend(
|
||||||
|
gen_annotated_params(
|
||||||
|
ast_args.kwonlyargs,
|
||||||
|
ast_args.kw_defaults,
|
||||||
|
parameters,
|
||||||
|
implicit_default=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
a = unnecessary_bracket()
|
||||||
|
# fmt: on
|
||||||
|
_type_comment_re = re.compile(
|
||||||
|
r"""
|
||||||
|
^
|
||||||
|
[\t ]*
|
||||||
|
\#[ ]type:[ ]*
|
||||||
|
(?P<type>
|
||||||
|
[^#\t\n]+?
|
||||||
|
)
|
||||||
|
(?<!ignore) # note: this will force the non-greedy + in <type> to match
|
||||||
|
# a trailing space which is why we need the silliness below
|
||||||
|
(?<!ignore[ ]{1})(?<!ignore[ ]{2})(?<!ignore[ ]{3})(?<!ignore[ ]{4})
|
||||||
|
(?<!ignore[ ]{5})(?<!ignore[ ]{6})(?<!ignore[ ]{7})(?<!ignore[ ]{8})
|
||||||
|
(?<!ignore[ ]{9})(?<!ignore[ ]{10})
|
||||||
|
[\t ]*
|
||||||
|
(?P<nl>
|
||||||
|
(?:\#[^\n]*)?
|
||||||
|
\n?
|
||||||
|
)
|
||||||
|
$
|
||||||
|
""",
|
||||||
|
# fmt: off
|
||||||
|
re.MULTILINE
|
||||||
|
| re.VERBOSE,
|
||||||
|
# fmt: on
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def single_literal_yapf_disable():
|
||||||
|
"""Black does not support this."""
|
||||||
|
BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable
|
||||||
|
|
||||||
|
|
||||||
|
cfg.rule(
|
||||||
|
"Default",
|
||||||
|
"address",
|
||||||
|
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
|
||||||
|
xxxxxx="xx_xxxxx",
|
||||||
|
xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||||
|
xxxxxxxxx_xxxx=True,
|
||||||
|
xxxxxxxx_xxxxxxxxxx=False,
|
||||||
|
xxxxxx_xxxxxx=2,
|
||||||
|
xxxxxx_xxxxx_xxxxxxxx=70,
|
||||||
|
xxxxxx_xxxxxx_xxxxx=True,
|
||||||
|
xxxxxxx_xxxxxxxxxxxx=# fmt: off
|
||||||
|
{
|
||||||
|
"xxxxxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": False,
|
||||||
|
"xxxx_xxxxxx": "xxxxx",
|
||||||
|
},
|
||||||
|
"xxxxxxxx-xxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": True,
|
||||||
|
"xxxx_xxxxxx": "xxxxxx",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=# fmt: on
|
||||||
|
5,
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
yield "hello"
|
||||||
|
# No formatting to the end of the file
|
||||||
|
l = [1, 2, 3]
|
||||||
|
d = {"a": 1, "b": 2}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
import asyncio
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from third_party import X, Y, Z
|
||||||
|
|
||||||
|
from library import some_connection, some_decorator
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
from third_party import (X,
|
||||||
|
Y, Z)
|
||||||
|
# fmt: on
|
||||||
|
f"trigger 3.6 mode"
|
||||||
|
# Comment 1
|
||||||
|
|
||||||
|
# Comment 2
|
||||||
|
|
||||||
|
|
||||||
|
# fmt: off
|
||||||
|
def func_no_args():
|
||||||
|
a; b; c
|
||||||
|
if True: raise RuntimeError
|
||||||
|
if False: ...
|
||||||
|
for i in range(10):
|
||||||
|
print(i)
|
||||||
|
continue
|
||||||
|
exec('new-style exec', {}, {})
|
||||||
|
return None
|
||||||
|
async def coroutine(arg, exec=False):
|
||||||
|
'Single-line docstring. Multiline is harder to reformat.'
|
||||||
|
async with some_connection() as conn:
|
||||||
|
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
@asyncio.coroutine
|
||||||
|
@some_decorator(
|
||||||
|
with_args=True,
|
||||||
|
many_args=[1,2,3]
|
||||||
|
)
|
||||||
|
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
|
||||||
|
return text[number:-1]
|
||||||
|
# fmt: on
|
||||||
|
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
|
||||||
|
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
|
||||||
|
assert task._cancel_stack[: len(old_stack)] == old_stack
|
||||||
|
|
||||||
|
|
||||||
|
def spaces_types(
|
||||||
|
a: int = 1,
|
||||||
|
b: tuple = (),
|
||||||
|
c: list = [],
|
||||||
|
d: dict = {},
|
||||||
|
e: bool = True,
|
||||||
|
f: int = -1,
|
||||||
|
g: int = 1 if False else 2,
|
||||||
|
h: str = "",
|
||||||
|
i: str = r"",
|
||||||
|
):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
def spaces2(result=_core.Value(None)):
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
something = {
|
||||||
|
# fmt: off
|
||||||
|
key: 'value',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def subscriptlist():
|
||||||
|
atom[
|
||||||
|
# fmt: off
|
||||||
|
'some big and',
|
||||||
|
'complex subscript',
|
||||||
|
# fmt: on
|
||||||
|
goes + here,
|
||||||
|
andhere,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def import_as_names():
|
||||||
|
# fmt: off
|
||||||
|
from hello import a, b
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def testlist_star_expr():
|
||||||
|
# fmt: off
|
||||||
|
a , b = *hello
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def yield_expr():
|
||||||
|
# fmt: off
|
||||||
|
yield hello
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
"formatted"
|
||||||
|
# fmt: off
|
||||||
|
( yield hello )
|
||||||
|
'unformatted'
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def example(session):
|
||||||
|
# fmt: off
|
||||||
|
result = session\
|
||||||
|
.query(models.Customer.id)\
|
||||||
|
.filter(models.Customer.account_id == account_id,
|
||||||
|
models.Customer.email == email_address)\
|
||||||
|
.order_by(models.Customer.id.asc())\
|
||||||
|
.all()
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def off_and_on_without_data():
|
||||||
|
"""All comments here are technically on the same prefix.
|
||||||
|
|
||||||
|
The comments between will be formatted. This is a known limitation.
|
||||||
|
"""
|
||||||
|
# fmt: off
|
||||||
|
|
||||||
|
# hey, that won't work
|
||||||
|
|
||||||
|
# fmt: on
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def on_and_off_broken():
|
||||||
|
"""Another known limitation."""
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
this=should.not_be.formatted()
|
||||||
|
and_=indeed . it is not formatted
|
||||||
|
because . the . handling . inside . generate_ignored_nodes()
|
||||||
|
now . considers . multiple . fmt . directives . within . one . prefix
|
||||||
|
# fmt: on
|
||||||
|
# fmt: off
|
||||||
|
# ...but comments still get reformatted even though they should not be
|
||||||
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
|
def long_lines():
|
||||||
|
if True:
|
||||||
|
typedargslist.extend(
|
||||||
|
gen_annotated_params(
|
||||||
|
ast_args.kwonlyargs,
|
||||||
|
ast_args.kw_defaults,
|
||||||
|
parameters,
|
||||||
|
implicit_default=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
a = (
|
||||||
|
unnecessary_bracket()
|
||||||
|
)
|
||||||
|
# fmt: on
|
||||||
|
_type_comment_re = re.compile(
|
||||||
|
r"""
|
||||||
|
^
|
||||||
|
[\t ]*
|
||||||
|
\#[ ]type:[ ]*
|
||||||
|
(?P<type>
|
||||||
|
[^#\t\n]+?
|
||||||
|
)
|
||||||
|
(?<!ignore) # note: this will force the non-greedy + in <type> to match
|
||||||
|
# a trailing space which is why we need the silliness below
|
||||||
|
(?<!ignore[ ]{1})(?<!ignore[ ]{2})(?<!ignore[ ]{3})(?<!ignore[ ]{4})
|
||||||
|
(?<!ignore[ ]{5})(?<!ignore[ ]{6})(?<!ignore[ ]{7})(?<!ignore[ ]{8})
|
||||||
|
(?<!ignore[ ]{9})(?<!ignore[ ]{10})
|
||||||
|
[\t ]*
|
||||||
|
(?P<nl>
|
||||||
|
(?:\#[^\n]*)?
|
||||||
|
\n?
|
||||||
|
)
|
||||||
|
$
|
||||||
|
""",
|
||||||
|
# fmt: off
|
||||||
|
re.MULTILINE|re.VERBOSE
|
||||||
|
# fmt: on
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def single_literal_yapf_disable():
|
||||||
|
"""Black does not support this."""
|
||||||
|
BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable
|
||||||
|
|
||||||
|
|
||||||
|
cfg.rule(
|
||||||
|
"Default",
|
||||||
|
"address",
|
||||||
|
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
|
||||||
|
xxxxxx="xx_xxxxx",
|
||||||
|
xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
|
||||||
|
xxxxxxxxx_xxxx=True,
|
||||||
|
xxxxxxxx_xxxxxxxxxx=False,
|
||||||
|
xxxxxx_xxxxxx=2,
|
||||||
|
xxxxxx_xxxxx_xxxxxxxx=70,
|
||||||
|
xxxxxx_xxxxxx_xxxxx=True,
|
||||||
|
# fmt: off
|
||||||
|
xxxxxxx_xxxxxxxxxxxx={
|
||||||
|
"xxxxxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": False,
|
||||||
|
"xxxx_xxxxxx": "xxxxx",
|
||||||
|
},
|
||||||
|
"xxxxxxxx-xxxxx": {
|
||||||
|
"xxxxxx": False,
|
||||||
|
"xxxxxxx": True,
|
||||||
|
"xxxx_xxxxxx": "xxxxxx",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
# fmt: on
|
||||||
|
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||||
|
)
|
||||||
|
# fmt: off
|
||||||
|
yield 'hello'
|
||||||
|
# No formatting to the end of the file
|
||||||
|
l=[1,2,3]
|
||||||
|
d={'a':1,
|
||||||
|
'b':2}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,293 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/src/lib.rs
|
||||||
|
expression: snapshot
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
|
||||||
|
```py
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
def some_func( unformatted, args ): # fmt: skip
|
||||||
|
print("I am some_func")
|
||||||
|
return 0
|
||||||
|
# Make sure this comment is not removed.
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
async def some_async_func( unformatted, args): # fmt: skip
|
||||||
|
print("I am some_async_func")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
class SomeClass( Unformatted, SuperClasses ): # fmt: skip
|
||||||
|
def some_method( self, unformatted, args ): # fmt: skip
|
||||||
|
print("I am some_method")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
async def some_async_method( self, unformatted, args ): # fmt: skip
|
||||||
|
print("I am some_async_method")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
if unformatted_call( args ): # fmt: skip
|
||||||
|
print("First branch")
|
||||||
|
# Make sure this is not removed.
|
||||||
|
elif another_unformatted_call( args ): # fmt: skip
|
||||||
|
print("Second branch")
|
||||||
|
else : # fmt: skip
|
||||||
|
print("Last branch")
|
||||||
|
|
||||||
|
|
||||||
|
while some_condition( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
for i in some_iter( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_for():
|
||||||
|
async for i in some_async_iter( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
try : # fmt: skip
|
||||||
|
some_call()
|
||||||
|
except UnformattedError as ex: # fmt: skip
|
||||||
|
handle_exception()
|
||||||
|
finally : # fmt: skip
|
||||||
|
finally_call()
|
||||||
|
|
||||||
|
|
||||||
|
with give_me_context( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_with():
|
||||||
|
async with give_me_async_context( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Differences
|
||||||
|
|
||||||
|
```diff
|
||||||
|
--- Black
|
||||||
|
+++ Ruff
|
||||||
|
@@ -1,62 +1,62 @@
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
-def some_func( unformatted, args ): # fmt: skip
|
||||||
|
+def some_func(unformatted, args): # fmt: skip
|
||||||
|
print("I am some_func")
|
||||||
|
return 0
|
||||||
|
# Make sure this comment is not removed.
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
-async def some_async_func( unformatted, args): # fmt: skip
|
||||||
|
+async def some_async_func(unformatted, args): # fmt: skip
|
||||||
|
print("I am some_async_func")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
-class SomeClass( Unformatted, SuperClasses ): # fmt: skip
|
||||||
|
- def some_method( self, unformatted, args ): # fmt: skip
|
||||||
|
+class SomeClass(Unformatted, SuperClasses): # fmt: skip
|
||||||
|
+ def some_method(self, unformatted, args): # fmt: skip
|
||||||
|
print("I am some_method")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
- async def some_async_method( self, unformatted, args ): # fmt: skip
|
||||||
|
+ async def some_async_method(self, unformatted, args): # fmt: skip
|
||||||
|
print("I am some_async_method")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
-if unformatted_call( args ): # fmt: skip
|
||||||
|
+if unformatted_call(args): # fmt: skip
|
||||||
|
print("First branch")
|
||||||
|
# Make sure this is not removed.
|
||||||
|
-elif another_unformatted_call( args ): # fmt: skip
|
||||||
|
+elif another_unformatted_call(args): # fmt: skip
|
||||||
|
print("Second branch")
|
||||||
|
-else : # fmt: skip
|
||||||
|
+else: # fmt: skip
|
||||||
|
print("Last branch")
|
||||||
|
|
||||||
|
|
||||||
|
-while some_condition( unformatted, args ): # fmt: skip
|
||||||
|
+while some_condition(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
-for i in some_iter( unformatted, args ): # fmt: skip
|
||||||
|
+for i in some_iter(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_for():
|
||||||
|
- async for i in some_async_iter( unformatted, args ): # fmt: skip
|
||||||
|
+ async for i in some_async_iter(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
-try : # fmt: skip
|
||||||
|
+try: # fmt: skip
|
||||||
|
some_call()
|
||||||
|
-except UnformattedError as ex: # fmt: skip
|
||||||
|
+except UnformattedError as ex:
|
||||||
|
handle_exception()
|
||||||
|
-finally : # fmt: skip
|
||||||
|
+finally: # fmt: skip
|
||||||
|
finally_call()
|
||||||
|
|
||||||
|
|
||||||
|
-with give_me_context( unformatted, args ): # fmt: skip
|
||||||
|
+with give_me_context(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_with():
|
||||||
|
- async with give_me_async_context( unformatted, args ): # fmt: skip
|
||||||
|
+ async with give_me_async_context(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ruff Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
def some_func(unformatted, args): # fmt: skip
|
||||||
|
print("I am some_func")
|
||||||
|
return 0
|
||||||
|
# Make sure this comment is not removed.
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
async def some_async_func(unformatted, args): # fmt: skip
|
||||||
|
print("I am some_async_func")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
class SomeClass(Unformatted, SuperClasses): # fmt: skip
|
||||||
|
def some_method(self, unformatted, args): # fmt: skip
|
||||||
|
print("I am some_method")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
async def some_async_method(self, unformatted, args): # fmt: skip
|
||||||
|
print("I am some_async_method")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
if unformatted_call(args): # fmt: skip
|
||||||
|
print("First branch")
|
||||||
|
# Make sure this is not removed.
|
||||||
|
elif another_unformatted_call(args): # fmt: skip
|
||||||
|
print("Second branch")
|
||||||
|
else: # fmt: skip
|
||||||
|
print("Last branch")
|
||||||
|
|
||||||
|
|
||||||
|
while some_condition(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
for i in some_iter(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_for():
|
||||||
|
async for i in some_async_iter(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
try: # fmt: skip
|
||||||
|
some_call()
|
||||||
|
except UnformattedError as ex:
|
||||||
|
handle_exception()
|
||||||
|
finally: # fmt: skip
|
||||||
|
finally_call()
|
||||||
|
|
||||||
|
|
||||||
|
with give_me_context(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_with():
|
||||||
|
async with give_me_async_context(unformatted, args): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Black Output
|
||||||
|
|
||||||
|
```py
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
def some_func( unformatted, args ): # fmt: skip
|
||||||
|
print("I am some_func")
|
||||||
|
return 0
|
||||||
|
# Make sure this comment is not removed.
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
async def some_async_func( unformatted, args): # fmt: skip
|
||||||
|
print("I am some_async_func")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
class SomeClass( Unformatted, SuperClasses ): # fmt: skip
|
||||||
|
def some_method( self, unformatted, args ): # fmt: skip
|
||||||
|
print("I am some_method")
|
||||||
|
return 0
|
||||||
|
|
||||||
|
async def some_async_method( self, unformatted, args ): # fmt: skip
|
||||||
|
print("I am some_async_method")
|
||||||
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
# Make sure a leading comment is not removed.
|
||||||
|
if unformatted_call( args ): # fmt: skip
|
||||||
|
print("First branch")
|
||||||
|
# Make sure this is not removed.
|
||||||
|
elif another_unformatted_call( args ): # fmt: skip
|
||||||
|
print("Second branch")
|
||||||
|
else : # fmt: skip
|
||||||
|
print("Last branch")
|
||||||
|
|
||||||
|
|
||||||
|
while some_condition( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
for i in some_iter( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_for():
|
||||||
|
async for i in some_async_iter( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
try : # fmt: skip
|
||||||
|
some_call()
|
||||||
|
except UnformattedError as ex: # fmt: skip
|
||||||
|
handle_exception()
|
||||||
|
finally : # fmt: skip
|
||||||
|
finally_call()
|
||||||
|
|
||||||
|
|
||||||
|
with give_me_context( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_async_with():
|
||||||
|
async with give_me_async_context( unformatted, args ): # fmt: skip
|
||||||
|
print("Do something")
|
||||||
|
```
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue