mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-24 05:25:17 +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",
|
||||
// Excluded tests because they reach unreachable when attaching tokens
|
||||
exclude = [
|
||||
"*comments.py",
|
||||
"*comments[3,5,8].py",
|
||||
"*comments_non_breaking_space.py",
|
||||
"*docstring_preview.py",
|
||||
"*docstring.py",
|
||||
"*fmtonoff.py",
|
||||
"*fmtskip8.py",
|
||||
"*comments8.py",
|
||||
])
|
||||
]
|
||||
#[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