Format DictComp expression (#5771)

## Summary

Format `DictComp` like `ListComp` from #5600. It's not 100%, but I
figured maybe it's worth starting to explore.

## Test Plan

Added ruff fixture based on `ListComp`'s.
This commit is contained in:
Chris Pryer 2023-07-15 12:35:23 -04:00 committed by GitHub
parent 3cda89ecaf
commit fa4855e6fe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 247 additions and 109 deletions

View file

@ -0,0 +1,45 @@
{i: i for i in []}
{i: i for i in [1,]}
{
a: a # a
for # for
c # c
in # in
e # e
}
{
# above a
a: a # a
# above for
for # for
# above c
c # c
# above in
in # in
# above e
e # e
# above if
if # if
# above f
f # f
# above if2
if # if2
# above g
g # g
}
{
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + [dddddddddddddddddd, eeeeeeeeeeeeeeeeeee]: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
for
ccccccccccccccccccccccccccccccccccccccc,
ddddddddddddddddddd, [eeeeeeeeeeeeeeeeeeeeee, fffffffffffffffffffffffff]
in
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffggggggggggggggggggggghhhhhhhhhhhhhhothermoreeand_even_moreddddddddddddddddddddd
if
fffffffffffffffffffffffffffffffffffffffffff < gggggggggggggggggggggggggggggggggggggggggggggg < hhhhhhhhhhhhhhhhhhhhhhhhhh
if
gggggggggggggggggggggggggggggggggggggggggggg
}

View file

@ -1,6 +1,10 @@
use crate::context::PyFormatContext; use crate::context::PyFormatContext;
use crate::expression::parentheses::{NeedsParentheses, OptionalParentheses}; use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; use crate::AsFormat;
use crate::{FormatNodeRule, FormattedIterExt, PyFormatter};
use ruff_formatter::prelude::{
format_args, format_with, group, soft_line_break_or_space, space, text,
};
use ruff_formatter::{write, Buffer, FormatResult}; use ruff_formatter::{write, Buffer, FormatResult};
use ruff_python_ast::node::AnyNodeRef; use ruff_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprDictComp; use rustpython_parser::ast::ExprDictComp;
@ -9,11 +13,33 @@ use rustpython_parser::ast::ExprDictComp;
pub struct FormatExprDictComp; pub struct FormatExprDictComp;
impl FormatNodeRule<ExprDictComp> for FormatExprDictComp { impl FormatNodeRule<ExprDictComp> for FormatExprDictComp {
fn fmt_fields(&self, _item: &ExprDictComp, f: &mut PyFormatter) -> FormatResult<()> { fn fmt_fields(&self, item: &ExprDictComp, f: &mut PyFormatter) -> FormatResult<()> {
let ExprDictComp {
range: _,
key,
value,
generators,
} = item;
let joined = format_with(|f| {
f.join_with(soft_line_break_or_space())
.entries(generators.iter().formatted())
.finish()
});
write!( write!(
f, f,
[not_yet_implemented_custom_text( [parenthesized(
"{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}" "{",
&format_args!(
group(&key.format()),
text(":"),
space(),
value.format(),
soft_line_break_or_space(),
group(&joined)
),
"}"
)] )]
) )
} }

View file

@ -316,27 +316,19 @@ last_call()
() ()
(1,) (1,)
(1, 2) (1, 2)
@@ -95,14 +98,11 @@ @@ -101,7 +104,10 @@
[(i**2) for i in (1, 2, 3)] {a: b * -2 for a, b in dictionary.items()}
[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))] {
[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)] k: v
-{i: 0 for i in (1, 2, 3)}
-{i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
-{a: b * 2 for a, b in dictionary.items()}
-{a: b * -2 for a, b in dictionary.items()}
-{
- k: v
- for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension - for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
-} + for (
+{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} + k,
+{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} + v,
+{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} + ) in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
+{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} }
+{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
Python3 > Python2 > COBOL Python3 > Python2 > COBOL
Life is Life Life is Life
call() @@ -115,7 +121,7 @@
@@ -115,7 +115,7 @@
arg, arg,
another, another,
kwarg="hey", kwarg="hey",
@ -345,7 +337,7 @@ last_call()
) # note: no trailing comma pre-3.6 ) # note: no trailing comma pre-3.6
call(*gidgets[:2]) call(*gidgets[:2])
call(a, *gidgets[:2]) call(a, *gidgets[:2])
@@ -152,13 +152,13 @@ @@ -152,13 +158,13 @@
slice[0:1] slice[0:1]
slice[0:1:2] slice[0:1:2]
slice[:] slice[:]
@ -362,7 +354,7 @@ last_call()
numpy[0, :] numpy[0, :]
numpy[:, i] numpy[:, i]
numpy[0, :2] numpy[0, :2]
@@ -172,7 +172,7 @@ @@ -172,7 +178,7 @@
numpy[1 : c + 1, c] numpy[1 : c + 1, c]
numpy[-(c + 1) :, d] numpy[-(c + 1) :, d]
numpy[:, l[-2]] numpy[:, l[-2]]
@ -371,7 +363,7 @@ last_call()
numpy[np.newaxis, :] numpy[np.newaxis, :]
(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None) (str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None)
{"2.7": dead, "3.7": long_live or die_hard} {"2.7": dead, "3.7": long_live or die_hard}
@@ -181,10 +181,10 @@ @@ -181,10 +187,10 @@
(SomeName) (SomeName)
SomeName SomeName
(Good, Bad, Ugly) (Good, Bad, Ugly)
@ -386,7 +378,7 @@ last_call()
(*starred,) (*starred,)
{ {
"id": "1", "id": "1",
@@ -208,24 +208,14 @@ @@ -208,24 +214,14 @@
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set( what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
vars_to_remove vars_to_remove
) )
@ -419,7 +411,7 @@ last_call()
Ø = set() Ø = set()
authors.łukasz.say_thanks() authors.łukasz.say_thanks()
mapping = { mapping = {
@@ -237,10 +227,10 @@ @@ -237,10 +233,10 @@
def gen(): def gen():
@ -434,22 +426,16 @@ last_call()
async def f(): async def f():
@@ -248,8 +238,12 @@ @@ -249,7 +245,7 @@
print(*[] or [1]) print(*[] or [1])
-print(**{1: 3} if False else {x: x for x in range(3)}) print(**{1: 3} if False else {x: x for x in range(3)})
-print(*lambda x: x) -print(*lambda x: x)
+print(
+ **{1: 3}
+ if False
+ else {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
+)
+print(*lambda NOT_YET_IMPLEMENTED_lambda: True) +print(*lambda NOT_YET_IMPLEMENTED_lambda: True)
assert not Test, "Short message" assert not Test, "Short message"
assert this is ComplexTest and not requirements.fit_in_a_single_line( assert this is ComplexTest and not requirements.fit_in_a_single_line(
force=False force=False
@@ -259,7 +253,7 @@ @@ -259,7 +255,7 @@
... ...
for y in (): for y in ():
... ...
@ -458,7 +444,7 @@ last_call()
... ...
for i in call(): for i in call():
... ...
@@ -328,13 +322,18 @@ @@ -328,13 +324,18 @@
): ):
return True return True
if ( if (
@ -480,7 +466,7 @@ last_call()
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
): ):
return True return True
@@ -342,7 +341,8 @@ @@ -342,7 +343,8 @@
~aaaaaaaaaaaaaaaa.a ~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b + aaaaaaaaaaaaaaaa.b
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
@ -595,11 +581,17 @@ str or None if (1 if True else 2) else str or bytes or None
[(i**2) for i in (1, 2, 3)] [(i**2) for i in (1, 2, 3)]
[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))] [(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))]
[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)] [((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} {i: 0 for i in (1, 2, 3)}
{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} {i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} {a: b * 2 for a, b in dictionary.items()}
{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} {a: b * -2 for a, b in dictionary.items()}
{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} {
k: v
for (
k,
v,
) in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
}
Python3 > Python2 > COBOL Python3 > Python2 > COBOL
Life is Life Life is Life
call() call()
@ -735,11 +727,7 @@ async def f():
print(*[] or [1]) print(*[] or [1])
print( print(**{1: 3} if False else {x: x for x in range(3)})
**{1: 3}
if False
else {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
)
print(*lambda NOT_YET_IMPLEMENTED_lambda: True) print(*lambda NOT_YET_IMPLEMENTED_lambda: True)
assert not Test, "Short message" assert not Test, "Short message"
assert this is ComplexTest and not requirements.fit_in_a_single_line( assert this is ComplexTest and not requirements.fit_in_a_single_line(

View file

@ -84,15 +84,6 @@ return np.divide(
f = f() ** 5 f = f() ** 5
g = a.b**c.d g = a.b**c.d
h = 5 ** funcs.f() h = 5 ** funcs.f()
@@ -26,7 +26,7 @@
m = [([2**63], [1, 2**63])]
n = count <= 10**5
o = settings(max_examples=10**6)
-p = {(k, k**2): v**2 for k, v in pairs}
+p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
q = [10**i for i in range(6)]
r = x**y
@@ -34,7 +34,7 @@ @@ -34,7 +34,7 @@
b = 5.0 ** f() b = 5.0 ** f()
c = -(5.0**2.0) c = -(5.0**2.0)
@ -102,15 +93,6 @@ return np.divide(
f = f() ** 5.0 f = f() ** 5.0
g = a.b**c.d g = a.b**c.d
h = 5.0 ** funcs.f() h = 5.0 ** funcs.f()
@@ -45,7 +45,7 @@
m = [([2.0**63.0], [1.0, 2**63.0])]
n = count <= 10**5.0
o = settings(max_examples=10**6.0)
-p = {(k, k**2): v**2.0 for k, v in pairs}
+p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
q = [10.5**i for i in range(6)]
``` ```
## Ruff Output ## Ruff Output
@ -144,7 +126,7 @@ l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2**63], [1, 2**63])] m = [([2**63], [1, 2**63])]
n = count <= 10**5 n = count <= 10**5
o = settings(max_examples=10**6) o = settings(max_examples=10**6)
p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} 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
@ -163,7 +145,7 @@ l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2.0**63.0], [1.0, 2**63.0])] m = [([2.0**63.0], [1.0, 2**63.0])]
n = count <= 10**5.0 n = count <= 10**5.0
o = settings(max_examples=10**6.0) o = settings(max_examples=10**6.0)
p = {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} 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)]

