mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-01 12:25:10 +00:00
Call chain formatting in fluent style (#6151)
Implement fluent style/call chains. See the `call_chains.py` formatting for examples. This isn't fully like black because in `raise A from B` they allow `A` breaking can influence the formatting of `B` even if it is already multiline. Similarity index: | project | main | PR | |--------------|-------|-------| | build | ??? | 0.753 | | django | 0.991 | 0.998 | | transformers | 0.993 | 0.994 | | typeshed | 0.723 | 0.723 | | warehouse | 0.978 | 0.994 | | zulip | 0.992 | 0.994 | Call chain formatting is affected by https://github.com/astral-sh/ruff/issues/627, but i'm cutting scope here. Closes #5343 **Test Plan**: * Added a dedicated call chains test file * The ecosystem checks found some bugs * I manually check django and zulip formatting --------- Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
parent
35bdbe43a8
commit
99baad12d8
16 changed files with 917 additions and 517 deletions
|
|
@ -1,348 +0,0 @@
|
|||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
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
|
||||
@@ -58,37 +58,28 @@
|
||||
|
||||
def foo(list_a, list_b):
|
||||
results = (
|
||||
- User.query.filter(User.foo == "bar")
|
||||
- .filter( # Because foo.
|
||||
+ 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))
|
||||
+ ).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()
|
||||
+ 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))
|
||||
- )
|
||||
+ 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(
|
||||
+ 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))
|
||||
+ ).filter(User.xyz.is_(None))
|
||||
)
|
||||
```
|
||||
|
||||
## 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))
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -300,40 +300,7 @@ last_call()
|
|||
) # note: no trailing comma pre-3.6
|
||||
call(*gidgets[:2])
|
||||
call(a, *gidgets[:2])
|
||||
@@ -208,24 +209,14 @@
|
||||
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
|
||||
vars_to_remove
|
||||
)
|
||||
-result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
- models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
- )
|
||||
- .order_by(models.Customer.id.asc())
|
||||
- .all()
|
||||
-)
|
||||
-result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
- models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
- )
|
||||
- .order_by(
|
||||
- models.Customer.id.asc(),
|
||||
- )
|
||||
- .all()
|
||||
-)
|
||||
+result = session.query(models.Customer.id).filter(
|
||||
+ models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
+).order_by(models.Customer.id.asc()).all()
|
||||
+result = session.query(models.Customer.id).filter(
|
||||
+ models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
+).order_by(
|
||||
+ models.Customer.id.asc(),
|
||||
+).all()
|
||||
Ø = set()
|
||||
authors.łukasz.say_thanks()
|
||||
mapping = {
|
||||
@@ -328,13 +319,18 @@
|
||||
@@ -328,13 +329,18 @@
|
||||
):
|
||||
return True
|
||||
if (
|
||||
|
|
@ -355,7 +322,7 @@ last_call()
|
|||
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
|
||||
):
|
||||
return True
|
||||
@@ -342,7 +338,8 @@
|
||||
@@ -342,7 +348,8 @@
|
||||
~aaaaaaaaaaaaaaaa.a
|
||||
+ aaaaaaaaaaaaaaaa.b
|
||||
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
|
||||
|
|
@ -581,14 +548,24 @@ what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + se
|
|||
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
|
||||
vars_to_remove
|
||||
)
|
||||
result = session.query(models.Customer.id).filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
).order_by(models.Customer.id.asc()).all()
|
||||
result = session.query(models.Customer.id).filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
).order_by(
|
||||
models.Customer.id.asc(),
|
||||
).all()
|
||||
result = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
)
|
||||
.order_by(models.Customer.id.asc())
|
||||
.all()
|
||||
)
|
||||
result = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
)
|
||||
.order_by(
|
||||
models.Customer.id.asc(),
|
||||
)
|
||||
.all()
|
||||
)
|
||||
Ø = set()
|
||||
authors.łukasz.say_thanks()
|
||||
mapping = {
|
||||
|
|
|
|||
|
|
@ -287,7 +287,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
goes + here,
|
||||
andhere,
|
||||
@@ -80,38 +94,36 @@
|
||||
@@ -80,38 +94,42 @@
|
||||
|
||||
def import_as_names():
|
||||
# fmt: off
|
||||
|
|
@ -330,14 +330,19 @@ d={'a':1,
|
|||
- .filter(models.Customer.account_id == account_id,
|
||||
- models.Customer.email == email_address)\
|
||||
- .order_by(models.Customer.id.asc())\
|
||||
- .all()
|
||||
+ result = session.query(models.Customer.id).filter(
|
||||
+ models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
+ ).order_by(models.Customer.id.asc()).all()
|
||||
+ result = (
|
||||
+ session.query(models.Customer.id)
|
||||
+ .filter(
|
||||
+ models.Customer.account_id == account_id,
|
||||
+ models.Customer.email == email_address,
|
||||
+ )
|
||||
+ .order_by(models.Customer.id.asc())
|
||||
.all()
|
||||
+ )
|
||||
# fmt: on
|
||||
|
||||
|
||||
@@ -132,10 +144,10 @@
|
||||
@@ -132,10 +150,10 @@
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
|
@ -352,7 +357,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
# fmt: off
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
@@ -153,9 +165,7 @@
|
||||
@@ -153,9 +171,7 @@
|
||||
)
|
||||
)
|
||||
# fmt: off
|
||||
|
|
@ -363,7 +368,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
_type_comment_re = re.compile(
|
||||
r"""
|
||||
@@ -178,7 +188,7 @@
|
||||
@@ -178,7 +194,7 @@
|
||||
$
|
||||
""",
|
||||
# fmt: off
|
||||
|
|
@ -372,7 +377,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
)
|
||||
|
||||
@@ -216,8 +226,7 @@
|
||||
@@ -216,8 +232,7 @@
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||
)
|
||||
# fmt: off
|
||||
|
|
@ -512,9 +517,15 @@ def yield_expr():
|
|||
|
||||
def example(session):
|
||||
# fmt: off
|
||||
result = session.query(models.Customer.id).filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
).order_by(models.Customer.id.asc()).all()
|
||||
result = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == account_id,
|
||||
models.Customer.email == email_address,
|
||||
)
|
||||
.order_by(models.Customer.id.asc())
|
||||
.all()
|
||||
)
|
||||
# fmt: on
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ def __await__(): return (yield)
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -65,18 +65,14 @@
|
||||
@@ -65,6 +65,7 @@
|
||||
|
||||
def spaces2(result=_core.Value(None)):
|
||||
assert fut is self._read_fut, (fut, self._read_fut)
|
||||
|
|
@ -115,22 +115,6 @@ def __await__(): return (yield)
|
|||
|
||||
|
||||
def example(session):
|
||||
- result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
- models.Customer.account_id == account_id,
|
||||
- models.Customer.email == email_address,
|
||||
- )
|
||||
- .order_by(models.Customer.id.asc())
|
||||
- .all()
|
||||
- )
|
||||
+ result = session.query(models.Customer.id).filter(
|
||||
+ models.Customer.account_id == account_id,
|
||||
+ models.Customer.email == email_address,
|
||||
+ ).order_by(models.Customer.id.asc()).all()
|
||||
|
||||
|
||||
def long_lines():
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
|
@ -207,10 +191,15 @@ def spaces2(result=_core.Value(None)):
|
|||
|
||||
|
||||
def example(session):
|
||||
result = session.query(models.Customer.id).filter(
|
||||
models.Customer.account_id == account_id,
|
||||
models.Customer.email == email_address,
|
||||
).order_by(models.Customer.id.asc()).all()
|
||||
result = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == account_id,
|
||||
models.Customer.email == email_address,
|
||||
)
|
||||
.order_by(models.Customer.id.asc())
|
||||
.all()
|
||||
)
|
||||
|
||||
|
||||
def long_lines():
|
||||
|
|
|
|||
|
|
@ -0,0 +1,340 @@
|
|||
---
|
||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/call_chains.py
|
||||
---
|
||||
## Input
|
||||
```py
|
||||
# Test cases for call chains and optional parentheses, with and without fluent style
|
||||
|
||||
raise OsError("") from a.aaaaa(
|
||||
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
|
||||
).a(aaaa)
|
||||
|
||||
raise OsError(
|
||||
"sökdjffffsldkfjlhsakfjhalsökafhsöfdahsödfjösaaksjdllllllllllllll"
|
||||
) from a.aaaaa(
|
||||
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
|
||||
).a(
|
||||
aaaa
|
||||
)
|
||||
|
||||
a1 = Blog.objects.filter(entry__headline__contains="Lennon").filter(
|
||||
entry__pub_date__year=2008
|
||||
)
|
||||
|
||||
a2 = Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
).filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
|
||||
raise OsError("") from (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
)
|
||||
|
||||
raise OsError("sökdjffffsldkfjlhsakfjhalsökafhsöfdahsödfjösaaksjdllllllllllllll") from (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
)
|
||||
|
||||
# Break only after calls and indexing
|
||||
b1 = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
b2 = (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
)
|
||||
.limit_results[:10]
|
||||
.filter(
|
||||
entry__pub_date__month=10,
|
||||
)
|
||||
)
|
||||
|
||||
# Nested call chains
|
||||
c1 = (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
).filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
+ Blog.objects.filter(
|
||||
entry__headline__contains="McCartney",
|
||||
)
|
||||
.limit_results[:10]
|
||||
.filter(
|
||||
entry__pub_date__year=2010,
|
||||
)
|
||||
).all()
|
||||
|
||||
# Test different cases with trailing end of line comments:
|
||||
# * fluent style, fits: no parentheses -> ignore the expand_parent
|
||||
# * fluent style, doesn't fit: break all soft line breaks
|
||||
# * default, fits: no parentheses
|
||||
# * default, doesn't fit: parentheses but no soft line breaks
|
||||
|
||||
# Fits, either style
|
||||
d11 = x.e().e().e() #
|
||||
d12 = (x.e().e().e()) #
|
||||
d13 = (
|
||||
x.e() #
|
||||
.e()
|
||||
.e()
|
||||
)
|
||||
|
||||
# Doesn't fit, default
|
||||
d2 = (
|
||||
x.e().esadjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkfsdddd() #
|
||||
)
|
||||
|
||||
# Doesn't fit, fluent style
|
||||
d3 = (
|
||||
x.e() #
|
||||
.esadjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk()
|
||||
.esadjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk()
|
||||
)
|
||||
|
||||
# Don't drop the bin op parentheses
|
||||
e1 = (1 + 2).w().t()
|
||||
e2 = (1 + 2)().w().t()
|
||||
e3 = (1 + 2)[1].w().t()
|
||||
|
||||
# Treat preserved parentheses correctly
|
||||
f1 = (b().c()).d(1,)
|
||||
f2 = b().c().d(1,)
|
||||
f3 = (b).c().d(1,)
|
||||
f4 = (a)(b).c(1,)
|
||||
f5 = (a.b()).c(1,)
|
||||
|
||||
# Indent in the parentheses without breaking
|
||||
g1 = (
|
||||
queryset.distinct().order_by(field.name).values_list(field_name_flat_long_long=True)
|
||||
)
|
||||
|
||||
# Fluent style in subexpressions
|
||||
if (
|
||||
not a()
|
||||
.b()
|
||||
.cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc()
|
||||
):
|
||||
pass
|
||||
h2 = (
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
+ ccccccccccccccccccccccccc()
|
||||
.dddddddddddddddddddddd()
|
||||
.eeeeeeeeee()
|
||||
.ffffffffffffffffffffff()
|
||||
)
|
||||
|
||||
# Parentheses aren't allowed on statement level, don't use fluent style here
|
||||
if True:
|
||||
(alias).filter(content_typeold_content_type).update(
|
||||
content_typenew_contesadfasfdant_type
|
||||
)
|
||||
|
||||
zero(
|
||||
one,
|
||||
).two(
|
||||
three,
|
||||
).four(
|
||||
five,
|
||||
)
|
||||
|
||||
|
||||
```
|
||||
|
||||
## Output
|
||||
```py
|
||||
# Test cases for call chains and optional parentheses, with and without fluent style
|
||||
|
||||
raise OsError("") from a.aaaaa(
|
||||
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
|
||||
).a(aaaa)
|
||||
|
||||
raise OsError(
|
||||
"sökdjffffsldkfjlhsakfjhalsökafhsöfdahsödfjösaaksjdllllllllllllll"
|
||||
) from a.aaaaa(
|
||||
aksjdhflsakhdflkjsadlfajkslhfdkjsaldajlahflashdfljahlfksajlhfajfjfsaahflakjslhdfkjalhdskjfa
|
||||
).a(aaaa)
|
||||
|
||||
a1 = Blog.objects.filter(entry__headline__contains="Lennon").filter(
|
||||
entry__pub_date__year=2008
|
||||
)
|
||||
|
||||
a2 = Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
).filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
|
||||
raise OsError("") from (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
)
|
||||
|
||||
raise OsError("sökdjffffsldkfjlhsakfjhalsökafhsöfdahsödfjösaaksjdllllllllllllll") from (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
.filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
)
|
||||
|
||||
# Break only after calls and indexing
|
||||
b1 = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == account_id, models.Customer.email == email_address
|
||||
)
|
||||
.count()
|
||||
)
|
||||
|
||||
b2 = (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
)
|
||||
.limit_results[:10]
|
||||
.filter(
|
||||
entry__pub_date__month=10,
|
||||
)
|
||||
)
|
||||
|
||||
# Nested call chains
|
||||
c1 = (
|
||||
Blog.objects.filter(
|
||||
entry__headline__contains="Lennon",
|
||||
).filter(
|
||||
entry__pub_date__year=2008,
|
||||
)
|
||||
+ Blog.objects.filter(
|
||||
entry__headline__contains="McCartney",
|
||||
)
|
||||
.limit_results[:10]
|
||||
.filter(
|
||||
entry__pub_date__year=2010,
|
||||
)
|
||||
).all()
|
||||
|
||||
# Test different cases with trailing end of line comments:
|
||||
# * fluent style, fits: no parentheses -> ignore the expand_parent
|
||||
# * fluent style, doesn't fit: break all soft line breaks
|
||||
# * default, fits: no parentheses
|
||||
# * default, doesn't fit: parentheses but no soft line breaks
|
||||
|
||||
# Fits, either style
|
||||
d11 = x.e().e().e() #
|
||||
d12 = x.e().e().e() #
|
||||
d13 = (
|
||||
x.e() #
|
||||
.e()
|
||||
.e()
|
||||
)
|
||||
|
||||
# Doesn't fit, default
|
||||
d2 = x.e().esadjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkfsdddd() #
|
||||
|
||||
# Doesn't fit, fluent style
|
||||
d3 = (
|
||||
x.e() #
|
||||
.esadjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk()
|
||||
.esadjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk()
|
||||
)
|
||||
|
||||
# Don't drop the bin op parentheses
|
||||
e1 = (1 + 2).w().t()
|
||||
e2 = (1 + 2)().w().t()
|
||||
e3 = (1 + 2)[1].w().t()
|
||||
|
||||
# Treat preserved parentheses correctly
|
||||
f1 = (b().c()).d(
|
||||
1,
|
||||
)
|
||||
f2 = (
|
||||
b()
|
||||
.c()
|
||||
.d(
|
||||
1,
|
||||
)
|
||||
)
|
||||
f3 = (
|
||||
(b)
|
||||
.c()
|
||||
.d(
|
||||
1,
|
||||
)
|
||||
)
|
||||
f4 = (a)(b).c(
|
||||
1,
|
||||
)
|
||||
f5 = (a.b()).c(
|
||||
1,
|
||||
)
|
||||
|
||||
# Indent in the parentheses without breaking
|
||||
g1 = (
|
||||
queryset.distinct().order_by(field.name).values_list(field_name_flat_long_long=True)
|
||||
)
|
||||
|
||||
# Fluent style in subexpressions
|
||||
if (
|
||||
not a()
|
||||
.b()
|
||||
.cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc()
|
||||
):
|
||||
pass
|
||||
h2 = (
|
||||
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|
||||
+ ccccccccccccccccccccccccc()
|
||||
.dddddddddddddddddddddd()
|
||||
.eeeeeeeeee()
|
||||
.ffffffffffffffffffffff()
|
||||
)
|
||||
|
||||
# Parentheses aren't allowed on statement level, don't use fluent style here
|
||||
if True:
|
||||
(alias).filter(content_typeold_content_type).update(
|
||||
content_typenew_contesadfasfdant_type
|
||||
)
|
||||
|
||||
zero(
|
||||
one,
|
||||
).two(
|
||||
three,
|
||||
).four(
|
||||
five,
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
@ -143,10 +143,10 @@ a = Namespace()
|
|||
|
||||
|
||||
(
|
||||
a.
|
||||
a. # trailing dot comment
|
||||
# comment
|
||||
# in between
|
||||
b # trailing dot comment # trailing identifier comment
|
||||
b # trailing identifier comment
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -157,10 +157,10 @@ a.aaaaaaaaaaaaaaaaaaaaa.lllllllllllllllllllllllllllloooooooooong.chaaaaaaaaaaaaa
|
|||
# chain if and only if we need them, that is if there are own line comments inside
|
||||
# the chain.
|
||||
x1 = (
|
||||
a.b.
|
||||
a.b. # comment 2
|
||||
# comment 1
|
||||
# comment 3
|
||||
c.d # comment 2
|
||||
c.d
|
||||
)
|
||||
|
||||
x20 = a.b
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ f(
|
|||
hey_this_is_a_very_long_call=1, it_has_funny_attributes_asdf_asdf=1, too_long_for_the_line=1, really=True
|
||||
)
|
||||
|
||||
# TODO(konstin): Call chains/fluent interface (https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#call-chains)
|
||||
# Call chains/fluent interface (https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#call-chains)
|
||||
result = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
|
|
@ -178,11 +178,16 @@ f(
|
|||
really=True,
|
||||
)
|
||||
|
||||
# TODO(konstin): Call chains/fluent interface (https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#call-chains)
|
||||
result = session.query(models.Customer.id).filter(
|
||||
models.Customer.account_id == 10000,
|
||||
models.Customer.email == "user@example.org",
|
||||
).order_by(models.Customer.id.asc()).all()
|
||||
# Call chains/fluent interface (https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#call-chains)
|
||||
result = (
|
||||
session.query(models.Customer.id)
|
||||
.filter(
|
||||
models.Customer.account_id == 10000,
|
||||
models.Customer.email == "user@example.org",
|
||||
)
|
||||
.order_by(models.Customer.id.asc())
|
||||
.all()
|
||||
)
|
||||
# TODO(konstin): Black has this special case for comment placement where everything stays in one line
|
||||
f("aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa")
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue