Implement basic module formatting (#4784)

* Add Format for Stmt

* Implement basic module formatting

This implements formatting each statement in a module with a hard line break in between, so that we can start formatting statements.

Basic testing is done by the snapshots
This commit is contained in:
konstin 2023-06-01 15:25:50 +02:00 committed by GitHub
parent 28aad95414
commit 63d892f1e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 2926 additions and 1171 deletions

1
.gitignore vendored
View file

@ -5,6 +5,7 @@ ruff-old
github_search*.jsonl github_search*.jsonl
schemastore schemastore
.venv* .venv*
scratch.py
### ###
# Rust.gitignore # Rust.gitignore

View file

@ -180,11 +180,8 @@ if True:
print( "hi" ) print( "hi" )
# trailing # trailing
"#; "#;
let expected = r#" let expected = r#"if True:
# preceding
if True:
print( "hi" ) print( "hi" )
# trailing
"#; "#;
let actual = format_module(input)?.as_code().to_string(); let actual = format_module(input)?.as_code().to_string();
assert_eq!(expected, actual); assert_eq!(expected, actual);

View file

@ -1,5 +1,8 @@
use crate::{verbatim_text, FormatNodeRule, PyFormatter}; use crate::AsFormat;
use crate::{FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::hard_line_break;
use ruff_formatter::{write, Buffer, FormatResult}; use ruff_formatter::{write, Buffer, FormatResult};
use rustpython_parser::ast::ModModule; use rustpython_parser::ast::ModModule;
#[derive(Default)] #[derive(Default)]
@ -7,6 +10,9 @@ pub struct FormatModModule;
impl FormatNodeRule<ModModule> for FormatModModule { impl FormatNodeRule<ModModule> for FormatModModule {
fn fmt_fields(&self, item: &ModModule, f: &mut PyFormatter) -> FormatResult<()> { fn fmt_fields(&self, item: &ModModule, f: &mut PyFormatter) -> FormatResult<()> {
write!(f, [verbatim_text(item.range)]) for stmt in &item.body {
write!(f, [stmt.format(), hard_line_break()])?;
}
Ok(())
} }
} }

View file

@ -35,7 +35,7 @@ y = 100(no)
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,21 +1,21 @@ @@ -1,22 +1,20 @@
-x = (123456789).bit_count() -x = (123456789).bit_count()
+x = 123456789 .bit_count() +x = 123456789 .bit_count()
x = (123456).__abs__() x = (123456).__abs__()
@ -53,6 +53,8 @@ y = 100(no)
-x = 0o777.real -x = 0o777.real
-x = (0.000000006).hex() -x = (0.000000006).hex()
-x = -100.0000j -x = -100.0000j
-
-if (10).real:
+x = .1.is_integer() +x = .1.is_integer()
+x = 1. .imag +x = 1. .imag
+x = 1E+1.imag +x = 1E+1.imag
@ -67,12 +69,11 @@ y = 100(no)
+x = 0O777 .real +x = 0O777 .real
+x = 0.000000006 .hex() +x = 0.000000006 .hex()
+x = -100.0000J +x = -100.0000J
-if (10).real:
+if 10 .real: +if 10 .real:
... ...
-
y = 100[no] y = 100[no]
y = 100(no)
``` ```
## Ruff Output ## Ruff Output
@ -94,10 +95,8 @@ x = 0B1011 .conjugate()
x = 0O777 .real x = 0O777 .real
x = 0.000000006 .hex() x = 0.000000006 .hex()
x = -100.0000J x = -100.0000J
if 10 .real: if 10 .real:
... ...
y = 100[no] y = 100[no]
y = 100(no) y = 100(no)
``` ```

View file

@ -36,7 +36,7 @@ class NormalClass (
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,30 +1,23 @@ @@ -1,30 +1,21 @@
-class SimpleClassWithBlankParentheses: -class SimpleClassWithBlankParentheses:
+class SimpleClassWithBlankParentheses(): +class SimpleClassWithBlankParentheses():
pass pass
@ -50,13 +50,13 @@ class NormalClass (
def test_func(self): def test_func(self):
return None return None
- -
+class ClassWithEmptyFunc(object): -
class ClassWithEmptyFunc(object):
-class ClassWithEmptyFunc(object): +
def func_with_blank_parentheses(): def func_with_blank_parentheses():
return 5 return 5
-
-
def public_func_with_blank_parentheses(): def public_func_with_blank_parentheses():
return None return None
- -
@ -89,8 +89,6 @@ class ClassWithEmptyFunc(object):
def func_with_blank_parentheses(): def func_with_blank_parentheses():
return 5 return 5
def public_func_with_blank_parentheses(): def public_func_with_blank_parentheses():
return None return None
def class_under_the_func_with_blank_parentheses(): def class_under_the_func_with_blank_parentheses():

View file

@ -84,10 +84,27 @@ if True:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -18,44 +18,26 @@ @@ -1,99 +1,57 @@
import core, time, a
-
from . import A, B, C
-
-# keeps existing trailing comma
from foo import (
bar,
)
-
-# also keeps existing structure
from foo import (
baz,
qux,
)
-
-# `as` works as well
from foo import (
xyzzy as magic, xyzzy as magic,
) )
-
-a = { -a = {
- 1, - 1,
- 2, - 2,
@ -137,30 +154,32 @@ if True:
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" - "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s"
- % bar - % bar
-) -)
-
-# looping over a 1-tuple should also not get wrapped
+y = {"oneple": (1,),} +y = {"oneple": (1,),}
+assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar) +assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
# looping over a 1-tuple should also not get wrapped
for x in (1,): for x in (1,):
@@ -63,13 +45,9 @@ pass
for (x,) in (1,), (2,), (3,): for (x,) in (1,), (2,), (3,):
pass pass
-
-[ -[
- 1, - 1,
- 2, - 2,
- 3, - 3,
-] -]
+[1, 2, 3,] -
-division_result_tuple = (6 / 2,) -division_result_tuple = (6 / 2,)
+[1, 2, 3,]
+division_result_tuple = (6/2,) +division_result_tuple = (6/2,)
print("foo %r", (foo.bar,)) print("foo %r", (foo.bar,))
-
if True: if True:
@@ -79,21 +57,15 @@ IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
) )
-
if True: if True:
- ec2client.get_waiter("instance_stopped").wait( - ec2client.get_waiter("instance_stopped").wait(
+ ec2client.get_waiter('instance_stopped').wait( + ec2client.get_waiter('instance_stopped').wait(
@ -191,25 +210,17 @@ if True:
```py ```py
import core, time, a import core, time, a
from . import A, B, C from . import A, B, C
# keeps existing trailing comma
from foo import ( from foo import (
bar, bar,
) )
# also keeps existing structure
from foo import ( from foo import (
baz, baz,
qux, qux,
) )
# `as` works as well
from foo import ( from foo import (
xyzzy as magic, xyzzy as magic,
) )
a = {1,2,3,} a = {1,2,3,}
b = { b = {
1,2, 1,2,
@ -230,24 +241,18 @@ nested_long_lines = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbb
x = {"oneple": (1,)} x = {"oneple": (1,)}
y = {"oneple": (1,),} y = {"oneple": (1,),}
assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar) assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
# looping over a 1-tuple should also not get wrapped
for x in (1,): for x in (1,):
pass pass
for (x,) in (1,), (2,), (3,): for (x,) in (1,), (2,), (3,):
pass pass
[1, 2, 3,] [1, 2, 3,]
division_result_tuple = (6/2,) division_result_tuple = (6/2,)
print("foo %r", (foo.bar,)) print("foo %r", (foo.bar,))
if True: if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = ( IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController} | {pylons.controllers.WSGIController}
) )
if True: if True:
ec2client.get_waiter('instance_stopped').wait( ec2client.get_waiter('instance_stopped').wait(
InstanceIds=[instance.id], InstanceIds=[instance.id],

View file

@ -22,13 +22,13 @@ def bobtwo(): \
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,6 +1,9 @@ @@ -1,6 +1,7 @@
-def bob(): # pylint: disable=W9016 -def bob(): # pylint: disable=W9016
+def bob(): \ +def bob(): \
+ # pylint: disable=W9016 + # pylint: disable=W9016
pass pass
-
-
-def bobtwo(): # some comment here -def bobtwo(): # some comment here
+def bobtwo(): \ +def bobtwo(): \
+ \ + \
@ -42,8 +42,6 @@ def bobtwo(): \
def bob(): \ def bob(): \
# pylint: disable=W9016 # pylint: disable=W9016
pass pass
def bobtwo(): \ def bobtwo(): \
\ \
# some comment here # some comment here

View file

@ -178,7 +178,7 @@ instruction()#comment with bad spacing
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,39 +1,40 @@ @@ -1,39 +1,36 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY - MyLovelyCompanyTeamProjectComponent, # NOT DRY
+ MyLovelyCompanyTeamProjectComponent # NOT DRY + MyLovelyCompanyTeamProjectComponent # NOT DRY
@ -187,9 +187,9 @@ instruction()#comment with bad spacing
- MyLovelyCompanyTeamProjectComponent as component, # DRY - MyLovelyCompanyTeamProjectComponent as component, # DRY
+ MyLovelyCompanyTeamProjectComponent as component # DRY + MyLovelyCompanyTeamProjectComponent as component # DRY
) )
-
# Please keep __all__ alphabetized within each category. -# Please keep __all__ alphabetized within each category.
-
__all__ = [ __all__ = [
# Super-special typing primitives. # Super-special typing primitives.
- "Any", - "Any",
@ -227,7 +227,7 @@ instruction()#comment with bad spacing
+ 'NamedTuple', # Not really a type. + 'NamedTuple', # Not really a type.
+ 'Generator', + 'Generator',
] ]
-
not_shareables = [ not_shareables = [
# singletons # singletons
True, True,
@ -238,10 +238,11 @@ instruction()#comment with bad spacing
# builtin types and objects # builtin types and objects
type, type,
object, object,
@@ -48,20 +49,23 @@ @@ -47,21 +44,20 @@
Cheese("Wensleydale"),
SubBytes(b"spam"), SubBytes(b"spam"),
] ]
-
-if "PYTHON" in os.environ: -if "PYTHON" in os.environ:
+if 'PYTHON' in os.environ: +if 'PYTHON' in os.environ:
add_compiler(compiler_from_env()) add_compiler(compiler_from_env())
@ -250,10 +251,10 @@ instruction()#comment with bad spacing
- # add_compiler(compiler) - # add_compiler(compiler)
+ # add_compiler(compiler) + # add_compiler(compiler)
add_compiler(compilers[(7.0, 32)]) add_compiler(compilers[(7.0, 32)])
# add_compiler(compilers[(7.1, 64)]) - # add_compiler(compilers[(7.1, 64)])
- -
-
# Comment before function. -# Comment before function.
def inline_comments_in_brackets_ruin_everything(): def inline_comments_in_brackets_ruin_everything():
if typedargslist: if typedargslist:
- parameters.children = [children[0], body, children[-1]] # (1 # )1 - parameters.children = [children[0], body, children[-1]] # (1 # )1
@ -266,7 +267,7 @@ instruction()#comment with bad spacing
children[0], children[0],
body, body,
children[-1], # type: ignore children[-1], # type: ignore
@@ -73,49 +77,42 @@ @@ -73,49 +69,42 @@
parameters.children[-1], # )2 parameters.children[-1], # )2
] ]
parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore
@ -339,7 +340,7 @@ instruction()#comment with bad spacing
] ]
lcomp2 = [ lcomp2 = [
# hello # hello
@@ -127,7 +124,7 @@ @@ -127,7 +116,7 @@
] ]
lcomp3 = [ lcomp3 = [
# This one is actually too long to fit in a single line. # This one is actually too long to fit in a single line.
@ -348,7 +349,7 @@ instruction()#comment with bad spacing
# yup # yup
for element in collection.select_elements() for element in collection.select_elements()
# right # right
@@ -140,34 +137,26 @@ @@ -140,34 +129,18 @@
# and round and round we go # and round and round we go
# and round and round we go # and round and round we go
@ -362,7 +363,7 @@ instruction()#comment with bad spacing
+ Leaf(token.NEWLINE, '\n') # FIXME: \r\n? + Leaf(token.NEWLINE, '\n') # FIXME: \r\n?
+ ], + ],
) )
-
- -
-CONFIG_FILES = ( -CONFIG_FILES = (
- [ - [
@ -371,27 +372,27 @@ instruction()#comment with bad spacing
- + SHARED_CONFIG_FILES - + SHARED_CONFIG_FILES
- + USER_CONFIG_FILES - + USER_CONFIG_FILES
-) # type: Final -) # type: Final
+CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
- -
-
+CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES
class Test: class Test:
def _init_host(self, parsed) -> None: def _init_host(self, parsed) -> None:
- if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore - if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore
+ if (parsed.hostname is None or # type: ignore + if (parsed.hostname is None or # type: ignore
+ not parsed.hostname.strip()): + not parsed.hostname.strip()):
pass pass
- -
####################### -
### SECTION COMMENT ### -#######################
####################### -### SECTION COMMENT ###
-#######################
-
-
-instruction() # comment with bad spacing -instruction() # comment with bad spacing
- -
-# END COMMENTS -# END COMMENTS
-# MORE END COMMENTS -# MORE END COMMENTS
+instruction()#comment with bad spacing +instruction()
``` ```
## Ruff Output ## Ruff Output
@ -403,9 +404,6 @@ from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import ( from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component # DRY MyLovelyCompanyTeamProjectComponent as component # DRY
) )
# Please keep __all__ alphabetized within each category.
__all__ = [ __all__ = [
# Super-special typing primitives. # Super-special typing primitives.
'Any', 'Any',
@ -428,7 +426,6 @@ __all__ = [
'NamedTuple', # Not really a type. 'NamedTuple', # Not really a type.
'Generator', 'Generator',
] ]
not_shareables = [ not_shareables = [
# singletons # singletons
True, True,
@ -447,16 +444,12 @@ not_shareables = [
Cheese("Wensleydale"), Cheese("Wensleydale"),
SubBytes(b"spam"), SubBytes(b"spam"),
] ]
if 'PYTHON' in os.environ: if 'PYTHON' in os.environ:
add_compiler(compiler_from_env()) add_compiler(compiler_from_env())
else: else:
# for compiler in compilers.values(): # for compiler in compilers.values():
# add_compiler(compiler) # add_compiler(compiler)
add_compiler(compilers[(7.0, 32)]) add_compiler(compilers[(7.0, 32)])
# add_compiler(compilers[(7.1, 64)])
# Comment before function.
def inline_comments_in_brackets_ruin_everything(): def inline_comments_in_brackets_ruin_everything():
if typedargslist: if typedargslist:
parameters.children = [ parameters.children = [
@ -544,21 +537,13 @@ short
Leaf(token.NEWLINE, '\n') # FIXME: \r\n? Leaf(token.NEWLINE, '\n') # FIXME: \r\n?
], ],
) )
CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES
CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
class Test: class Test:
def _init_host(self, parsed) -> None: def _init_host(self, parsed) -> None:
if (parsed.hostname is None or # type: ignore if (parsed.hostname is None or # type: ignore
not parsed.hostname.strip()): not parsed.hostname.strip()):
pass pass
instruction()
#######################
### SECTION COMMENT ###
#######################
instruction()#comment with bad spacing
``` ```
## Black Output ## Black Output

View file

