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::expression::parentheses::{NeedsParentheses, OptionalParentheses};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use crate::expression::parentheses::{parenthesized, NeedsParentheses, OptionalParentheses};
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_python_ast::node::AnyNodeRef;
use rustpython_parser::ast::ExprDictComp;
@ -9,11 +13,33 @@ use rustpython_parser::ast::ExprDictComp;
pub struct 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!(
f,
[not_yet_implemented_custom_text(
"{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}"
[parenthesized(
"{",
&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, 2)
@@ -95,14 +98,11 @@
[(i**2) for i in (1, 2, 3)]
[(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: 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
@@ -101,7 +104,10 @@
{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
-}
+{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}
+{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}
+{NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
+ for (
+ k,
+ v,
+ ) in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
}
Python3 > Python2 > COBOL
Life is Life
call()
@@ -115,7 +115,7 @@
@@ -115,7 +121,7 @@
arg,
another,
kwarg="hey",
@ -345,7 +337,7 @@ last_call()
) # note: no trailing comma pre-3.6
call(*gidgets[:2])
call(a, *gidgets[:2])
@@ -152,13 +152,13 @@
@@ -152,13 +158,13 @@
slice[0:1]
slice[0:1:2]
slice[:]
@ -362,7 +354,7 @@ last_call()
numpy[0, :]
numpy[:, i]
numpy[0, :2]
@@ -172,7 +172,7 @@
@@ -172,7 +178,7 @@
numpy[1 : c + 1, c]
numpy[-(c + 1) :, d]
numpy[:, l[-2]]
@ -371,7 +363,7 @@ last_call()
numpy[np.newaxis, :]
(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}
@@ -181,10 +181,10 @@
@@ -181,10 +187,10 @@
(SomeName)
SomeName
(Good, Bad, Ugly)
@ -386,7 +378,7 @@ last_call()
(*starred,)
{
"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(
vars_to_remove
)
@ -419,7 +411,7 @@ last_call()
Ø = set()
authors.łukasz.say_thanks()
mapping = {
@@ -237,10 +227,10 @@
@@ -237,10 +233,10 @@
def gen():
@ -434,22 +426,16 @@ last_call()
async def f():
@@ -248,8 +238,12 @@
@@ -249,7 +245,7 @@
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(
+ **{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)
assert not Test, "Short message"
assert this is ComplexTest and not requirements.fit_in_a_single_line(
force=False
@@ -259,7 +253,7 @@
@@ -259,7 +255,7 @@
...
for y in ():
...
@ -458,7 +444,7 @@ last_call()
...
for i in call():
...
@@ -328,13 +322,18 @@
@@ -328,13 +324,18 @@
):
return True
if (
@ -480,7 +466,7 @@ last_call()
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
):
return True
@@ -342,7 +341,8 @@
@@ -342,7 +343,8 @@
~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b
- 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, "a"), (2, "b"), (3, "c"))]
[((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}
{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}
{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}
{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
}
Python3 > Python2 > COBOL
Life is Life
call()
@ -735,11 +727,7 @@ async def f():
print(*[] or [1])
print(
**{1: 3}
if False
else {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
)
print(**{1: 3} if False else {x: x for x in range(3)})
print(*lambda NOT_YET_IMPLEMENTED_lambda: True)
assert not Test, "Short message"
assert this is ComplexTest and not requirements.fit_in_a_single_line(

View file

@ -84,15 +84,6 @@ return np.divide(
f = f() ** 5
g = a.b**c.d
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 @@
b = 5.0 ** f()
c = -(5.0**2.0)
@ -102,15 +93,6 @@ return np.divide(
f = f() ** 5.0
g = a.b**c.d
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
@ -144,7 +126,7 @@ l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2**63], [1, 2**63])]
n = count <= 10**5
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)]
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])]
n = count <= 10**5.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)]

View file

@ -96,44 +96,6 @@ def example8():
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
@ -185,11 +147,35 @@ def example5():
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():
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():

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
}
```