View file

@ -96,44 +96,6 @@ def example8():
def example4(): def example4():
@@ -50,35 +44,11 @@
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 {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
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 {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
def example8():
``` ```
## Ruff Output ## Ruff Output
@ -185,11 +147,35 @@ def example5():
def example6(): def example6():
return {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} 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 {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict} 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():

View file

@ -0,0 +1,111 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/dict_comp.py
---
## Input
```py
{i: i for i in []}
{i: i for i in [1,]}
{
a: a # a
for # for
c # c
in # in
e # e
}
{
# above a
a: a # a
# above for
for # for
# above c
c # c
# above in
in # in
# above e
e # e
# above if
if # if
# above f
f # f
# above if2
if # if2
# above g
g # g
}
{
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + [dddddddddddddddddd, eeeeeeeeeeeeeeeeeee]: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
for
ccccccccccccccccccccccccccccccccccccccc,
ddddddddddddddddddd, [eeeeeeeeeeeeeeeeeeeeee, fffffffffffffffffffffffff]
in
eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffggggggggggggggggggggghhhhhhhhhhhhhhothermoreeand_even_moreddddddddddddddddddddd
if
fffffffffffffffffffffffffffffffffffffffffff < gggggggggggggggggggggggggggggggggggggggggggggg < hhhhhhhhhhhhhhhhhhhhhhhhhh
if
gggggggggggggggggggggggggggggggggggggggggggg
}
```
## Output
```py
{i: i for i in []}
{
i: i
for i in [
1,
]
}
{
a: a # a
for c in e # for # c # in # e
}
{
# above a
a: a # a
# above for
for # for
# above c
c # c
# above in
in # in
# above e
e # e
# above if
if # if
# above f
f # f
# above if2
if # if2
# above g
g # g
}
{
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
+ [
dddddddddddddddddd,
eeeeeeeeeeeeeeeeeee,
]: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
for (
ccccccccccccccccccccccccccccccccccccccc,
ddddddddddddddddddd,
[eeeeeeeeeeeeeeeeeeeeee, fffffffffffffffffffffffff],
) in eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffffffffffffffffffffffffggggggggggggggggggggghhhhhhhhhhhhhhothermoreeand_even_moreddddddddddddddddddddd
if fffffffffffffffffffffffffffffffffffffffffff
< gggggggggggggggggggggggggggggggggggggggggggggg
< hhhhhhhhhhhhhhhhhhhhhhhhhh
if gggggggggggggggggggggggggggggggggggggggggggg
}
```