@ -0,0 +1,180 @@
---
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
@@ -1,7 +1,3 @@
-# The percent-percent comments are Spyder IDE cells.
-
-
-# %%
def func():
x = """
a really long string
@@ -43,6 +39,3 @@
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
-
-
-# %%
```
## Ruff Output
```py
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 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),
)
# %%
```

View file

@ -0,0 +1,338 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py
---
## Input
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -4,8 +4,6 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
-
-
class C:
@pytest.mark.parametrize(
("post_data", "message"),
@@ -54,8 +52,6 @@
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
-
-
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
@@ -70,8 +66,6 @@
.all()
)
return results
-
-
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
@@ -81,8 +75,6 @@
)
.filter(User.xyz.is_(None))
)
-
-
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
```
## Ruff Output
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
```
## Black Output
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
```

View file

@ -0,0 +1,288 @@
---
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
@@ -1,13 +1,6 @@
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.
-
+ do.stuff()
for i in range(100):
# first we do this
if i % 33 == 0:
@@ -15,31 +8,17 @@
# 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)
@@ -47,27 +26,14 @@
@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()
```
## Ruff Output
```py
while True:
if something.changed:
do.stuff()
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
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
def wat():
...
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
some_instruction
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()
```

View file

@ -0,0 +1,442 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py
---
## Input
```py
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,18 +1,11 @@
from typing import Any, Tuple
-
-
def f(
a, # type: int
):
pass
-
-
-# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
-
-
def f(
a, # type: int
b, # type: int
@@ -26,8 +19,6 @@
):
# type: (...) -> None
pass
-
-
def f(
arg, # type: int
*args, # type: *Any
@@ -36,8 +27,6 @@
):
# type: (...) -> None
pass
-
-
def f(
a, # type: int
b, # type: int
@@ -66,23 +55,17 @@
+ element
+ another_element
+ another_element_with_long_name
- ) # type: int
-
-
+ )
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
-
-
def f(
x, # not a type comment
): # type: (int) -> None
pass
-
-
def func(
a=some_list[0], # type: int
): # type: () -> int
@@ -102,17 +85,12 @@
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
-
-
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
-
-AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
-
+AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
-
-aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
+aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items)))
```
## Ruff Output
```py
from typing import Any, Tuple
def f(
a, # type: int
):
pass
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
)
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items)))
```
## Black Output
```py
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
```

View file

@ -152,84 +152,102 @@ def bar():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,16 +1,12 @@ @@ -1,61 +1,23 @@
# Test for https://github.com/psf/black/issues/246. -# Test for https://github.com/psf/black/issues/246.
-
some = statement some = statement
- -
- -
# This comment should be split from the statement above by two lines. -# This comment should be split from the statement above by two lines.
def function(): def function():
pass pass
-
-
some = statement some = statement
- -
- -
# This multiline comments section -# This multiline comments section
# should be split from the statement -# should be split from the statement
# above by two lines. -# above by two lines.
@@ -19,16 +15,12 @@ def function():
pass
-
-
some = statement some = statement
- -
- -
# This comment should be split from the statement above by two lines. -# This comment should be split from the statement above by two lines.
async def async_function(): async def async_function():
pass pass
-
-
some = statement some = statement
- -
- -
# This comment should be split from the statement above by two lines. -# This comment should be split from the statement above by two lines.
class MyClass: class MyClass:
pass pass
@@ -36,7 +28,6 @@
some = statement
# This should be stick to the statement above
- -
-
# This should be split from the above by two lines some = statement
-# This should be stick to the statement above
-
-
-# This should be split from the above by two lines
class MyClassWithComplexLeadingComments: class MyClassWithComplexLeadingComments:
@@ -45,16 +36,12 @@ pass
-
-
class ClassWithDocstring: class ClassWithDocstring:
"""A docstring.""" """A docstring."""
- -
- -
# Leading comment after a class with just a docstring -# Leading comment after a class with just a docstring
class MyClassAfterAnotherClassWithDocstring: class MyClassAfterAnotherClassWithDocstring:
pass pass
-
-
some = statement some = statement
- -
- -
# leading 1 -# leading 1
@deco1 @deco1
# leading 2 # leading 2
@@ -68,8 +55,6 @@ # leading 2 extra
@@ -65,12 +27,7 @@
# leading 4
def decorated():
pass
-
-
some = statement some = statement
- -
- -
# leading 1 -# leading 1
@deco1 @deco1
# leading 2 # leading 2
@@ -83,8 +68,6 @@ @deco2(with_args=True)
@@ -80,12 +37,7 @@
# leading 4
def decorated_with_split_leading_comments():
pass
-
-
some = statement some = statement
- -
- -
# leading 1 -# leading 1
@deco1 @deco1
# leading 2 # leading 2
@@ -102,11 +85,9 @@ @deco2(with_args=True)
@@ -95,66 +47,42 @@
# leading 4 that already has an empty line
def decorated_with_split_leading_comments():
pass
-
-
def main():
if a:
# Leading comment before inline function # Leading comment before inline function
def inline(): def inline():
pass pass
@ -241,7 +259,10 @@ def bar():
else: else:
# More leading comments # More leading comments
def inline_after_else(): def inline_after_else():
@@ -117,11 +98,9 @@ pass
-
-
if a:
# Leading comment before "top-level inline" function # Leading comment before "top-level inline" function
def top_level_quote_inline(): def top_level_quote_inline():
pass pass
@ -253,64 +274,64 @@ def bar():
else: else:
# More leading comments # More leading comments
def top_level_quote_inline_after_else(): def top_level_quote_inline_after_else():
@@ -153,7 +132,6 @@ pass
# Trailing comment that belongs to this function. -
# NOTE this comment only has one empty line below, and the formatter -
# should enforce two blank lines. class MyClass:
# First method has no empty lines between bare class def.
# More comments.
def first_method(self):
pass
-
-
-# Regression test for https://github.com/psf/black/issues/3454.
def foo():
pass
- # Trailing comment that belongs to this function
-
-
@decorator1
@decorator2 # fmt: skip
def bar():
pass
-
-
-# Regression test for https://github.com/psf/black/issues/3454.
def foo():
pass
- # Trailing comment that belongs to this function.
- # NOTE this comment only has one empty line below, and the formatter
- # should enforce two blank lines.
-
- -
@decorator1 @decorator1
# A standalone comment # A standalone comment
def bar():
``` ```
## Ruff Output ## Ruff Output
```py ```py
# Test for https://github.com/psf/black/issues/246.
some = statement some = statement
# This comment should be split from the statement above by two lines.
def function(): def function():
pass pass
some = statement some = statement
# This multiline comments section
# should be split from the statement
# above by two lines.
def function(): def function():
pass pass
some = statement some = statement
# This comment should be split from the statement above by two lines.
async def async_function(): async def async_function():
pass pass
some = statement some = statement
# This comment should be split from the statement above by two lines.
class MyClass: class MyClass:
pass pass
some = statement some = statement
# This should be stick to the statement above
# This should be split from the above by two lines
class MyClassWithComplexLeadingComments: class MyClassWithComplexLeadingComments:
pass pass
class ClassWithDocstring: class ClassWithDocstring:
"""A docstring.""" """A docstring."""
# Leading comment after a class with just a docstring
class MyClassAfterAnotherClassWithDocstring: class MyClassAfterAnotherClassWithDocstring:
pass pass
some = statement some = statement
# leading 1
@deco1 @deco1
# leading 2 # leading 2
# leading 2 extra # leading 2 extra
@ -320,10 +341,7 @@ some = statement
# leading 4 # leading 4
def decorated(): def decorated():
pass pass
some = statement some = statement
# leading 1
@deco1 @deco1
# leading 2 # leading 2
@deco2(with_args=True) @deco2(with_args=True)
@ -333,10 +351,7 @@ some = statement
# leading 4 # leading 4
def decorated_with_split_leading_comments(): def decorated_with_split_leading_comments():
pass pass
some = statement some = statement
# leading 1
@deco1 @deco1
# leading 2 # leading 2
@deco2(with_args=True) @deco2(with_args=True)
@ -346,8 +361,6 @@ some = statement
# leading 4 that already has an empty line # leading 4 that already has an empty line
def decorated_with_split_leading_comments(): def decorated_with_split_leading_comments():
pass pass
def main(): def main():
if a: if a:
# Leading comment before inline function # Leading comment before inline function
@ -360,8 +373,6 @@ def main():
# More leading comments # More leading comments
def inline_after_else(): def inline_after_else():
pass pass
if a: if a:
# Leading comment before "top-level inline" function # Leading comment before "top-level inline" function
def top_level_quote_inline(): def top_level_quote_inline():
@ -373,34 +384,19 @@ else:
# More leading comments # More leading comments
def top_level_quote_inline_after_else(): def top_level_quote_inline_after_else():
pass pass
class MyClass: class MyClass:
# First method has no empty lines between bare class def. # First method has no empty lines between bare class def.
# More comments. # More comments.
def first_method(self): def first_method(self):
pass pass
# Regression test for https://github.com/psf/black/issues/3454.
def foo(): def foo():
pass pass
# Trailing comment that belongs to this function
@decorator1 @decorator1
@decorator2 # fmt: skip @decorator2 # fmt: skip
def bar(): def bar():
pass pass
# Regression test for https://github.com/psf/black/issues/3454.
def foo(): def foo():
pass pass
# Trailing comment that belongs to this function.
# NOTE this comment only has one empty line below, and the formatter
# should enforce two blank lines.
@decorator1 @decorator1
# A standalone comment # A standalone comment
def bar(): def bar():

View file

@ -32,7 +32,7 @@ def function(a:int=42):
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,23 +1,19 @@ @@ -1,23 +1,16 @@
-from .config import ( -from .config import (
- ConfigTypeAttributes, - ConfigTypeAttributes,
- Int, - Int,
@ -41,24 +41,24 @@ def function(a:int=42):
+from .config import ( ConfigTypeAttributes, Int, Path, # String, +from .config import ( ConfigTypeAttributes, Int, Path, # String,
+ # DEFAULT_TYPE_ATTRIBUTES, + # DEFAULT_TYPE_ATTRIBUTES,
) )
-
-result = 1 # A simple comment -result = 1 # A simple comment
-result = (1,) # Another one -result = (1,) # Another one
+result = 1 # A simple comment -
+result = ( 1, ) # Another one
-result = 1 #  type: ignore -result = 1 #  type: ignore
-result = 1 # This comment is talking about type: ignore -result = 1 # This comment is talking about type: ignore
-square = Square(4) #  type: Optional[Square] -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): -def function(a: int = 42):
- """This docstring is already formatted - """This docstring is already formatted
- a - a
- b - b
+result = 1
+result = ( 1, )
+result = 1
+result = 1
+square = Square(4)
+def function(a:int=42): +def function(a:int=42):
+ """ This docstring is already formatted + """ This docstring is already formatted
+ a + a
@ -76,14 +76,11 @@ def function(a:int=42):
from .config import ( ConfigTypeAttributes, Int, Path, # String, from .config import ( ConfigTypeAttributes, Int, Path, # String,
# DEFAULT_TYPE_ATTRIBUTES, # DEFAULT_TYPE_ATTRIBUTES,
) )
result = 1
result = 1 # A simple comment result = ( 1, )
result = ( 1, ) # Another one result = 1
result = 1
result = 1 # type: ignore square = Square(4)
result = 1# This comment is talking about type: ignore
square = Square(4) # type: Optional[Square]
def function(a:int=42): def function(a:int=42):
""" This docstring is already formatted """ This docstring is already formatted
a a

View file

@ -109,49 +109,103 @@ async def wat():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -93,4 +93,4 @@ @@ -1,34 +1,20 @@
-#!/usr/bin/env python3
-# fmt: on
-# Some license here.
-#
-# Has many lines. Many, many lines.
-# Many, many, many lines.
"""Module docstring.
# Some closing comments. Possibly also many, many lines.
# Maybe Vim or Emacs directives for formatting. """
-
import os.path
import sys
-
import a
-from b.c import X # some noqa comment
-
+from b.c import X
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.
@@ -45,16 +31,7 @@
# 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."""
@@ -73,11 +50,6 @@
self.spam = 4
"""Docstring for instance attribute spam."""
-
-
-#' <h1>This is pweave!</h1>
-
-
@fast(really=True)
async def wat():
# This comment, for some reason \
@@ -89,8 +61,3 @@
print("A OK", file=sys.stdout)
# Comment between things.
print()
-
-
-# Some closing comments.
-# Maybe Vim or Emacs directives for formatting.
-# Who knows. -# Who knows.
\ No newline at end of file \ No newline at end of file
+# Who knows.
``` ```
## Ruff Output ## Ruff Output
```py ```py
#!/usr/bin/env python3
# fmt: on
# Some license here.
#
# Has many lines. Many, many lines.
# Many, many, many lines.
"""Module docstring. """Module docstring.
Possibly also many, many lines. Possibly also many, many lines.
""" """
import os.path import os.path
import sys import sys
import a import a
from b.c import X # some noqa comment from b.c import X
try: try:
import fast import fast
except ImportError: except ImportError:
import slow as fast import slow as fast
# Some comment before a function.
y = 1 y = 1
( (
# some strings # some strings
y # type: ignore y # type: ignore
) )
def function(default=None): def function(default=None):
"""Docstring comes first. """Docstring comes first.
@ -168,16 +222,7 @@ def function(default=None):
# This return is also commented for some reason. # This return is also commented for some reason.
return default return default
# Explains why we use global state.
GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)} GLOBAL_STATE = {"a": a(1), "b": a(2), "c": a(3)}
# Another comment!
# This time two lines.
class Foo: class Foo:
"""Docstring for class Foo. Example from Sphinx docs.""" """Docstring for class Foo. Example from Sphinx docs."""
@ -196,11 +241,6 @@ class Foo:
self.spam = 4 self.spam = 4
"""Docstring for instance attribute spam.""" """Docstring for instance attribute spam."""
#' <h1>This is pweave!</h1>
@fast(really=True) @fast(really=True)
async def wat(): async def wat():
# This comment, for some reason \ # This comment, for some reason \
@ -212,11 +252,6 @@ async def wat():
print("A OK", file=sys.stdout) print("A OK", file=sys.stdout)
# Comment between things. # Comment between things.
print() print()
# Some closing comments.
# Maybe Vim or Emacs directives for formatting.
# Who knows.
``` ```
## Black Output ## Black Output

View file

@ -0,0 +1,43 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/docstring_no_extra_empty_line_before_eof.py
---
## Input
```py
# Make sure when the file ends with class's docstring,
# It doesn't add extra blank lines.
class ClassWithDocstring:
"""A docstring."""
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,4 +1,2 @@
-# Make sure when the file ends with class's docstring,
-# It doesn't add extra blank lines.
class ClassWithDocstring:
"""A docstring."""
```
## Ruff Output
```py
class ClassWithDocstring:
"""A docstring."""
```
## Black Output
```py
# Make sure when the file ends with class's docstring,
# It doesn't add extra blank lines.
class ClassWithDocstring:
"""A docstring."""
```

View file

@ -63,23 +63,57 @@ def single_quote_docstring_over_line_limit2():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,9 +1,11 @@ @@ -1,48 +1,32 @@
def docstring_almost_at_line_limit(): def docstring_almost_at_line_limit():
- """long docstring.................................................................""" - """long docstring................................................................."""
-
-
+ """long docstring................................................................. + """long docstring.................................................................
+ """ + """
def docstring_almost_at_line_limit_with_prefix(): def docstring_almost_at_line_limit_with_prefix():
- f"""long docstring................................................................""" - f"""long docstring................................................................"""
-
-
+ f"""long docstring................................................................ + f"""long docstring................................................................
+ """ + """
def mulitline_docstring_almost_at_line_limit(): def mulitline_docstring_almost_at_line_limit():
@@ -45,4 +47,4 @@ """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(): 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)." - "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
+ 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).' + 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).'
@ -91,51 +125,33 @@ def single_quote_docstring_over_line_limit2():
def docstring_almost_at_line_limit(): def docstring_almost_at_line_limit():
"""long docstring................................................................. """long docstring.................................................................
""" """
def docstring_almost_at_line_limit_with_prefix(): def docstring_almost_at_line_limit_with_prefix():
f"""long docstring................................................................ f"""long docstring................................................................
""" """
def mulitline_docstring_almost_at_line_limit(): def mulitline_docstring_almost_at_line_limit():
"""long docstring................................................................. """long docstring.................................................................
.................................................................................. ..................................................................................
""" """
def mulitline_docstring_almost_at_line_limit_with_prefix(): def mulitline_docstring_almost_at_line_limit_with_prefix():
f"""long docstring................................................................ f"""long docstring................................................................
.................................................................................. ..................................................................................
""" """
def docstring_at_line_limit(): def docstring_at_line_limit():
"""long docstring................................................................""" """long docstring................................................................"""
def docstring_at_line_limit_with_prefix(): def docstring_at_line_limit_with_prefix():
f"""long docstring...............................................................""" f"""long docstring..............................................................."""
def multiline_docstring_at_line_limit(): def multiline_docstring_at_line_limit():
"""first line----------------------------------------------------------------------- """first line-----------------------------------------------------------------------
second line----------------------------------------------------------------------""" second line----------------------------------------------------------------------"""
def multiline_docstring_at_line_limit_with_prefix(): def multiline_docstring_at_line_limit_with_prefix():
f"""first line---------------------------------------------------------------------- f"""first line----------------------------------------------------------------------
second line----------------------------------------------------------------------""" second line----------------------------------------------------------------------"""
def single_quote_docstring_over_line_limit(): 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)." "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(): 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).' 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).'
``` ```

View file

@ -234,7 +234,7 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,83 +1,84 @@ @@ -1,219 +1,155 @@
class MyClass: class MyClass:
+ """ Multiline + """ Multiline
+ class docstring + class docstring
@ -251,51 +251,51 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
- method docstring - method docstring
- """ - """
- pass - pass
-
-
+ pass + pass
def foo(): def foo():
- """This is a docstring with - """This is a docstring with
- some lines of text here - some lines of text here
- """ - """
- return - return
-
-
+ """This is a docstring with + """This is a docstring with
+ some lines of text here + some lines of text here
+ """ + """
+ return + return
def bar(): def bar():
- """This is another docstring - """This is another docstring
- with more lines of text - with more lines of text
- """ - """
- return - return
-
-
+ '''This is another docstring + '''This is another docstring
+ with more lines of text + with more lines of text
+ ''' + '''
+ return + return
def baz(): def baz():
- '''"This" is a string with some - '''"This" is a string with some
- embedded "quotes"''' - embedded "quotes"'''
- return - return
-
-
+ '''"This" is a string with some + '''"This" is a string with some
+ embedded "quotes"''' + embedded "quotes"'''
+ return + return
def troz(): def troz():
- """Indentation with tabs - """Indentation with tabs
- is just as OK - is just as OK
- """ - """
- return - return
-
-
+ '''Indentation with tabs + '''Indentation with tabs
+ is just as OK + is just as OK
+ ''' + '''
+ return + return
def zort(): def zort():
- """Another - """Another
- multiline - multiline
@ -303,12 +303,12 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
- """ - """
- pass - pass
- -
-
+ """Another + """Another
+ multiline + multiline
+ docstring + docstring
+ """ + """
+ pass + pass
def poit(): def poit():
- """ - """
- Lorem ipsum dolor sit amet. - Lorem ipsum dolor sit amet.
@ -323,6 +323,8 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
- - aliquip ex ea commodo consequat - - aliquip ex ea commodo consequat
- """ - """
- pass - pass
-
-
+ Consectetur adipiscing elit: + Consectetur adipiscing elit:
+ - sed do eiusmod tempor incididunt ut labore + - sed do eiusmod tempor incididunt ut labore
+ - dolore magna aliqua + - dolore magna aliqua
@ -331,107 +333,107 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
+ - aliquip ex ea commodo consequat + - aliquip ex ea commodo consequat
+ """ + """
+ pass + pass
def under_indent(): def under_indent():
- """ - """
- These lines are indented in a way that does not - These lines are indented in a way that does not
- make sense. - make sense.
- """
- pass
+ """ + """
+ These lines are indented in a way that does not + These lines are indented in a way that does not
+make sense. +make sense.
+ """ + """
+ pass + pass
+def over_indent():
def over_indent():
+ """ + """
+ This has a shallow indent + This has a shallow indent
+ - But some lines are deeper + - But some lines are deeper
+ - And the closing quote is too deep + - And the closing quote is too deep
""" """
- pass
-
+ pass
+def single_line():
+ """But with a newline after it!
-def over_indent():
- """
- This has a shallow indent - This has a shallow indent
- - But some lines are deeper - - But some lines are deeper
- - And the closing quote is too deep - - And the closing quote is too deep
- """ """
- pass
+ pass
def single_line():
- """But with a newline after it!"""
+ """But with a newline after it!
+
+ """
pass pass
-
-
@@ -88,25 +89,30 @@ -def single_line():
- """But with a newline after it!"""
- pass
-
-
def this():
r"""
'hey ho'
"""
-
-
def that(): def that():
- """ "hey yah" """ - """ "hey yah" """
-
-
+ """ "hey yah" """ + """ "hey yah" """
def and_that(): def and_that():
- """ - """
- "hey yah" """ - "hey yah" """
-
-
+ """ + """
+ "hey yah" """ + "hey yah" """
def and_this(): def and_this():
- ''' - '''
- "hey yah"''' - "hey yah"'''
-
-
+ ''' + '''
+ "hey yah"''' + "hey yah"'''
def multiline_whitespace(): def multiline_whitespace():
- """ """ - """ """
-
-
+ ''' + '''
+ +
+ +
+ +
+ +
+ ''' + '''
def oneline_whitespace(): def oneline_whitespace():
- """ """ - """ """
-
-
+ ''' ''' + ''' '''
def empty(): def empty():
@@ -114,46 +120,43 @@ """"""
-
-
def single_quotes(): def single_quotes():
- "testing" - "testing"
+ 'testing' -
-
-def believe_it_or_not_this_is_in_the_py_stdlib(): -def believe_it_or_not_this_is_in_the_py_stdlib():
- ''' - '''
- "hey yah"''' - "hey yah"'''
-
-
+ 'testing'
+def believe_it_or_not_this_is_in_the_py_stdlib(): ''' +def believe_it_or_not_this_is_in_the_py_stdlib(): '''
+"hey yah"''' +"hey yah"'''
def ignored_docstring(): def ignored_docstring():
"""a => \ """a => \
-b""" b"""
-
- -
+b"""
def single_line_docstring_with_whitespace(): def single_line_docstring_with_whitespace():
- """This should be stripped""" - """This should be stripped"""
- -
-
+ """ This should be stripped """ + """ This should be stripped """
def docstring_with_inline_tabs_and_space_indentation(): def docstring_with_inline_tabs_and_space_indentation():
"""hey """hey
@ -447,20 +449,22 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
+ +
+ line ends with some tabs + line ends with some tabs
""" """
-
-
def docstring_with_inline_tabs_and_tab_indentation(): def docstring_with_inline_tabs_and_tab_indentation():
- """hey - """hey
+ """hey -
- tab separated value - tab separated value
- tab at start of line and then a tab separated value - tab at start of line and then a tab separated value
- multiple tabs at the beginning and inline - multiple tabs at the beginning and inline
- mixed tabs and spaces at beginning. next line has mixed tabs and spaces only. - mixed tabs and spaces at beginning. next line has mixed tabs and spaces only.
- + """hey
- line ends with some tabs - line ends with some tabs
- """ - """
- pass - pass
-
-
+ tab separated value + tab separated value
+ tab at start of line and then a tab separated value + tab at start of line and then a tab separated value
+ multiple tabs at the beginning and inline + multiple tabs at the beginning and inline
@ -469,53 +473,69 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
+ line ends with some tabs + line ends with some tabs
+ """ + """
+ pass + pass
def backslash_space(): def backslash_space():
@@ -161,16 +164,15 @@ """\ """
-
-
def multiline_backslash_1(): def multiline_backslash_1():
- """ - """
+ ''' + '''
hey\there\ hey\there\
- \ """ - \ """
-
-
+ \ ''' + \ '''
def multiline_backslash_2(): def multiline_backslash_2():
- """ - """
- hey there \ """ - hey there \ """
-
-
-# Regression test for #3425
+ ''' + '''
+ hey there \ ''' + hey there \ '''
-
# Regression test for #3425
def multiline_backslash_really_long_dont_crash(): def multiline_backslash_really_long_dont_crash():
""" """
@@ -178,8 +180,8 @@ hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
-
-
def multiline_backslash_3(): def multiline_backslash_3():
- """ - """
- already escaped \\""" - already escaped \\"""
-
-
+ ''' + '''
+ already escaped \\ ''' + already escaped \\ '''
def my_god_its_full_of_stars_1(): def my_god_its_full_of_stars_1():
@@ -188,7 +190,7 @@ "I'm sorry Dave\u2001"
-
# the space below is actually a \u2001, removed in output -
-# the space below is actually a \u2001, removed in output
def my_god_its_full_of_stars_2(): def my_god_its_full_of_stars_2():
- "I'm sorry Dave" - "I'm sorry Dave"
-
-
+ "I'm sorry Dave" + "I'm sorry Dave"
def docstring_almost_at_line_limit(): def docstring_almost_at_line_limit():
@@ -213,7 +215,7 @@ """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): def stable_quote_normalization_with_immediate_inner_single_quote(self):
- """'<text here> - """'<text here>
+ ''''<text here> + ''''<text here>
@ -538,42 +558,31 @@ class MyClass:
method docstring method docstring
""" """
pass pass
def foo(): def foo():
"""This is a docstring with """This is a docstring with
some lines of text here some lines of text here
""" """
return return
def bar(): def bar():
'''This is another docstring '''This is another docstring
with more lines of text with more lines of text
''' '''
return return
def baz(): def baz():
'''"This" is a string with some '''"This" is a string with some
embedded "quotes"''' embedded "quotes"'''
return return
def troz(): def troz():
'''Indentation with tabs '''Indentation with tabs
is just as OK is just as OK
''' '''
return return
def zort(): def zort():
"""Another """Another
multiline multiline
docstring docstring
""" """
pass pass
def poit(): def poit():
""" """
Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet.
@ -586,16 +595,12 @@ def poit():
- aliquip ex ea commodo consequat - aliquip ex ea commodo consequat
""" """
pass pass
def under_indent(): def under_indent():
""" """
These lines are indented in a way that does not These lines are indented in a way that does not
make sense. make sense.
""" """
pass pass
def over_indent(): def over_indent():
""" """
This has a shallow indent This has a shallow indent
@ -603,35 +608,23 @@ def over_indent():
- And the closing quote is too deep - And the closing quote is too deep
""" """
pass pass
def single_line(): def single_line():
"""But with a newline after it! """But with a newline after it!
""" """
pass pass
def this(): def this():
r""" r"""
'hey ho' 'hey ho'
""" """
def that(): def that():
""" "hey yah" """ """ "hey yah" """
def and_that(): def and_that():
""" """
"hey yah" """ "hey yah" """
def and_this(): def and_this():
''' '''
"hey yah"''' "hey yah"'''
def multiline_whitespace(): def multiline_whitespace():
''' '''
@ -639,31 +632,19 @@ def multiline_whitespace():
''' '''
def oneline_whitespace(): def oneline_whitespace():
''' ''' ''' '''
def empty(): def empty():
"""""" """"""
def single_quotes(): def single_quotes():
'testing' 'testing'
def believe_it_or_not_this_is_in_the_py_stdlib(): ''' def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"''' "hey yah"'''
def ignored_docstring(): def ignored_docstring():
"""a => \ """a => \
b""" b"""
def single_line_docstring_with_whitespace(): def single_line_docstring_with_whitespace():
""" This should be stripped """ """ This should be stripped """
def docstring_with_inline_tabs_and_space_indentation(): def docstring_with_inline_tabs_and_space_indentation():
"""hey """hey
@ -674,8 +655,6 @@ def docstring_with_inline_tabs_and_space_indentation():
line ends with some tabs line ends with some tabs
""" """
def docstring_with_inline_tabs_and_tab_indentation(): def docstring_with_inline_tabs_and_tab_indentation():
"""hey """hey
@ -687,63 +666,38 @@ def docstring_with_inline_tabs_and_tab_indentation():
line ends with some tabs line ends with some tabs
""" """
pass pass
def backslash_space(): def backslash_space():
"""\ """ """\ """
def multiline_backslash_1(): def multiline_backslash_1():
''' '''
hey\there\ hey\there\
\ ''' \ '''
def multiline_backslash_2(): def multiline_backslash_2():
''' '''
hey there \ ''' hey there \ '''
# Regression test for #3425
def multiline_backslash_really_long_dont_crash(): def multiline_backslash_really_long_dont_crash():
""" """
hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """ hey there hello guten tag hi hoow are you ola zdravstvuyte ciao como estas ca va \ """
def multiline_backslash_3(): def multiline_backslash_3():
''' '''
already escaped \\ ''' already escaped \\ '''
def my_god_its_full_of_stars_1(): def my_god_its_full_of_stars_1():
"I'm sorry Dave\u2001" "I'm sorry Dave\u2001"
# the space below is actually a \u2001, removed in output
def my_god_its_full_of_stars_2(): def my_god_its_full_of_stars_2():
"I'm sorry Dave" "I'm sorry Dave"
def docstring_almost_at_line_limit(): def docstring_almost_at_line_limit():
"""long docstring.................................................................""" """long docstring................................................................."""
def docstring_almost_at_line_limit2(): def docstring_almost_at_line_limit2():
"""long docstring................................................................. """long docstring.................................................................
.................................................................................. ..................................................................................
""" """
def docstring_at_line_limit(): def docstring_at_line_limit():
"""long docstring................................................................""" """long docstring................................................................"""
def multiline_docstring_at_line_limit(): def multiline_docstring_at_line_limit():
"""first line----------------------------------------------------------------------- """first line-----------------------------------------------------------------------
second line----------------------------------------------------------------------""" second line----------------------------------------------------------------------"""
def stable_quote_normalization_with_immediate_inner_single_quote(self): def stable_quote_normalization_with_immediate_inner_single_quote(self):
''''<text here> ''''<text here>

View file

@ -105,9 +105,11 @@ def g():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -3,9 +3,9 @@ @@ -1,11 +1,8 @@
"""Docstring."""
# leading comment -
-
-# leading comment
def f(): def f():
- NO = "" - NO = ""
- SPACE = " " - SPACE = " "
@ -118,7 +120,7 @@ def g():
t = leaf.type t = leaf.type
p = leaf.parent # trailing comment p = leaf.parent # trailing comment
@@ -16,14 +16,19 @@ @@ -16,14 +13,19 @@
if t == token.COMMENT: # another trailing comment if t == token.COMMENT: # another trailing comment
return DOUBLESPACE return DOUBLESPACE
@ -138,16 +140,17 @@ def g():
if prevp.type == token.EQUAL: if prevp.type == token.EQUAL:
if prevp.parent and prevp.parent.type in { if prevp.parent and prevp.parent.type in {
syms.typedargslist, syms.typedargslist,
@@ -44,16 +49,14 @@ @@ -43,17 +45,10 @@
syms.dictsetmaker,
}: }:
return NO return NO
- -
###############################################################################
# SECTION BECAUSE SECTIONS
###############################################################################
- -
-###############################################################################
-# SECTION BECAUSE SECTIONS
-###############################################################################
-
-
def g(): def g():
- NO = "" - NO = ""
- SPACE = " " - SPACE = " "
@ -158,7 +161,7 @@ def g():
t = leaf.type t = leaf.type
p = leaf.parent p = leaf.parent
@@ -67,7 +70,7 @@ @@ -67,7 +62,7 @@
return DOUBLESPACE return DOUBLESPACE
# Another comment because more comments # Another comment because more comments
@ -173,9 +176,6 @@ def g():
```py ```py
"""Docstring.""" """Docstring."""
# leading comment
def f(): def f():
NO = '' NO = ''
SPACE = ' ' SPACE = ' '
@ -222,11 +222,6 @@ def f():
syms.dictsetmaker, syms.dictsetmaker,
}: }:
return NO return NO
###############################################################################
# SECTION BECAUSE SECTIONS
###############################################################################
def g(): def g():
NO = '' NO = ''
SPACE = ' ' SPACE = ' '

View file

@ -401,7 +401,7 @@ last_call()
+call(kwarg='hey') +call(kwarg='hey')
+call(arg, kwarg='hey') +call(arg, kwarg='hey')
+call(arg, another, kwarg='hey', **kwargs) +call(arg, another, kwarg='hey', **kwargs)
+call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs) # note: no trailing comma pre-3.6 +call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs)
call(*gidgets[:2]) call(*gidgets[:2])
call(a, *gidgets[:2]) call(a, *gidgets[:2])
call(**self.screen_kwargs) call(**self.screen_kwargs)
@ -437,7 +437,7 @@ last_call()
-) # type: ignore -) # type: ignore
+xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[ +xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[
+ ..., List[SomeClass] + ..., List[SomeClass]
+] = classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore +] = classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__))
slice[0] slice[0]
slice[0:1] slice[0:1]
slice[0:1:2] slice[0:1:2]
@ -510,22 +510,22 @@ last_call()
Ø = set() Ø = set()
authors.łukasz.say_thanks() authors.łukasz.say_thanks()
mapping = { mapping = {
@@ -233,138 +170,84 @@ @@ -233,138 +170,82 @@
C: 0.1 * (10.0 / 12), C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12), D: 0.1 * (10.0 / 12),
} }
- -
-
def gen(): def gen():
yield from outside_of_generator yield from outside_of_generator
- a = yield - a = yield
- b = yield - b = yield
- c = yield - c = yield
- -
-
+ a = (yield) + a = (yield)
+ b = ((yield)) + b = ((yield))
+ c = (((yield))) + c = (((yield)))
async def f(): async def f():
await some.complicated[0].call(with_args=(True or (1 is not 1))) await some.complicated[0].call(with_args=(True or (1 is not 1)))
- -
@ -773,7 +773,7 @@ call(arg)
call(kwarg='hey') call(kwarg='hey')
call(arg, kwarg='hey') call(arg, kwarg='hey')
call(arg, another, kwarg='hey', **kwargs) call(arg, another, kwarg='hey', **kwargs)
call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs) # note: no trailing comma pre-3.6 call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs)
call(*gidgets[:2]) call(*gidgets[:2])
call(a, *gidgets[:2]) call(a, *gidgets[:2])
call(**self.screen_kwargs) call(**self.screen_kwargs)
@ -801,7 +801,7 @@ xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # t
) )
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[ xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[
..., List[SomeClass] ..., List[SomeClass]
] = classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore ] = classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__))
slice[0] slice[0]
slice[0:1] slice[0:1]
slice[0:1:2] slice[0:1:2]
@ -860,13 +860,11 @@ mapping = {
C: 0.1 * (10.0 / 12), C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12), D: 0.1 * (10.0 / 12),
} }
def gen(): def gen():
yield from outside_of_generator yield from outside_of_generator
a = (yield) a = (yield)
b = ((yield)) b = ((yield))
c = (((yield))) c = (((yield)))
async def f(): async def f():
await some.complicated[0].call(with_args=(True or (1 is not 1))) await some.complicated[0].call(with_args=(True or (1 is not 1)))
print(* [] or [1]) print(* [] or [1])

View file

@ -0,0 +1,174 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py
---
## Input
```py
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,13 +1,6 @@
import pytest
-
TmSt = 1
TmEx = 2
-
-# fmt: off
-
-# Test data:
-# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
-
@pytest.mark.parametrize('test', [
# Test don't manage the volume
@@ -17,24 +10,18 @@
])
def test_fader(test):
pass
-
def check_fader(test):
pass
-
def verify_fader(test):
# misaligned comment
pass
-
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
-
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
-
-# fmt: on
```
## Ruff Output
```py
import pytest
TmSt = 1
TmEx = 2
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
```
## Black Output
```py
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on
```

View file

@ -30,10 +30,21 @@ x = [
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -12,4 +12,6 @@ @@ -1,15 +1,11 @@
-# fmt: off
x = [
1, 2,
3, 4,
] ]
# fmt: on -# fmt: on
-
-# fmt: off
x = [
1, 2,
3, 4,
]
-# fmt: on
-
-x = [1, 2, 3, 4] -x = [1, 2, 3, 4]
+x = [ +x = [
+ 1, 2, 3, 4 + 1, 2, 3, 4
@ -43,20 +54,14 @@ x = [
## Ruff Output ## Ruff Output
```py ```py
# fmt: off
x = [ x = [
1, 2, 1, 2,
3, 4, 3, 4,
] ]
# fmt: on
# fmt: off
x = [ x = [
1, 2, 1, 2,
3, 4, 3, 4,
] ]
# fmt: on
x = [ x = [
1, 2, 3, 4 1, 2, 3, 4
] ]

View file

@ -26,15 +26,17 @@ def f(): pass
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -4,17 +4,10 @@ @@ -1,20 +1,11 @@
-# fmt: off
@test([
1, 2,
3, 4, 3, 4,
]) ])
# fmt: on # fmt: on
-def f(): -def f():
- pass - pass
- -
+def f(): pass -
-@test( -@test(
- [ - [
- 1, - 1,
@ -45,6 +47,7 @@ def f(): pass
-) -)
-def f(): -def f():
- pass - pass
+def f(): pass
+@test([ +@test([
+ 1, 2, + 1, 2,
+ 3, 4, + 3, 4,
@ -55,14 +58,12 @@ def f(): pass
## Ruff Output ## Ruff Output
```py ```py
# fmt: off
@test([ @test([
1, 2, 1, 2,
3, 4, 3, 4,
]) ])
# fmt: on # fmt: on
def f(): pass def f(): pass
@test([ @test([
1, 2, 1, 2,
3, 4, 3, 4,

View file

@ -97,38 +97,78 @@ elif unformatted:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -44,7 +44,7 @@ @@ -1,4 +1,3 @@
-# Regression test for https://github.com/psf/black/issues/3129.
setup(
entry_points={
# fmt: off
@@ -9,9 +8,6 @@
] # Includes an formatted indentation.
},
)
-
-
-# Regression test for https://github.com/psf/black/issues/2015.
run(
# fmt: off
[
@@ -22,9 +18,6 @@
+ path,
check=True,
)
-
-
-# Regression test for https://github.com/psf/black/issues/3026.
def test_func():
# yapf: disable
if unformatted( args ):
@@ -34,9 +27,6 @@
return True
return False
-
-
-# Regression test for https://github.com/psf/black/issues/2567.
if True:
# fmt: off
for _ in range( 1 ):
@@ -44,10 +34,7 @@
print ( "This won't be formatted" ) print ( "This won't be formatted" )
print ( "This won't be formatted either" ) print ( "This won't be formatted either" )
else: else:
- print("This will be formatted") - print("This will be formatted")
-
-
-# Regression test for https://github.com/psf/black/issues/3184.
+ print ( "This will be formatted" ) + print ( "This will be formatted" )
class A:
async def call(param):
# Regression test for https://github.com/psf/black/issues/3184. if param:
@@ -61,7 +61,7 @@ @@ -61,27 +48,16 @@
elif param[0:4] in ("ZZZZ",): elif param[0:4] in ("ZZZZ",):
print ( "This won't be formatted either" ) print ( "This won't be formatted either" )
- print("This will be formatted") - print("This will be formatted")
-
-
-# Regression test for https://github.com/psf/black/issues/2985.
+ print ( "This will be formatted" ) + print ( "This will be formatted" )
class Named(t.Protocol):
# fmt: off
# Regression test for https://github.com/psf/black/issues/2985.
@@ -70,11 +70,8 @@
@property @property
def this_wont_be_formatted ( self ) -> str: ... def this_wont_be_formatted ( self ) -> str: ...
-
- -
class Factory(t.Protocol): class Factory(t.Protocol):
- def this_will_be_formatted(self, **kwargs) -> Named: - def this_will_be_formatted(self, **kwargs) -> Named:
- ... - ...
- -
- # fmt: on
-
-
-# Regression test for https://github.com/psf/black/issues/3436.
+ def this_will_be_formatted ( self, **kwargs ) -> Named: ... + def this_will_be_formatted ( self, **kwargs ) -> Named: ...
# fmt: on if x:
@@ -83,5 +80,5 @@
return x return x
# fmt: off # fmt: off
elif unformatted: elif unformatted:
@ -141,7 +181,6 @@ elif unformatted:
## Ruff Output ## Ruff Output
```py ```py
# Regression test for https://github.com/psf/black/issues/3129.
setup( setup(
entry_points={ entry_points={
# fmt: off # fmt: off
@ -152,9 +191,6 @@ setup(
] # Includes an formatted indentation. ] # Includes an formatted indentation.
}, },
) )
# Regression test for https://github.com/psf/black/issues/2015.
run( run(
# fmt: off # fmt: off
[ [
@ -165,9 +201,6 @@ run(
+ path, + path,
check=True, check=True,
) )
# Regression test for https://github.com/psf/black/issues/3026.
def test_func(): def test_func():
# yapf: disable # yapf: disable
if unformatted( args ): if unformatted( args ):
@ -177,9 +210,6 @@ def test_func():
return True return True
return False return False
# Regression test for https://github.com/psf/black/issues/2567.
if True: if True:
# fmt: off # fmt: off
for _ in range( 1 ): for _ in range( 1 ):
@ -188,9 +218,6 @@ if True:
print ( "This won't be formatted either" ) print ( "This won't be formatted either" )
else: else:
print ( "This will be formatted" ) print ( "This will be formatted" )
# Regression test for https://github.com/psf/black/issues/3184.
class A: class A:
async def call(param): async def call(param):
if param: if param:
@ -205,20 +232,12 @@ class A:
print ( "This won't be formatted either" ) print ( "This won't be formatted either" )
print ( "This will be formatted" ) print ( "This will be formatted" )
# Regression test for https://github.com/psf/black/issues/2985.
class Named(t.Protocol): class Named(t.Protocol):
# fmt: off # fmt: off
@property @property
def this_wont_be_formatted ( self ) -> str: ... def this_wont_be_formatted ( self ) -> str: ...
class Factory(t.Protocol): class Factory(t.Protocol):
def this_will_be_formatted ( self, **kwargs ) -> Named: ... def this_will_be_formatted ( self, **kwargs ) -> Named: ...
# fmt: on
# Regression test for https://github.com/psf/black/issues/3436.
if x: if x:
return x return x
# fmt: off # fmt: off

View file

@ -199,32 +199,37 @@ d={'a':1,
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -4,18 +4,17 @@ @@ -1,22 +1,11 @@
-#!/usr/bin/env python3
import asyncio
import sys
-
from third_party import X, Y, Z from third_party import X, Y, Z
-
-from library import some_connection, some_decorator -from library import some_connection, some_decorator
- -
-# fmt: off
+from library import some_connection, \ +from library import some_connection, \
+ some_decorator + some_decorator
# fmt: off
from third_party import (X, from third_party import (X,
Y, Z) Y, Z)
# fmt: on -# fmt: on
-f"trigger 3.6 mode" -f"trigger 3.6 mode"
+f'trigger 3.6 mode' -# Comment 1
# Comment 1
# Comment 2
- -
# fmt: off -# Comment 2
-
-
-# fmt: off
+f'trigger 3.6 mode'
def func_no_args(): def func_no_args():
a; b; c a; b; c
@@ -39,34 +38,16 @@ if True: raise RuntimeError
@@ -38,73 +27,41 @@
)
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str: def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
return text[number:-1] return text[number:-1]
# fmt: on -# fmt: on
-def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""): -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))) - offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
- assert task._cancel_stack[: len(old_stack)] == old_stack - assert task._cancel_stack[: len(old_stack)] == old_stack
@ -259,10 +264,10 @@ d={'a':1,
key: 'value', key: 'value',
} }
- -
-
def subscriptlist(): def subscriptlist():
atom[ atom[
@@ -74,17 +55,14 @@ # fmt: off
'some big and', 'some big and',
'complex subscript', 'complex subscript',
# fmt: on # fmt: on
@ -270,22 +275,22 @@ d={'a':1,
- andhere, - andhere,
- ] - ]
- -
-
+ goes + here, andhere, + goes + here, andhere,
+ ] + ]
def import_as_names(): def import_as_names():
# fmt: off # fmt: off
from hello import a, b from hello import a, b
'unformatted' 'unformatted'
# fmt: on - # fmt: on
-
- -
def testlist_star_expr(): def testlist_star_expr():
# fmt: off # fmt: off
@@ -92,18 +70,16 @@ a , b = *hello
'unformatted' 'unformatted'
# fmt: on - # fmt: on
-
- -
def yield_expr(): def yield_expr():
# fmt: off # fmt: off
@ -297,43 +302,46 @@ d={'a':1,
# fmt: off # fmt: off
( yield hello ) ( yield hello )
'unformatted' 'unformatted'
# fmt: on - # fmt: on
-
- -
def example(session): def example(session):
# fmt: off # fmt: off
@@ -114,8 +90,6 @@ result = session\
@@ -113,9 +70,6 @@
models.Customer.email == email_address)\
.order_by(models.Customer.id.asc())\ .order_by(models.Customer.id.asc())\
.all() .all()
# fmt: on - # fmt: on
- -
- -
def off_and_on_without_data(): def off_and_on_without_data():
"""All comments here are technically on the same prefix. """All comments here are technically on the same prefix.
@@ -123,12 +97,12 @@ @@ -123,12 +77,12 @@
""" """
# fmt: off # fmt: off
- # hey, that won't work - # hey, that won't work
- # fmt: on
- pass
+ #hey, that won't work + #hey, that won't work
+
+
# fmt: on + # fmt: on
pass + pass
-
-
def on_and_off_broken(): def on_and_off_broken():
"""Another known limitation.""" """Another known limitation."""
# fmt: on # fmt: on
@@ -139,19 +113,12 @@ @@ -137,21 +91,10 @@
and_=indeed . it is not formatted
because . the . handling . inside . generate_ignored_nodes()
now . considers . multiple . fmt . directives . within . one . prefix now . considers . multiple . fmt . directives . within . one . prefix
# fmt: on - # fmt: on
# fmt: off - # fmt: off
- # ...but comments still get reformatted even though they should not be - # ...but comments still get reformatted even though they should not be
+ # ...but comments still get reformatted even though they should not be - # fmt: on
# fmt: on
- -
- -
def long_lines(): def long_lines():
@ -349,7 +357,7 @@ d={'a':1,
) )
# fmt: off # fmt: off
a = ( a = (
@@ -182,24 +149,19 @@ @@ -182,24 +125,19 @@
re.MULTILINE|re.VERBOSE re.MULTILINE|re.VERBOSE
# fmt: on # fmt: on
) )
@ -364,7 +372,7 @@ d={'a':1,
+ (1, 2, 3, 4), + (1, 2, 3, 4),
+ (5, 6, 7, 8), + (5, 6, 7, 8),
+ (9, 10, 11, 12) + (9, 10, 11, 12)
+ } # yapf: disable + }
cfg.rule( cfg.rule(
- "Default", - "Default",
- "address", - "address",
@ -383,38 +391,32 @@ d={'a':1,
# fmt: off # fmt: off
xxxxxxx_xxxxxxxxxxxx={ xxxxxxx_xxxxxxxxxxxx={
"xxxxxxxx": { "xxxxxxxx": {
@@ -214,7 +176,7 @@ @@ -214,11 +152,9 @@
}, },
}, },
# fmt: on # fmt: on
- xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5, - xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
+ xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5 + xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
) )
# fmt: off -# fmt: off
yield 'hello' yield 'hello'
-# No formatting to the end of the file
l=[1,2,3]
d={'a':1,
'b':2}
``` ```
## Ruff Output ## Ruff Output
```py ```py
#!/usr/bin/env python3
import asyncio import asyncio
import sys import sys
from third_party import X, Y, Z from third_party import X, Y, Z
from library import some_connection, \ from library import some_connection, \
some_decorator some_decorator
# fmt: off
from third_party import (X, from third_party import (X,
Y, Z) Y, Z)
# fmt: on
f'trigger 3.6 mode' f'trigger 3.6 mode'
# Comment 1
# Comment 2
# fmt: off
def func_no_args(): def func_no_args():
a; b; c a; b; c
if True: raise RuntimeError if True: raise RuntimeError
@ -436,7 +438,6 @@ many_args=[1,2,3]
) )
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str: def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
return text[number:-1] 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''): 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))) offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2)))
assert task._cancel_stack[:len(old_stack)] == old_stack assert task._cancel_stack[:len(old_stack)] == old_stack
@ -447,7 +448,6 @@ something = {
# fmt: off # fmt: off
key: 'value', key: 'value',
} }
def subscriptlist(): def subscriptlist():
atom[ atom[
# fmt: off # fmt: off
@ -456,19 +456,14 @@ def subscriptlist():
# fmt: on # fmt: on
goes + here, andhere, goes + here, andhere,
] ]
def import_as_names(): def import_as_names():
# fmt: off # fmt: off
from hello import a, b from hello import a, b
'unformatted' 'unformatted'
# fmt: on
def testlist_star_expr(): def testlist_star_expr():
# fmt: off # fmt: off
a , b = *hello a , b = *hello
'unformatted' 'unformatted'
# fmt: on
def yield_expr(): def yield_expr():
# fmt: off # fmt: off
yield hello yield hello
@ -478,8 +473,6 @@ def yield_expr():
# fmt: off # fmt: off
( yield hello ) ( yield hello )
'unformatted' 'unformatted'
# fmt: on
def example(session): def example(session):
# fmt: off # fmt: off
result = session\ result = session\
@ -488,7 +481,6 @@ def example(session):
models.Customer.email == email_address)\ models.Customer.email == email_address)\
.order_by(models.Customer.id.asc())\ .order_by(models.Customer.id.asc())\
.all() .all()
# fmt: on
def off_and_on_without_data(): def off_and_on_without_data():
"""All comments here are technically on the same prefix. """All comments here are technically on the same prefix.
@ -510,10 +502,6 @@ def on_and_off_broken():
and_=indeed . it is not formatted and_=indeed . it is not formatted
because . the . handling . inside . generate_ignored_nodes() because . the . handling . inside . generate_ignored_nodes()
now . considers . multiple . fmt . directives . within . one . prefix 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(): def long_lines():
if True: if True:
typedargslist.extend( typedargslist.extend(
@ -554,7 +542,7 @@ def single_literal_yapf_disable():
(1, 2, 3, 4), (1, 2, 3, 4),
(5, 6, 7, 8), (5, 6, 7, 8),
(9, 10, 11, 12) (9, 10, 11, 12)
} # yapf: disable }
cfg.rule( cfg.rule(
"Default", "address", "Default", "address",
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"], xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
@ -577,9 +565,7 @@ cfg.rule(
# fmt: on # fmt: on
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5 xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
) )
# fmt: off
yield 'hello' yield 'hello'
# No formatting to the end of the file
l=[1,2,3] l=[1,2,3]
d={'a':1, d={'a':1,
'b':2} 'b':2}

View file

@ -22,13 +22,14 @@ l3 = ["I have", "trailing comma", "so I should be braked",]
- "into multiple lines", - "into multiple lines",
- "because it is way too long", - "because it is way too long",
-] -]
+l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"] -l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip
l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip
-l3 = [ -l3 = [
- "I have", - "I have",
- "trailing comma", - "trailing comma",
- "so I should be braked", - "so I should be braked",
-] -]
+l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"]
+l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"]
+l3 = ["I have", "trailing comma", "so I should be braked",] +l3 = ["I have", "trailing comma", "so I should be braked",]
``` ```
@ -36,7 +37,7 @@ l3 = ["I have", "trailing comma", "so I should be braked",]
```py ```py
l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"] l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"]
l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"]
l3 = ["I have", "trailing comma", "so I should be braked",] l3 = ["I have", "trailing comma", "so I should be braked",]
``` ```

View file

@ -20,14 +20,15 @@ f = ["This is a very long line that should be formatted into a clearer line ", "
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,10 +1,7 @@ @@ -1,10 +1,5 @@
-a = 3 -a = 3
-# fmt: off
+a = 3 +a = 3
# fmt: off
b, c = 1, 2 b, c = 1, 2
d = 6 # fmt: skip -d = 6 # fmt: skip
+d = 6
e = 5 e = 5
# fmt: on -# fmt: on
-f = [ -f = [
- "This is a very long line that should be formatted into a clearer line ", - "This is a very long line that should be formatted into a clearer line ",
- "by rearranging.", - "by rearranging.",
@ -39,11 +40,9 @@ f = ["This is a very long line that should be formatted into a clearer line ", "
```py ```py
a = 3 a = 3
# fmt: off
b, c = 1, 2 b, c = 1, 2
d = 6 # fmt: skip d = 6
e = 5 e = 5
# fmt: on
f = ["This is a very long line that should be formatted into a clearer line ", "by rearranging."] f = ["This is a very long line that should be formatted into a clearer line ", "by rearranging."]
``` ```

View file

@ -16,15 +16,15 @@ l = [1, 2, 3,]
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,7 +1,3 @@ @@ -1,7 +1,2 @@
-a = 2 -a = 2
+a = 2 -# fmt: skip
# fmt: skip
-l = [ -l = [
- 1, - 1,
- 2, - 2,
- 3, - 3,
-] -]
+a = 2
+l = [1, 2, 3,] +l = [1, 2, 3,]
``` ```
@ -32,7 +32,6 @@ l = [1, 2, 3,]
```py ```py
a = 2 a = 2
# fmt: skip
l = [1, 2, 3,] l = [1, 2, 3,]
``` ```

View file

@ -0,0 +1,49 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip6.py
---
## Input
```py
class A:
def f(self):
for line in range(10):
if True:
pass # fmt: skip
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -2,4 +2,4 @@
def f(self):
for line in range(10):
if True:
- pass # fmt: skip
+ pass
```
## Ruff Output
```py
class A:
def f(self):
for line in range(10):
if True:
pass
```
## Black Output
```py
class A:
def f(self):
for line in range(10):
if True:
pass # fmt: skip
```

View file

@ -23,18 +23,18 @@ d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasu
-c = 9 # fmt: skip -c = 9 # fmt: skip
-d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip -d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
+a = "this is some code" +a = "this is some code"
+b = 5 #fmt:skip +b = 5
+c = 9 #fmt: skip +c = 9
+d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" #fmt:skip +d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring"
``` ```
## Ruff Output ## Ruff Output
```py ```py
a = "this is some code" a = "this is some code"
b = 5 #fmt:skip b = 5
c = 9 #fmt: skip c = 9
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" #fmt:skip d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring"
``` ```
## Black Output ## Black Output

View file

@ -0,0 +1,253 @@
---
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,17 +1,9 @@
-# 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")
@@ -20,9 +12,6 @@
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.
@@ -30,33 +19,21 @@
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")
```
## Ruff Output
```py
def some_func( unformatted, args ): # fmt: skip
print("I am some_func")
return 0
async def some_async_func( unformatted, args): # fmt: skip
print("I am some_async_func")
await asyncio.sleep(1)
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)
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 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")
```

View file

@ -1,18 +1,14 @@
--- ---
source: crates/ruff_python_formatter/src/lib.rs source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py
--- ---
## Input ## Input
```py ```py
\ a, b = 1, 2
c = 6 # fmt: skip
d = 5
print("hello, world")
``` ```
## Black Differences ## Black Differences
@ -20,32 +16,27 @@ print("hello, world")
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1 +1,7 @@ @@ -1,3 +1,3 @@
+\ a, b = 1, 2
+ -c = 6 # fmt: skip
+ +c = 6
+ d = 5
+
+
print("hello, world")
``` ```
## Ruff Output ## Ruff Output
```py ```py
\ a, b = 1, 2
c = 6
d = 5
print("hello, world")
``` ```
## Black Output ## Black Output
```py ```py
print("hello, world") a, b = 1, 2
c = 6 # fmt: skip
d = 5
``` ```

View file

@ -82,7 +82,7 @@ with hmm_but_this_should_get_two_preceding_newlines():
) )
limited.append(-limited.pop()) # negate top limited.append(-limited.pop()) # negate top
return A( return A(
@@ -13,34 +13,24 @@ @@ -13,34 +13,22 @@
very_long_argument_name2=-very.long.value.for_the_argument, very_long_argument_name2=-very.long.value.for_the_argument,
**kwargs, **kwargs,
) )
@ -102,8 +102,8 @@ with hmm_but_this_should_get_two_preceding_newlines():
pass pass
- -
print("Inner defs should breathe a little.") print("Inner defs should breathe a little.")
-
-
if os.name == "posix": if os.name == "posix":
import termios import termios
- -
@ -117,7 +117,7 @@ with hmm_but_this_should_get_two_preceding_newlines():
def i_should_be_followed_by_only_one_newline(): def i_should_be_followed_by_only_one_newline():
pass pass
@@ -54,12 +44,10 @@ @@ -54,12 +42,9 @@
class IHopeYouAreHavingALovelyDay: class IHopeYouAreHavingALovelyDay:
def __call__(self): def __call__(self):
print("i_should_be_followed_by_only_one_newline") print("i_should_be_followed_by_only_one_newline")
@ -127,7 +127,7 @@ with hmm_but_this_should_get_two_preceding_newlines():
def foo(): def foo():
pass pass
- -
-
with hmm_but_this_should_get_two_preceding_newlines(): with hmm_but_this_should_get_two_preceding_newlines():
pass pass
``` ```
@ -159,8 +159,6 @@ def h():
def inner(): def inner():
pass pass
print("Inner defs should breathe a little.") print("Inner defs should breathe a little.")
if os.name == "posix": if os.name == "posix":
import termios import termios
def i_should_be_followed_by_only_one_newline(): def i_should_be_followed_by_only_one_newline():
@ -185,7 +183,6 @@ else:
def foo(): def foo():
pass pass
with hmm_but_this_should_get_two_preceding_newlines(): with hmm_but_this_should_get_two_preceding_newlines():
pass pass
``` ```

View file

@ -108,10 +108,13 @@ def __await__(): return (yield)
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -4,97 +4,52 @@ @@ -1,100 +1,51 @@
-#!/usr/bin/env python3
import asyncio
import sys
-
from third_party import X, Y, Z from third_party import X, Y, Z
-
-from library import some_connection, some_decorator -from library import some_connection, some_decorator
- -
-f"trigger 3.6 mode" -f"trigger 3.6 mode"
@ -202,7 +205,6 @@ def __await__(): return (yield)
+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 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)): +def spaces2(result= _core.Value(None)):
+ assert fut is self._read_fut, (fut, self._read_fut) + assert fut is self._read_fut, (fut, self._read_fut)
+
def example(session): def example(session):
- result = ( - result = (
- session.query(models.Customer.id) - session.query(models.Customer.id)
@ -242,7 +244,7 @@ def __await__(): return (yield)
# trailing standalone comment # trailing standalone comment
) )
) )
@@ -117,23 +72,18 @@ @@ -117,23 +68,18 @@
\n? \n?
) )
$ $
@ -274,7 +276,7 @@ def __await__(): return (yield)
) -> A: ) -> A:
return ( return (
yield from A( yield from A(
@@ -142,7 +92,4 @@ @@ -142,7 +88,4 @@
**kwargs, **kwargs,
) )
) )
@ -288,12 +290,9 @@ def __await__(): return (yield)
## Ruff Output ## Ruff Output
```py ```py
#!/usr/bin/env python3
import asyncio import asyncio
import sys import sys
from third_party import X, Y, Z from third_party import X, Y, Z
from library import some_connection, \ from library import some_connection, \
some_decorator some_decorator
f'trigger 3.6 mode' f'trigger 3.6 mode'
@ -324,7 +323,6 @@ def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''
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 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)): def spaces2(result= _core.Value(None)):
assert fut is self._read_fut, (fut, self._read_fut) assert fut is self._read_fut, (fut, self._read_fut)
def example(session): def example(session):
result = session.query(models.Customer.id).filter( result = session.query(models.Customer.id).filter(
models.Customer.account_id == account_id, models.Customer.account_id == account_id,

View file

@ -74,7 +74,7 @@ some_module.some_function(
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,69 +1,26 @@ @@ -1,114 +1,42 @@
-def f( -def f(
- a, - a,
-): -):
@ -84,7 +84,7 @@ some_module.some_function(
+def f(a,): +def f(a,):
+ d = {'key': 'value',} + d = {'key': 'value',}
tup = (1,) tup = (1,)
-
- -
-def f2( -def f2(
- a, - a,
@ -99,10 +99,7 @@ some_module.some_function(
- 2, - 2,
- ) - )
- -
+def f2(a,b,): -
+ d = {'key': 'value', 'key2': 'value2',}
+ tup = (1,2,)
-def f( -def f(
- a: int = 1, - a: int = 1,
-): -):
@ -114,6 +111,9 @@ some_module.some_function(
- call2( - call2(
- arg=[1, 2, 3], - arg=[1, 2, 3],
- ) - )
+def f2(a,b,):
+ d = {'key': 'value', 'key2': 'value2',}
+ tup = (1,2,)
+def f(a:int=1,): +def f(a:int=1,):
+ call(arg={'explode': 'this',}) + call(arg={'explode': 'this',})
+ call2(arg=[1,2,3],) + call2(arg=[1,2,3],)
@ -136,12 +136,8 @@ some_module.some_function(
- ): - ):
+ if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]: + if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]:
pass pass
-
+def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[ -
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+]:
+ json = {"k": {"k2": {"k3": [1,]}}}
-def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> ( -def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> (
- Set["xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"] - Set["xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]
-): -):
@ -154,13 +150,20 @@ some_module.some_function(
- } - }
- } - }
- } - }
-
-
# The type annotation shouldn't get a trailing comma since that would change its type. -# The type annotation shouldn't get a trailing comma since that would change its type.
@@ -74,24 +31,21 @@ -# Relevant bug report: https://github.com/psf/black/issues/2381.
+def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+]:
+ json = {"k": {"k2": {"k3": [1,]}}}
def some_function_with_a_really_long_name() -> (
returning_a_deeply_nested_import_of_a_type_i_suppose
):
pass pass
-
-
-def some_method_with_a_really_long_name( -def some_method_with_a_really_long_name(
- very_long_parameter_so_yeah: str, another_long_parameter: int - very_long_parameter_so_yeah: str, another_long_parameter: int
-) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not: -) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not:
@ -168,8 +171,8 @@ some_module.some_function(
+ another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not + another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not
+): +):
pass pass
-
-
def func() -> ( def func() -> (
- also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( - also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
- this_shouldn_t_get_a_trailing_comma_too - this_shouldn_t_get_a_trailing_comma_too
@ -177,8 +180,8 @@ some_module.some_function(
+ also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too) + also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too)
): ):
pass pass
-
-
-def func() -> ( -def func() -> (
- also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( - also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
+def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( +def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
@ -187,10 +190,14 @@ some_module.some_function(
+ )) + ))
): ):
pass pass
-
@@ -103,12 +57,5 @@ -
-# Make sure inner one-element tuple won't explode
# Inner trailing comma causes outer to explode some_module.some_function(
argument1, (one_element_tuple,), argument4, argument5, argument6
)
-
-# Inner trailing comma causes outer to explode
some_module.some_function( some_module.some_function(
- argument1, - argument1,
- ( - (
@ -210,11 +217,9 @@ some_module.some_function(
def f(a,): def f(a,):
d = {'key': 'value',} d = {'key': 'value',}
tup = (1,) tup = (1,)
def f2(a,b,): def f2(a,b,):
d = {'key': 'value', 'key2': 'value2',} d = {'key': 'value', 'key2': 'value2',}
tup = (1,2,) tup = (1,2,)
def f(a:int=1,): def f(a:int=1,):
call(arg={'explode': 'this',}) call(arg={'explode': 'this',})
call2(arg=[1,2,3],) call2(arg=[1,2,3],)
@ -224,47 +229,30 @@ def f(a:int=1,):
}["a"] }["a"]
if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]: if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]:
pass pass
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[ def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
]: ]:
json = {"k": {"k2": {"k3": [1,]}}} json = {"k": {"k2": {"k3": [1,]}}}
# The type annotation shouldn't get a trailing comma since that would change its type.
# Relevant bug report: https://github.com/psf/black/issues/2381.
def some_function_with_a_really_long_name() -> ( def some_function_with_a_really_long_name() -> (
returning_a_deeply_nested_import_of_a_type_i_suppose returning_a_deeply_nested_import_of_a_type_i_suppose
): ):
pass pass
def some_method_with_a_really_long_name(very_long_parameter_so_yeah: str, another_long_parameter: int) -> ( def some_method_with_a_really_long_name(very_long_parameter_so_yeah: str, another_long_parameter: int) -> (
another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not
): ):
pass pass
def func() -> ( def func() -> (
also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too) also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too)
): ):
pass pass
def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black( def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
this_shouldn_t_get_a_trailing_comma_too this_shouldn_t_get_a_trailing_comma_too
)) ))
): ):
pass pass
# Make sure inner one-element tuple won't explode
some_module.some_function( some_module.some_function(
argument1, (one_element_tuple,), argument4, argument5, argument6 argument1, (one_element_tuple,), argument4, argument5, argument6
) )
# Inner trailing comma causes outer to explode
some_module.some_function( some_module.some_function(
argument1, (one, two,), argument4, argument5, argument6 argument1, (one, two,), argument4, argument5, argument6
) )

View file

@ -62,10 +62,11 @@ __all__ = (
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -2,8 +2,10 @@ @@ -1,55 +1,30 @@
"""The asyncio package, tracking PEP 3156."""
# flake8: noqa -
-# flake8: noqa
-
-from logging import WARNING -from logging import WARNING
from logging import ( from logging import (
+ WARNING + WARNING
@ -74,9 +75,23 @@ __all__ = (
ERROR, ERROR,
) )
import sys import sys
@@ -22,33 +24,16 @@ -
-# This relies on each of the submodules having an __all__ variable.
from .base_events import *
from .coroutines import *
-from .events import * # comment here
-
+from .events import *
from .futures import *
-from .locks import * # comment here
+from .locks import *
from .protocols import *
-
-from ..runners import * # comment here
+from ..runners import *
from ..queues import *
from ..streams import * from ..streams import *
-
from some_library import ( from some_library import (
- Just, - Just,
- Enough, - Enough,
@ -99,7 +114,7 @@ __all__ = (
-) -)
+from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy +from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import * from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
-
from .a.b.c.subprocess import * from .a.b.c.subprocess import *
-from . import tasks -from . import tasks
-from . import A, B, C -from . import A, B, C
@ -107,22 +122,20 @@ __all__ = (
- SomeVeryLongNameAndAllOfItsAdditionalLetters1, - SomeVeryLongNameAndAllOfItsAdditionalLetters1,
- SomeVeryLongNameAndAllOfItsAdditionalLetters2, - SomeVeryLongNameAndAllOfItsAdditionalLetters2,
-) -)
-
+from . import (tasks) +from . import (tasks)
+from . import (A, B, C) +from . import (A, B, C)
+from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \ +from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \
+ SomeVeryLongNameAndAllOfItsAdditionalLetters2 + SomeVeryLongNameAndAllOfItsAdditionalLetters2
__all__ = ( __all__ = (
base_events.__all__ base_events.__all__
+ coroutines.__all__
``` ```
## Ruff Output ## Ruff Output
```py ```py
"""The asyncio package, tracking PEP 3156.""" """The asyncio package, tracking PEP 3156."""
# flake8: noqa
from logging import ( from logging import (
WARNING WARNING
) )
@ -130,32 +143,25 @@ from logging import (
ERROR, ERROR,
) )
import sys import sys
# This relies on each of the submodules having an __all__ variable.
from .base_events import * from .base_events import *
from .coroutines import * from .coroutines import *
from .events import * # comment here from .events import *
from .futures import * from .futures import *
from .locks import * # comment here from .locks import *
from .protocols import * from .protocols import *
from ..runners import *
from ..runners import * # comment here
from ..queues import * from ..queues import *
from ..streams import * from ..streams import *
from some_library import ( from some_library import (
Just, Enough, Libraries, To, Fit, In, This, Nice, Split, Which, We, No, Longer, Use Just, Enough, Libraries, To, Fit, In, This, Nice, Split, Which, We, No, Longer, Use
) )
from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import * from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
from .a.b.c.subprocess import * from .a.b.c.subprocess import *
from . import (tasks) from . import (tasks)
from . import (A, B, C) from . import (A, B, C)
from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \ from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \
SomeVeryLongNameAndAllOfItsAdditionalLetters2 SomeVeryLongNameAndAllOfItsAdditionalLetters2
__all__ = ( __all__ = (
base_events.__all__ base_events.__all__
+ coroutines.__all__ + coroutines.__all__

View file

@ -25,10 +25,13 @@ list_of_types = [tuple[int,],]
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -4,19 +4,9 @@ @@ -1,22 +1,6 @@
-# We should not treat the trailing comma
-# in a single-element subscript.
a: tuple[int,]
b = tuple[int,] b = tuple[int,]
-
# The magic comma still applies to multi-element subscripts. -# The magic comma still applies to multi-element subscripts.
-c: tuple[ -c: tuple[
- int, - int,
- int, - int,
@ -37,16 +40,16 @@ list_of_types = [tuple[int,],]
- int, - int,
- int, - int,
-] -]
+c: tuple[int, int,] -
+d = tuple[int, int,] -# Magic commas still work as expected for non-subscripts.
# Magic commas still work as expected for non-subscripts.
-small_list = [ -small_list = [
- 1, - 1,
-] -]
-list_of_types = [ -list_of_types = [
- tuple[int,], - tuple[int,],
-] -]
+c: tuple[int, int,]
+d = tuple[int, int,]
+small_list = [1,] +small_list = [1,]
+list_of_types = [tuple[int,],] +list_of_types = [tuple[int,],]
``` ```
@ -54,16 +57,10 @@ list_of_types = [tuple[int,],]
## Ruff Output ## Ruff Output
```py ```py
# We should not treat the trailing comma
# in a single-element subscript.
a: tuple[int,] a: tuple[int,]
b = tuple[int,] b = tuple[int,]
# The magic comma still applies to multi-element subscripts.
c: tuple[int, int,] c: tuple[int, int,]
d = tuple[int, int,] d = tuple[int, int,]
# Magic commas still work as expected for non-subscripts.
small_list = [1,] small_list = [1,]
list_of_types = [tuple[int,],] list_of_types = [tuple[int,],]
``` ```

View file

@ -76,19 +76,51 @@ return np.divide(
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,10 +1,10 @@ @@ -1,16 +1,10 @@
def function(**kwargs): def function(**kwargs):
t = a**2 + b**3 t = a**2 + b**3
- return t**2 - return t**2
-
-
+ return t ** 2 + return t ** 2
def function_replace_spaces(**kwargs): def function_replace_spaces(**kwargs):
- t = a**2 + b**3 + c**4 - t = a**2 + b**3 + c**4
-
-
+ t = a **2 + b** 3 + c ** 4 + t = a **2 + b** 3 + c ** 4
def function_dont_replace_spaces(): def function_dont_replace_spaces():
{**a, **b, **c}
-
-
a = 5**~4
b = 5 ** f()
c = -(5**2)
@@ -29,7 +23,6 @@
p = {(k, k**2): v**2 for k, v in pairs}
q = [10**i for i in range(6)]
r = x**y
-
a = 5.0**~4.0
b = 5.0 ** f()
c = -(5.0**2.0)
@@ -47,9 +40,6 @@
o = settings(max_examples=10**6.0)
p = {(k, k**2): v**2.0 for k, v in pairs}
q = [10.5**i for i in range(6)]
-
-
-# WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873)
if hasattr(view, "sum_of_weights"):
return np.divide( # type: ignore[no-any-return]
view.variance, # type: ignore[union-attr]
@@ -57,7 +47,6 @@
out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr]
where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr]
)
-
return np.divide(
where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore
)
``` ```
## Ruff Output ## Ruff Output
@ -97,16 +129,10 @@ return np.divide(
def function(**kwargs): def function(**kwargs):
t = a**2 + b**3 t = a**2 + b**3
return t ** 2 return t ** 2
def function_replace_spaces(**kwargs): def function_replace_spaces(**kwargs):
t = a **2 + b** 3 + c ** 4 t = a **2 + b** 3 + c ** 4
def function_dont_replace_spaces(): def function_dont_replace_spaces():
{**a, **b, **c} {**a, **b, **c}
a = 5**~4 a = 5**~4
b = 5 ** f() b = 5 ** f()
c = -(5**2) c = -(5**2)
@ -125,7 +151,6 @@ o = settings(max_examples=10**6)
p = {(k, k**2): v**2 for k, v in pairs} p = {(k, k**2): v**2 for k, v in pairs}
q = [10**i for i in range(6)] q = [10**i for i in range(6)]
r = x**y r = x**y
a = 5.0**~4.0 a = 5.0**~4.0
b = 5.0 ** f() b = 5.0 ** f()
c = -(5.0**2.0) c = -(5.0**2.0)
@ -143,9 +168,6 @@ n = count <= 10**5.0
o = settings(max_examples=10**6.0) o = settings(max_examples=10**6.0)
p = {(k, k**2): v**2.0 for k, v in pairs} p = {(k, k**2): v**2.0 for k, v in pairs}
q = [10.5**i for i in range(6)] q = [10.5**i for i in range(6)]
# WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873)
if hasattr(view, "sum_of_weights"): if hasattr(view, "sum_of_weights"):
return np.divide( # type: ignore[no-any-return] return np.divide( # type: ignore[no-any-return]
view.variance, # type: ignore[union-attr] view.variance, # type: ignore[union-attr]
@ -153,7 +175,6 @@ if hasattr(view, "sum_of_weights"):
out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr] out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr]
where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr] where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr]
) )
return np.divide( return np.divide(
where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore
) )

View file

@ -25,10 +25,11 @@ xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxx
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -2,20 +2,11 @@ @@ -1,21 +1,5 @@
-# Test cases separate from `prefer_rhs_split.py` that contains unformatted source.
# Left hand side fits in a single line but will still be exploded by the -
# magic trailing comma. -# Left hand side fits in a single line but will still be exploded by the
-# magic trailing comma.
-( -(
- first_value, - first_value,
- ( - (
@ -41,9 +42,9 @@ xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxx
arg1, arg1,
arg2, arg2,
) )
-
# Make when when the left side of assignment plus the opening paren "... = (" is -# Make when when the left side of assignment plus the opening paren "... = (" is
# exactly line length limit + 1, it won't be split like that. -# exactly line length limit + 1, it won't be split like that.
-xxxxxxxxx_yyy_zzzzzzzz[ -xxxxxxxxx_yyy_zzzzzzzz[
- xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1) - xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)
-] = 1 -] = 1
@ -53,17 +54,10 @@ xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxx
## Ruff Output ## Ruff Output
```py ```py
# Test cases separate from `prefer_rhs_split.py` that contains unformatted source.
# Left hand side fits in a single line but will still be exploded by the
# magic trailing comma.
first_value, (m1, m2,), third_value = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv( first_value, (m1, m2,), third_value = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv(
arg1, arg1,
arg2, arg2,
) )
# Make when when the left side of assignment plus the opening paren "... = (" is
# exactly line length limit + 1, it won't be split like that.
xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)] = 1 xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)] = 1
``` ```

View file

@ -94,88 +94,90 @@ async def main():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,93 +1,81 @@ @@ -1,93 +1,56 @@
import asyncio import asyncio
- -
# Control example -
-# Control example
async def main(): async def main():
await asyncio.sleep(1) await asyncio.sleep(1)
- -
-
# Remove brackets for short coroutine/task -# Remove brackets for short coroutine/task
async def main(): async def main():
- await asyncio.sleep(1) - await asyncio.sleep(1)
- -
-
+ await (asyncio.sleep(1)) + await (asyncio.sleep(1))
async def main(): async def main():
- await asyncio.sleep(1) - await asyncio.sleep(1)
- -
-
+ await ( + await (
+ asyncio.sleep(1) + asyncio.sleep(1)
+ ) + )
async def main(): async def main():
- await asyncio.sleep(1) - await asyncio.sleep(1)
- -
-
-# Check comments
-async def main():
- await asyncio.sleep(1) # Hello
-
-
-async def main():
- await asyncio.sleep(1) # Hello
-
-
+ await (asyncio.sleep(1) + await (asyncio.sleep(1)
+ ) + )
# Check comments
async def main(): async def main():
- await asyncio.sleep(1) # Hello - await asyncio.sleep(1) # Hello
- -
-
-# Long lines
+ await ( # Hello + await ( # Hello
+ asyncio.sleep(1) + asyncio.sleep(1)
+ ) + )
async def main(): async def main():
- await asyncio.sleep(1) # Hello - await asyncio.gather(
- - asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
+ await ( + await (
+ asyncio.sleep(1) # Hello + asyncio.sleep(1) # Hello
+ ) )
async def main():
- await asyncio.sleep(1) # Hello
- -
-
-# Same as above but with magic trailing comma in function
async def main():
- await asyncio.gather(
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
+ await ( + await (
+ asyncio.sleep(1) + asyncio.sleep(1)
+ ) # Hello )
# Long lines
async def main():
- await asyncio.gather(
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- )
- -
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1))
# Same as above but with magic trailing comma in function
async def main():
- await asyncio.gather(
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
- )
- -
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),) -# Cr@zY Br@ck3Tz
# Cr@zY Br@ck3Tz
async def main(): async def main():
- await black(1) - await black(1)
- -
-
-# Keep brackets around non power operations and nested awaits
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1))
+async def main():
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),)
+async def main():
+ await ( + await (
+ ((((((((((((( + (((((((((((((
+ ((( ((( + ((( (((
@ -189,35 +191,33 @@ async def main():
+ ))) ))) + ))) )))
+ ))))))))))))) + )))))))))))))
+ ) + )
# Keep brackets around non power operations and nested awaits
async def main(): async def main():
await (set_of_tasks | other_set) await (set_of_tasks | other_set)
- -
-
async def main(): async def main():
await (await asyncio.sleep(1)) await (await asyncio.sleep(1))
- -
# It's awaits all the way down... -
-# It's awaits all the way down...
async def main(): async def main():
await (await x) await (await x)
- -
-
async def main(): async def main():
await (yield x) await (yield x)
- -
-
async def main(): async def main():
- await (await asyncio.sleep(1)) - await (await asyncio.sleep(1))
- -
-
+ await (await (asyncio.sleep(1))) + await (await (asyncio.sleep(1)))
async def main(): async def main():
- await (await (await (await (await asyncio.sleep(1))))) - await (await (await (await (await asyncio.sleep(1)))))
- -
-
+ await (await (await (await (await (asyncio.sleep(1)))))) + await (await (await (await (await (asyncio.sleep(1))))))
async def main(): async def main():
await (yield) await (yield)
``` ```
@ -226,49 +226,33 @@ async def main():
```py ```py
import asyncio import asyncio
# Control example
async def main(): async def main():
await asyncio.sleep(1) await asyncio.sleep(1)
# Remove brackets for short coroutine/task
async def main(): async def main():
await (asyncio.sleep(1)) await (asyncio.sleep(1))
async def main(): async def main():
await ( await (
asyncio.sleep(1) asyncio.sleep(1)
) )
async def main(): async def main():
await (asyncio.sleep(1) await (asyncio.sleep(1)
) )
# Check comments
async def main(): async def main():
await ( # Hello await ( # Hello
asyncio.sleep(1) asyncio.sleep(1)
) )
async def main(): async def main():
await ( await (
asyncio.sleep(1) # Hello asyncio.sleep(1) # Hello
) )
async def main(): async def main():
await ( await (
asyncio.sleep(1) asyncio.sleep(1)
) # Hello )
# Long lines
async def main(): async def main():
await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1)) await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1))
# Same as above but with magic trailing comma in function
async def main(): async def main():
await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),) await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),)
# Cr@zY Br@ck3Tz
async def main(): async def main():
await ( await (
((((((((((((( (((((((((((((
@ -283,27 +267,18 @@ async def main():
))) ))) ))) )))
))))))))))))) )))))))))))))
) )
# Keep brackets around non power operations and nested awaits
async def main(): async def main():
await (set_of_tasks | other_set) await (set_of_tasks | other_set)
async def main(): async def main():
await (await asyncio.sleep(1)) await (await asyncio.sleep(1))
# It's awaits all the way down...
async def main(): async def main():
await (await x) await (await x)
async def main(): async def main():
await (yield x) await (yield x)
async def main(): async def main():
await (await (asyncio.sleep(1))) await (await (asyncio.sleep(1)))
async def main(): async def main():
await (await (await (await (await (asyncio.sleep(1)))))) await (await (await (await (await (asyncio.sleep(1))))))
async def main(): async def main():
await (yield) await (yield)
``` ```

View file

@ -48,17 +48,29 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,7 +1,7 @@ @@ -1,42 +1,24 @@
# These brackets are redundant, therefore remove. -# These brackets are redundant, therefore remove.
try: try:
a.something a.something
-except AttributeError as err: -except AttributeError as err:
+except (AttributeError) as err: +except (AttributeError) as err:
raise err raise err
-
# This is tuple of exceptions. -# This is tuple of exceptions.
@@ -21,22 +21,15 @@ -# Although this could be replaced with just the exception,
# Test long variants. -# we do not remove brackets to preserve AST.
try:
a.something
except (AttributeError,) as err:
raise err
-
-# This is a tuple of exceptions. Do not remove brackets.
try:
a.something
except (AttributeError, ValueError) as err:
raise err
-
-# Test long variants.
try: try:
a.something a.something
-except ( -except (
@ -66,7 +78,7 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
-) as err: -) as err:
+except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err: +except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err:
raise err raise err
-
try: try:
a.something a.something
-except ( -except (
@ -74,7 +86,7 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
-) as err: -) as err:
+except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err: +except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err:
raise err raise err
-
try: try:
a.something a.something
-except ( -except (
@ -88,37 +100,26 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
## Ruff Output ## Ruff Output
```py ```py
# These brackets are redundant, therefore remove.
try: try:
a.something a.something
except (AttributeError) as err: except (AttributeError) as err:
raise err raise err
# This is tuple of exceptions.
# Although this could be replaced with just the exception,
# we do not remove brackets to preserve AST.
try: try:
a.something a.something
except (AttributeError,) as err: except (AttributeError,) as err:
raise err raise err
# This is a tuple of exceptions. Do not remove brackets.
try: try:
a.something a.something
except (AttributeError, ValueError) as err: except (AttributeError, ValueError) as err:
raise err raise err
# Test long variants.
try: try:
a.something a.something
except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err: except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err:
raise err raise err
try: try:
a.something a.something
except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err: except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err:
raise err raise err
try: try:
a.something a.something
except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error, some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err: except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error, some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err:

View file

@ -32,24 +32,25 @@ for (((((k, v))))) in d.items():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,5 +1,5 @@ @@ -1,27 +1,11 @@
# Only remove tuple brackets after `for` -# Only remove tuple brackets after `for`
-for k, v in d.items(): -for k, v in d.items():
+for (k, v) in d.items(): +for (k, v) in d.items():
print(k, v) print(k, v)
-
# Don't touch tuple brackets after `in` -# Don't touch tuple brackets after `in`
@@ -8,20 +8,12 @@ for module in (core, _unicodefun):
if hasattr(module, "_verify_python3_env"):
module._verify_python3_env = lambda: None module._verify_python3_env = lambda: None
-
# Brackets remain for long for loop lines -# Brackets remain for long for loop lines
-for ( -for (
- why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, - why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long,
- i_dont_know_but_we_should_still_check_the_behaviour_if_they_do, - i_dont_know_but_we_should_still_check_the_behaviour_if_they_do,
-) in d.items(): -) in d.items():
+for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items(): +for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items():
print(k, v) print(k, v)
-
-for ( -for (
- k, - k,
- v, - v,
@ -58,8 +59,8 @@ for (((((k, v))))) in d.items():
-): -):
+for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items(): +for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
print(k, v) print(k, v)
-
# Test deeply nested brackets -# Test deeply nested brackets
-for k, v in d.items(): -for k, v in d.items():
+for (((((k, v))))) in d.items(): +for (((((k, v))))) in d.items():
print(k, v) print(k, v)
@ -68,23 +69,15 @@ for (((((k, v))))) in d.items():
## Ruff Output ## Ruff Output
```py ```py
# Only remove tuple brackets after `for`
for (k, v) in d.items(): for (k, v) in d.items():
print(k, v) print(k, v)
# Don't touch tuple brackets after `in`
for module in (core, _unicodefun): for module in (core, _unicodefun):
if hasattr(module, "_verify_python3_env"): if hasattr(module, "_verify_python3_env"):
module._verify_python3_env = lambda: None module._verify_python3_env = lambda: None
# Brackets remain for long for loop lines
for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items(): for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items():
print(k, v) print(k, v)
for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items(): for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
print(k, v) print(k, v)
# Test deeply nested brackets
for (((((k, v))))) in d.items(): for (((((k, v))))) in d.items():
print(k, v) print(k, v)
``` ```

View file

@ -121,107 +121,104 @@ with open("/path/to/file.txt", mode="r") as read_file:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -2,20 +2,26 @@ @@ -1,78 +1,74 @@
import random
-
-
def foo1(): def foo1():
+ - print("The newline above me should be deleted!")
print("The newline above me should be deleted!") -
+ print("The newline above me should be deleted!")
def foo2(): def foo2():
+ - print("All the newlines above me should be deleted!")
+
+
print("All the newlines above me should be deleted!")
+
+ print("All the newlines above me should be deleted!")
def foo3(): def foo3():
+ +
print("No newline above me!") print("No newline above me!")
print("There is a newline above me, and that's OK!") print("There is a newline above me, and that's OK!")
+def foo4():
-
def foo4(): -def foo4():
+
# There is a comment here # There is a comment here
print("The newline above me should not be deleted!") print("The newline above me should not be deleted!")
@@ -23,27 +29,39 @@ -
-
class Foo: class Foo:
def bar(self): def bar(self):
+ +
print("The newline above me should be deleted!") print("The newline above me should be deleted!")
-
-
for i in range(5): for i in range(5):
+ - print(f"{i}) The line above me should be removed!")
print(f"{i}) The line above me should be removed!") -
+ print(f"{i}) The line above me should be removed!")
for i in range(5): for i in range(5):
+ - print(f"{i}) The lines above me should be removed!")
+
+
print(f"{i}) The lines above me should be removed!")
+
+ print(f"{i}) The lines above me should be removed!")
for i in range(5): for i in range(5):
+ +
for j in range(7): for j in range(7):
+ +
print(f"{i}) The lines above me should be removed!") print(f"{i}) The lines above me should be removed!")
+if random.randint(0, 3) == 0:
-
+ print("The new line above me is about to be removed!")
if random.randint(0, 3) == 0: if random.randint(0, 3) == 0:
+ - print("The new line above me is about to be removed!")
print("The new line above me is about to be removed!")
-if random.randint(0, 3) == 0:
- print("The new lines above me is about to be removed!")
+ print("The new lines above me is about to be removed!")
if random.randint(0, 3) == 0: if random.randint(0, 3) == 0:
+ if random.uniform(0, 1) > 0.5:
+ print("Two lines above me are about to be removed!")
+ -
+ +while True:
print("The new lines above me is about to be removed!")
@@ -53,26 +71,38 @@
+ print("The newline above me should be deleted!")
while True: while True:
+ - print("The newline above me should be deleted!")
print("The newline above me should be deleted!")
while True: -while True:
+
+
+ +
print("The newlines above me should be deleted!") print("The newlines above me should be deleted!")
+while True:
-
while True: -while True:
+
while False: while False:
+ - print("The newlines above me should be deleted!")
print("The newlines above me should be deleted!") -
+ print("The newlines above me should be deleted!")
with open("/path/to/file.txt", mode="w") as file: with open("/path/to/file.txt", mode="w") as file:
+ - file.write("The new line above me is about to be removed!")
file.write("The new line above me is about to be removed!") -
+ file.write("The new line above me is about to be removed!")
with open("/path/to/file.txt", mode="w") as file: with open("/path/to/file.txt", mode="w") as file:
+ - file.write("The new lines above me is about to be removed!")
+
+
file.write("The new lines above me is about to be removed!")
+
+ file.write("The new lines above me is about to be removed!")
with open("/path/to/file.txt", mode="r") as read_file: with open("/path/to/file.txt", mode="r") as read_file:
+ +
with open("/path/to/output_file.txt", mode="w") as write_file: with open("/path/to/output_file.txt", mode="w") as write_file:
@ -233,108 +230,74 @@ with open("/path/to/file.txt", mode="r") as read_file:
```py ```py
import random import random
def foo1(): def foo1():
print("The newline above me should be deleted!") print("The newline above me should be deleted!")
def foo2(): def foo2():
print("All the newlines above me should be deleted!") print("All the newlines above me should be deleted!")
def foo3(): def foo3():
print("No newline above me!") print("No newline above me!")
print("There is a newline above me, and that's OK!") print("There is a newline above me, and that's OK!")
def foo4(): def foo4():
# There is a comment here # There is a comment here
print("The newline above me should not be deleted!") print("The newline above me should not be deleted!")
class Foo: class Foo:
def bar(self): def bar(self):
print("The newline above me should be deleted!") print("The newline above me should be deleted!")
for i in range(5): for i in range(5):
print(f"{i}) The line above me should be removed!") print(f"{i}) The line above me should be removed!")
for i in range(5): for i in range(5):
print(f"{i}) The lines above me should be removed!") print(f"{i}) The lines above me should be removed!")
for i in range(5): for i in range(5):
for j in range(7): for j in range(7):
print(f"{i}) The lines above me should be removed!") print(f"{i}) The lines above me should be removed!")
if random.randint(0, 3) == 0: if random.randint(0, 3) == 0:
print("The new line above me is about to be removed!") print("The new line above me is about to be removed!")
if random.randint(0, 3) == 0: if random.randint(0, 3) == 0:
print("The new lines above me is about to be removed!") print("The new lines above me is about to be removed!")
if random.randint(0, 3) == 0: if random.randint(0, 3) == 0:
if random.uniform(0, 1) > 0.5: if random.uniform(0, 1) > 0.5:
print("Two lines above me are about to be removed!") print("Two lines above me are about to be removed!")
while True: while True:
print("The newline above me should be deleted!") print("The newline above me should be deleted!")
while True: while True:
print("The newlines above me should be deleted!") print("The newlines above me should be deleted!")
while True: while True:
while False: while False:
print("The newlines above me should be deleted!") print("The newlines above me should be deleted!")
with open("/path/to/file.txt", mode="w") as file: with open("/path/to/file.txt", mode="w") as file:
file.write("The new line above me is about to be removed!") file.write("The new line above me is about to be removed!")
with open("/path/to/file.txt", mode="w") as file: with open("/path/to/file.txt", mode="w") as file:
file.write("The new lines above me is about to be removed!") file.write("The new lines above me is about to be removed!")
with open("/path/to/file.txt", mode="r") as read_file: with open("/path/to/file.txt", mode="r") as read_file:
with open("/path/to/output_file.txt", mode="w") as write_file: with open("/path/to/output_file.txt", mode="w") as write_file:

View file

@ -68,16 +68,16 @@ def example8():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,85 +1,55 @@ @@ -1,85 +1,34 @@
-x = 1 -x = 1
-x = 1.2 -x = 1.2
-
+x = (1) +x = (1)
+x = (1.2) +x = (1.2)
data = ( data = (
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
).encode() ).encode()
-
- -
async def show_status(): async def show_status():
while True: while True:
@ -91,51 +91,51 @@ def example8():
except Exception as e: except Exception as e:
pass pass
- -
-
def example(): def example():
- return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-
-
+ return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example1(): def example1():
- return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 - return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
-
-
+ return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) + return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example1point5(): def example1point5():
- return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 - return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
-
-
+ return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)))))) + return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))))))
def example2(): def example2():
- return ( - return (
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" - "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- ) - )
-
-
+ return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) + return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example3(): def example3():
- return ( - return (
- 1111111111111111111111111111111111111111111111111111111111111111111111111111111 - 1111111111111111111111111111111111111111111111111111111111111111111111111111111
- ) - )
-
-
+ return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111)) + return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example4(): def example4():
- return True - return True
-
-
+ return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example5(): def example5():
- return () - return ()
-
-
+ return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example6(): def example6():
- return {a: a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]} - return {a: a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}
-
-
+ return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}))))))))) + return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]})))))))))
def example7(): def example7():
- return { - return {
- a: a - a: a
@ -162,9 +162,9 @@ def example8():
- 20000000000000000000, - 20000000000000000000,
- ] - ]
- } - }
-
-
+ return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]}))))))))) + return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]})))))))))
def example8(): def example8():
- return None - return None
+ return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) + return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
@ -175,11 +175,9 @@ def example8():
```py ```py
x = (1) x = (1)
x = (1.2) x = (1.2)
data = ( data = (
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
).encode() ).encode()
async def show_status(): async def show_status():
while True: while True:
try: try:
@ -189,43 +187,24 @@ async def show_status():
).encode() ).encode()
except Exception as e: except Exception as e:
pass pass
def example(): def example():
return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example1(): def example1():
return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)) return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example1point5(): def example1point5():
return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111)))))) return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))))))
def example2(): def example2():
return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example3(): def example3():
return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111)) return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example4(): def example4():
return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example5(): def example5():
return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((())))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example6(): def example6():
return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}))))))))) return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]})))))))))
def example7(): def example7():
return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]}))))))))) return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]})))))))))
def example8(): def example8():
return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))) return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
``` ```

View file

@ -101,81 +101,81 @@ def foo() -> tuple[int, int, int,]:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,120 +1,88 @@ @@ -1,120 +1,60 @@
# Control -# Control
-def double(a: int) -> int:
- return 2 * a
-
-
-# Remove the brackets
-def double(a: int) -> int:
- return 2 * a
-
-
-# Some newline variations
-def double(a: int) -> int:
- return 2 * a
-
-
-def double(a: int) -> int:
- return 2 * a
-
-
def double(a: int) -> int: def double(a: int) -> int:
- return 2 * a - return 2 * a
+ return 2*a
- -
# Remove the brackets -
-def double(a: int) -> int: -# Don't lose the comments
-def double(a: int) -> int: # Hello
- return 2 * a - return 2 * a
- -
-
-def double(a: int) -> int: # Hello
- return 2 * a
-
-
-# Really long annotations
-def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
+ return 2*a
+def double(a: int) -> (int): +def double(a: int) -> (int):
+ return 2*a + return 2*a
# Some newline variations
-def double(a: int) -> int:
- return 2 * a
+def double(a: int) -> ( +def double(a: int) -> (
+ int): + int):
+ return 2*a + return 2*a
-
-def double(a: int) -> int:
- return 2 * a
-
-
-def double(a: int) -> int:
- return 2 * a
+def double(a: int) -> (int +def double(a: int) -> (int
+): +):
+ return 2*a + return 2*a
+def double(a: int) -> ( +def double(a: int) -> (
+ int + int
+): +):
+ return 2*a + return 2*a
# Don't lose the comments
-def double(a: int) -> int: # Hello
- return 2 * a
-
+def double(a: int) -> ( # Hello +def double(a: int) -> ( # Hello
+ int + int
+): ):
+ return 2*a - return 2
-def double(a: int) -> int: # Hello
- return 2 * a
- -
-
+ return 2*a
+def double(a: int) -> ( +def double(a: int) -> (
+ int # Hello + int # Hello
+): +):
+ return 2*a + return 2*a
# Really long annotations
def foo() -> ( def foo() -> (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
): ):
return 2 return 2
- -
-def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-):
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
- -
-def foo() -> ( -def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds - intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
- | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds - | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-): -):
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
+ return 2
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: +def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
-
- -
-def foo( -def foo(
- a: int, - a: int,
@ -184,7 +184,7 @@ def foo() -> tuple[int, int, int,]:
-) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: -) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
+def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: +def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
-
- -
-def foo( -def foo(
- a: int, - a: int,
@ -196,9 +196,9 @@ def foo() -> tuple[int, int, int,]:
-): -):
+def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: +def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
- -
# Split args but no need to split return -
-# Split args but no need to split return
-def foo( -def foo(
- a: int, - a: int,
- b: int, - b: int,
@ -206,19 +206,20 @@ def foo() -> tuple[int, int, int,]:
-) -> int: -) -> int:
+def foo(a: int, b: int, c: int,) -> int: +def foo(a: int, b: int, c: int,) -> int:
return 2 return 2
- -
# Deeply nested brackets -
# with *interesting* spacing -# Deeply nested brackets
-# with *interesting* spacing
-def double(a: int) -> int: -def double(a: int) -> int:
- return 2 * a - return 2 * a
- -
- -
-def double(a: int) -> int: -def double(a: int) -> int:
- return 2 * a - return 2 * a
-
-
+def double(a: int) -> (((((int))))): +def double(a: int) -> (((((int))))):
+ return 2*a + return 2*a
+def double(a: int) -> ( +def double(a: int) -> (
+ ( ( + ( (
+ ((int) + ((int)
@ -227,7 +228,6 @@ def foo() -> tuple[int, int, int,]:
+ ) + )
+ ): + ):
+ return 2*a + return 2*a
def foo() -> ( def foo() -> (
+ ( ( + ( (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
@ -235,9 +235,9 @@ def foo() -> tuple[int, int, int,]:
+) +)
+)): +)):
return 2 return 2
- -
# Return type with commas -
-# Return type with commas
-def foo() -> tuple[int, int, int]: -def foo() -> tuple[int, int, int]:
- return 2 - return 2
- -
@ -251,11 +251,9 @@ def foo() -> tuple[int, int, int,]:
+ tuple[int, int, int] + tuple[int, int, int]
): ):
return 2 return 2
-
+def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]: -
+ return 2 -# Magic trailing comma example
# Magic trailing comma example
-def foo() -> ( -def foo() -> (
- tuple[ - tuple[
- int, - int,
@ -263,6 +261,8 @@ def foo() -> tuple[int, int, int,]:
- int, - int,
- ] - ]
-): -):
+def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]:
+ return 2
+def foo() -> tuple[int, int, int,]: +def foo() -> tuple[int, int, int,]:
return 2 return 2
``` ```
@ -270,66 +270,44 @@ def foo() -> tuple[int, int, int,]:
## Ruff Output ## Ruff Output
```py ```py
# Control
def double(a: int) -> int: def double(a: int) -> int:
return 2*a return 2*a
# Remove the brackets
def double(a: int) -> (int): def double(a: int) -> (int):
return 2*a return 2*a
# Some newline variations
def double(a: int) -> ( def double(a: int) -> (
int): int):
return 2*a return 2*a
def double(a: int) -> (int def double(a: int) -> (int
): ):
return 2*a return 2*a
def double(a: int) -> ( def double(a: int) -> (
int int
): ):
return 2*a return 2*a
# Don't lose the comments
def double(a: int) -> ( # Hello def double(a: int) -> ( # Hello
int int
): ):
return 2*a return 2*a
def double(a: int) -> ( def double(a: int) -> (
int # Hello int # Hello
): ):
return 2*a return 2*a
# Really long annotations
def foo() -> ( def foo() -> (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
): ):
return 2 return 2
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds: def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2 return 2
# Split args but no need to split return
def foo(a: int, b: int, c: int,) -> int: def foo(a: int, b: int, c: int,) -> int:
return 2 return 2
# Deeply nested brackets
# with *interesting* spacing
def double(a: int) -> (((((int))))): def double(a: int) -> (((((int))))):
return 2*a return 2*a
def double(a: int) -> ( def double(a: int) -> (
( ( ( (
((int) ((int)
@ -338,24 +316,18 @@ def double(a: int) -> (
) )
): ):
return 2*a return 2*a
def foo() -> ( def foo() -> (
( ( ( (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
) )
)): )):
return 2 return 2
# Return type with commas
def foo() -> ( def foo() -> (
tuple[int, int, int] tuple[int, int, int]
): ):
return 2 return 2
def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]: def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]:
return 2 return 2
# Magic trailing comma example
def foo() -> tuple[int, int, int,]: def foo() -> tuple[int, int, int,]:
return 2 return 2
``` ```

View file

@ -60,30 +60,38 @@ func(
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -3,23 +3,45 @@ @@ -1,25 +1,35 @@
-# We should not remove the trailing comma in a single-element subscript.
a: tuple[int,]
b = tuple[int,] b = tuple[int,]
-
# But commas in multiple element subscripts should be removed. -# But commas in multiple element subscripts should be removed.
-c: tuple[int, int] -c: tuple[int, int]
-d = tuple[int, int] -d = tuple[int, int]
+c: tuple[int, int,] -
+d = tuple[int, int,] -# Remove commas for non-subscripts.
# Remove commas for non-subscripts.
-small_list = [1] -small_list = [1]
-list_of_types = [tuple[int,]] -list_of_types = [tuple[int,]]
-small_set = {1} -small_set = {1}
-set_of_types = {tuple[int,]} -set_of_types = {tuple[int,]}
-
-# Except single element tuples
+c: tuple[int, int,]
+d = tuple[int, int,]
+small_list = [1,] +small_list = [1,]
+list_of_types = [tuple[int,],] +list_of_types = [tuple[int,],]
+small_set = {1,} +small_set = {1,}
+set_of_types = {tuple[int,],} +set_of_types = {tuple[int,],}
# Except single element tuples
small_tuple = (1,) small_tuple = (1,)
-
# Trailing commas in multiple chained non-nested parens. -# Trailing commas in multiple chained non-nested parens.
-zero(one).two(three).four(five) -zero(one).two(three).four(five)
-
-func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5)
-
-(a, b, c, d) = func1(arg1) and func2(arg2)
-
-func(argument1, (one, two), argument4, argument5, argument6)
+zero( +zero(
+ one, + one,
+).two( +).two(
@ -91,11 +99,7 @@ func(
+).four( +).four(
+ five, + five,
+) +)
-func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5)
+func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) +func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5)
-(a, b, c, d) = func1(arg1) and func2(arg2)
+( +(
+ a, + a,
+ b, + b,
@ -104,8 +108,6 @@ func(
+) = func1( +) = func1(
+ arg1 + arg1
+) and func2(arg2) +) and func2(arg2)
-func(argument1, (one, two), argument4, argument5, argument6)
+func( +func(
+ argument1, + argument1,
+ ( + (
@ -121,24 +123,15 @@ func(
## Ruff Output ## Ruff Output
```py ```py
# We should not remove the trailing comma in a single-element subscript.
a: tuple[int,] a: tuple[int,]
b = tuple[int,] b = tuple[int,]
# But commas in multiple element subscripts should be removed.
c: tuple[int, int,] c: tuple[int, int,]
d = tuple[int, int,] d = tuple[int, int,]
# Remove commas for non-subscripts.
small_list = [1,] small_list = [1,]
list_of_types = [tuple[int,],] list_of_types = [tuple[int,],]
small_set = {1,} small_set = {1,}
set_of_types = {tuple[int,],} set_of_types = {tuple[int,],}
# Except single element tuples
small_tuple = (1,) small_tuple = (1,)
# Trailing commas in multiple chained non-nested parens.
zero( zero(
one, one,
).two( ).two(
@ -146,9 +139,7 @@ zero(
).four( ).four(
five, five,
) )
func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5)
( (
a, a,
b, b,
@ -157,7 +148,6 @@ func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5)
) = func1( ) = func1(
arg1 arg1
) and func2(arg2) ) and func2(arg2)
func( func(
argument1, argument1,
( (

View file

@ -76,7 +76,35 @@ x[
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -56,4 +56,8 @@ @@ -17,19 +17,12 @@
slice[not so_simple : 1 < val <= 10]
slice[(1 for i in range(42)) : x]
slice[:: [i for i in range(42)]]
-
-
async def f():
slice[await x : [i async for i in arange(42)] : 42]
-
-
-# These are from PEP-8:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
-# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
-
slice[::, ::]
slice[
# A
@@ -46,7 +39,6 @@
# C
3
]
-
slice[
# A
1
@@ -56,4 +48,8 @@
# C # C
4 4
] ]
@ -110,19 +138,12 @@ slice[1 or 2 : True and False]
slice[not so_simple : 1 < val <= 10] slice[not so_simple : 1 < val <= 10]
slice[(1 for i in range(42)) : x] slice[(1 for i in range(42)) : x]
slice[:: [i for i in range(42)]] slice[:: [i for i in range(42)]]
async def f(): async def f():
slice[await x : [i async for i in arange(42)] : 42] slice[await x : [i async for i in arange(42)] : 42]
# These are from PEP-8:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:] ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step] ham[lower:upper], ham[lower:upper:], ham[lower::step]
# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)] ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset] ham[lower + offset : upper + offset]
slice[::, ::] slice[::, ::]
slice[ slice[
# A # A
@ -139,7 +160,6 @@ slice[
# C # C
3 3
] ]
slice[ slice[
# A # A
1 1

View file

@ -33,9 +33,9 @@ def docstring_multiline():
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,13 +1,13 @@ @@ -1,19 +1,12 @@
#!/usr/bin/env python3 -#!/usr/bin/env python3
-
name = "Łukasz" name = "Łukasz"
-(f"hello {name}", f"hello {name}") -(f"hello {name}", f"hello {name}")
-(b"", b"") -(b"", b"")
@ -44,35 +44,34 @@ def docstring_multiline():
+(b"", B"") +(b"", B"")
+(u"", U"") +(u"", U"")
(r"", R"") (r"", R"")
-
-(rf"", rf"", Rf"", Rf"", rf"", rf"", Rf"", Rf"") -(rf"", rf"", Rf"", Rf"", rf"", rf"", Rf"", Rf"")
-(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"") -(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"")
-
-
+(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"") +(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"")
+(rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"") +(rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"")
def docstring_singleline(): def docstring_singleline():
R"""2020 was one hell of a year. The good news is that we were able to"""
-
-
def docstring_multiline():
R"""
clear out all of the issues opened in that time :p
``` ```
## Ruff Output ## Ruff Output
```py ```py
#!/usr/bin/env python3
name = "Łukasz" name = "Łukasz"
(f"hello {name}", F"hello {name}") (f"hello {name}", F"hello {name}")
(b"", B"") (b"", B"")
(u"", U"") (u"", U"")
(r"", R"") (r"", R"")
(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"") (rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"")
(rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"") (rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"")
def docstring_singleline(): def docstring_singleline():
R"""2020 was one hell of a year. The good news is that we were able to""" R"""2020 was one hell of a year. The good news is that we were able to"""
def docstring_multiline(): def docstring_multiline():
R""" R"""
clear out all of the issues opened in that time :p clear out all of the issues opened in that time :p

View file

@ -42,15 +42,15 @@ assert (
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,58 +1,29 @@ @@ -1,58 +1,25 @@
-importA importA
-( -(
- () - ()
- << 0 - << 0
- ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 - ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525
-) # -) #
+importA;() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 # -
+() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525
assert sort_by_dependency( assert sort_by_dependency(
{ {
- "1": {"2", "3"}, - "1": {"2", "3"},
@ -64,13 +64,13 @@ assert (
+ "2a": set(), "2b": set(), "3a": set(), "3b": set() + "2a": set(), "2b": set(), "3a": set(), "3b": set()
} }
) == ["2a", "2b", "2", "3a", "3b", "3", "1"] ) == ["2a", "2b", "2", "3a", "3b", "3", "1"]
-
importA importA
-0 0
-0 ^ 0 # -0 ^ 0 #
- -
+0;0^0# -
+0^0
class A: class A:
def foo(self): def foo(self):
for _ in range(10): for _ in range(10):
@ -79,8 +79,8 @@ assert (
xxxxxxxxxxxx xxxxxxxxxxxx
- ) # pylint: disable=no-member - ) # pylint: disable=no-member
- -
-
+ ) + )
def test(self, othr): def test(self, othr):
- return 1 == 2 and ( - return 1 == 2 and (
- name, - name,
@ -101,15 +101,15 @@ assert (
- othr.meta_data, - othr.meta_data,
- othr.schedule, - othr.schedule,
- ) - )
+ return (1 == 2 and -
+ (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) == -
+ (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule))
-assert a_function( -assert a_function(
- very_long_arguments_that_surpass_the_limit, - very_long_arguments_that_surpass_the_limit,
- which_is_eighty_eight_in_this_case_plus_a_bit_more, - which_is_eighty_eight_in_this_case_plus_a_bit_more,
-) == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"} -) == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"}
+ return (1 == 2 and
+ (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) ==
+ (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule))
+assert ( +assert (
+ a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more) + a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more)
+ == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"} + == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"}
@ -119,31 +119,27 @@ assert (
## Ruff Output ## Ruff Output
```py ```py
importA;() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 # importA
() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525
assert sort_by_dependency( assert sort_by_dependency(
{ {
"1": {"2", "3"}, "2": {"2a", "2b"}, "3": {"3a", "3b"}, "1": {"2", "3"}, "2": {"2a", "2b"}, "3": {"3a", "3b"},
"2a": set(), "2b": set(), "3a": set(), "3b": set() "2a": set(), "2b": set(), "3a": set(), "3b": set()
} }
) == ["2a", "2b", "2", "3a", "3b", "3", "1"] ) == ["2a", "2b", "2", "3a", "3b", "3", "1"]
importA importA
0;0^0# 0
0^0
class A: class A:
def foo(self): def foo(self):
for _ in range(10): for _ in range(10):
aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( # pylint: disable=no-member aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( # pylint: disable=no-member
xxxxxxxxxxxx xxxxxxxxxxxx
) )
def test(self, othr): def test(self, othr):
return (1 == 2 and return (1 == 2 and
(name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) == (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) ==
(name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule)) (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule))
assert ( assert (
a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more) a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more)
== {"x": "this need to pass the line limit as well", "b": "but only by a little bit"} == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"}

View file

@ -38,7 +38,7 @@ class A:
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,19 +1,11 @@ @@ -1,29 +1,17 @@
-if e1234123412341234.winerror not in ( -if e1234123412341234.winerror not in (
- _winapi.ERROR_SEM_TIMEOUT, - _winapi.ERROR_SEM_TIMEOUT,
- _winapi.ERROR_PIPE_BUSY, - _winapi.ERROR_PIPE_BUSY,
@ -46,7 +46,7 @@ class A:
+if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT, +if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT,
+ _winapi.ERROR_PIPE_BUSY) or _check_timeout(t): + _winapi.ERROR_PIPE_BUSY) or _check_timeout(t):
pass pass
-
if x: if x:
if y: if y:
- new_id = ( - new_id = (
@ -57,21 +57,22 @@ class A:
- + 1 - + 1
- ) - )
- -
-
+ new_id = max(Vegetable.objects.order_by('-id')[0].id, + new_id = max(Vegetable.objects.order_by('-id')[0].id,
+ Mineral.objects.order_by('-id')[0].id) + 1 + Mineral.objects.order_by('-id')[0].id) + 1
class X: class X:
def get_help_text(self): def get_help_text(self):
@@ -21,8 +13,7 @@ return ngettext(
"Your password must contain at least %(min_length)d character.", "Your password must contain at least %(min_length)d character.",
"Your password must contain at least %(min_length)d characters.", "Your password must contain at least %(min_length)d characters.",
self.min_length, self.min_length,
- ) % {"min_length": self.min_length} - ) % {"min_length": self.min_length}
- -
-
+ ) % {'min_length': self.min_length} + ) % {'min_length': self.min_length}
class A: class A:
def b(self): def b(self):
if self.connection.mysql_is_mariadb and (
``` ```
## Ruff Output ## Ruff Output
@ -80,12 +81,10 @@ class A:
if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT, if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT,
_winapi.ERROR_PIPE_BUSY) or _check_timeout(t): _winapi.ERROR_PIPE_BUSY) or _check_timeout(t):
pass pass
if x: if x:
if y: if y:
new_id = max(Vegetable.objects.order_by('-id')[0].id, new_id = max(Vegetable.objects.order_by('-id')[0].id,
Mineral.objects.order_by('-id')[0].id) + 1 Mineral.objects.order_by('-id')[0].id) + 1
class X: class X:
def get_help_text(self): def get_help_text(self):
return ngettext( return ngettext(
@ -93,7 +92,6 @@ class X:
"Your password must contain at least %(min_length)d characters.", "Your password must contain at least %(min_length)d characters.",
self.min_length, self.min_length,
) % {'min_length': self.min_length} ) % {'min_length': self.min_length}
class A: class A:
def b(self): def b(self):
if self.connection.mysql_is_mariadb and ( if self.connection.mysql_is_mariadb and (

View file

@ -46,7 +46,7 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,28 +1,11 @@ @@ -1,31 +1,7 @@
-zero( -zero(
- one, - one,
-).two( -).two(
@ -54,18 +54,18 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
-).four( -).four(
- five, - five,
-) -)
+zero(one,).two(three,).four(five,) -
-func1(arg1).func2( -func1(arg1).func2(
- arg2, - arg2,
-).func3(arg3).func4( -).func3(arg3).func4(
- arg4, - arg4,
-).func5(arg5) -).func5(arg5)
-
-# Inner one-element tuple shouldn't explode
+zero(one,).two(three,).four(five,)
+func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) +func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5)
# Inner one-element tuple shouldn't explode
func1(arg1).func2(arg1, (one_tuple,)).func3(arg3) func1(arg1).func2(arg1, (one_tuple,)).func3(arg3)
-
-( -(
- a, - a,
- b, - b,
@ -74,26 +74,39 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
-) = func1( -) = func1(
- arg1 - arg1
-) and func2(arg2) -) and func2(arg2)
-
-
-# Example from https://github.com/psf/black/issues/3229
+(a, b, c, d,) = func1(arg1) and func2(arg2) +(a, b, c, d,) = func1(arg1) and func2(arg2)
def refresh_token(self, device_family, refresh_token, api_key):
return self.orchestration.refresh_token(
# Example from https://github.com/psf/black/issues/3229 data={
@@ -33,16 +9,10 @@
},
api_key=api_key,
)["extensions"]["sdk"]["token"]
-
-
-# Edge case where a bug in a working-in-progress version of
-# https://github.com/psf/black/pull/3370 causes an infinite recursion.
assert (
long_module.long_class.long_func().another_func()
== long_module.long_class.long_func()["some_key"].another_func(arg1)
)
-
-# Regression test for https://github.com/psf/black/issues/3414.
assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
xxxxxxxxx
).xxxxxxxxxxxxxxxxxx(), (
``` ```
## Ruff Output ## Ruff Output
```py ```py
zero(one,).two(three,).four(five,) zero(one,).two(three,).four(five,)
func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5) func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5)
# Inner one-element tuple shouldn't explode
func1(arg1).func2(arg1, (one_tuple,)).func3(arg3) func1(arg1).func2(arg1, (one_tuple,)).func3(arg3)
(a, b, c, d,) = func1(arg1) and func2(arg2) (a, b, c, d,) = func1(arg1) and func2(arg2)
# Example from https://github.com/psf/black/issues/3229
def refresh_token(self, device_family, refresh_token, api_key): def refresh_token(self, device_family, refresh_token, api_key):
return self.orchestration.refresh_token( return self.orchestration.refresh_token(
data={ data={
@ -101,16 +114,10 @@ def refresh_token(self, device_family, refresh_token, api_key):
}, },
api_key=api_key, api_key=api_key,
)["extensions"]["sdk"]["token"] )["extensions"]["sdk"]["token"]
# Edge case where a bug in a working-in-progress version of
# https://github.com/psf/black/pull/3370 causes an infinite recursion.
assert ( assert (
long_module.long_class.long_func().another_func() long_module.long_class.long_func().another_func()
== long_module.long_class.long_func()["some_key"].another_func(arg1) == long_module.long_class.long_func()["some_key"].another_func(arg1)
) )
# Regression test for https://github.com/psf/black/issues/3414.
assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx( assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
xxxxxxxxx xxxxxxxxx
).xxxxxxxxxxxxxxxxxx(), ( ).xxxxxxxxxxxxxxxxxx(), (

View file

@ -0,0 +1,61 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/tricky_unicode_symbols.py
---
## Input
```py
ä = 1
µ = 2
蟒 = 3
x󠄀 = 4
មុ = 1
Q̇_per_meter = 4
A᧚ = 3
A፩ = 8
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -4,6 +4,5 @@
x󠄀 = 4
មុ = 1
Q̇_per_meter = 4
-
A᧚ = 3
A፩ = 8
```
## Ruff Output
```py
ä = 1
µ = 2
蟒 = 3
x󠄀 = 4
មុ = 1
Q̇_per_meter = 4
A᧚ = 3
A፩ = 8
```
## Black Output
```py
ä = 1
µ = 2
蟒 = 3
x󠄀 = 4
មុ = 1
Q̇_per_meter = 4
A᧚ = 3
A፩ = 8
```

View file

@ -20,32 +20,28 @@ this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890")
```diff ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,12 +1,7 @@ @@ -1,12 +1,3 @@
# This is a standalone comment. -# This is a standalone comment.
-( -(
- sdfjklsdfsjldkflkjsf, - sdfjklsdfsjldkflkjsf,
- sdfjsdfjlksdljkfsdlkf, - sdfjsdfjlksdljkfsdlkf,
- sdfsdjfklsdfjlksdljkf, - sdfsdjfklsdfjlksdljkf,
- sdsfsdfjskdflsfsdf, - sdsfsdfjskdflsfsdf,
-) = (1, 2, 3) -) = (1, 2, 3)
+sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3 -
-# This is as well.
# This is as well.
-(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890") -(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890")
-
+sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3
+this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") +this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890")
(a,) = call() (a,) = call()
``` ```
## Ruff Output ## Ruff Output
```py ```py
# This is a standalone comment.
sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3 sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3
# This is as well.
this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890") this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890")
(a,) = call() (a,) = call()
``` ```

View file

@ -1,3 +1,8 @@
use crate::context::PyFormatContext;
use crate::{AsFormat, IntoFormat, PyFormatter};
use ruff_formatter::{Format, FormatOwnedWithRule, FormatRefWithRule, FormatResult, FormatRule};
use rustpython_parser::ast::Stmt;
pub(crate) mod stmt_ann_assign; pub(crate) mod stmt_ann_assign;
pub(crate) mod stmt_assert; pub(crate) mod stmt_assert;
pub(crate) mod stmt_assign; pub(crate) mod stmt_assign;
@ -25,3 +30,54 @@ pub(crate) mod stmt_try;
pub(crate) mod stmt_try_star; pub(crate) mod stmt_try_star;
pub(crate) mod stmt_while; pub(crate) mod stmt_while;
pub(crate) mod stmt_with; pub(crate) mod stmt_with;
#[derive(Default)]
pub struct FormatStmt;
impl FormatRule<Stmt, PyFormatContext<'_>> for FormatStmt {
fn fmt(&self, item: &Stmt, f: &mut PyFormatter) -> FormatResult<()> {
match item {
Stmt::FunctionDef(x) => x.format().fmt(f),
Stmt::AsyncFunctionDef(x) => x.format().fmt(f),
Stmt::ClassDef(x) => x.format().fmt(f),
Stmt::Return(x) => x.format().fmt(f),
Stmt::Delete(x) => x.format().fmt(f),
Stmt::Assign(x) => x.format().fmt(f),
Stmt::AugAssign(x) => x.format().fmt(f),
Stmt::AnnAssign(x) => x.format().fmt(f),
Stmt::For(x) => x.format().fmt(f),
Stmt::AsyncFor(x) => x.format().fmt(f),
Stmt::While(x) => x.format().fmt(f),
Stmt::If(x) => x.format().fmt(f),
Stmt::With(x) => x.format().fmt(f),
Stmt::AsyncWith(x) => x.format().fmt(f),
Stmt::Match(x) => x.format().fmt(f),
Stmt::Raise(x) => x.format().fmt(f),
Stmt::Try(x) => x.format().fmt(f),
Stmt::TryStar(x) => x.format().fmt(f),
Stmt::Assert(x) => x.format().fmt(f),
Stmt::Import(x) => x.format().fmt(f),
Stmt::ImportFrom(x) => x.format().fmt(f),
Stmt::Global(x) => x.format().fmt(f),
Stmt::Nonlocal(x) => x.format().fmt(f),
Stmt::Expr(x) => x.format().fmt(f),
Stmt::Pass(x) => x.format().fmt(f),
Stmt::Break(x) => x.format().fmt(f),
Stmt::Continue(x) => x.format().fmt(f),
}
}
}
impl<'ast> AsFormat<PyFormatContext<'ast>> for Stmt {
type Format<'a> = FormatRefWithRule<'a, Stmt, FormatStmt, PyFormatContext<'ast>>;
fn format(&self) -> Self::Format<'_> {
FormatRefWithRule::new(self, FormatStmt::default())
}
}
impl<'ast> IntoFormat<PyFormatContext<'ast>> for Stmt {
type Format = FormatOwnedWithRule<Stmt, FormatStmt, PyFormatContext<'ast>>;
fn into_format(self) -> Self::Format {
FormatOwnedWithRule::new(self, FormatStmt::default())
}
}