Format ExprIfExp (ternary operator) (#5597)

## Summary

Format `ExprIfExp`, also known as the ternary operator or inline `if`.
It can look like
```python
a1 = 1 if True else 2
```
but also
```python
b1 = (
    # We return "a" ...
    "a" # that's our True value
    # ... if this condition matches ...
    if True # that's our test
    # ... otherwise we return "b§
    else "b" # that's our False value
)
```

This also fixes a visitor order bug.

The jaccard index on django goes from 0.911 to 0.915.

## Test Plan

I added fixtures without and with comments in strange places.
This commit is contained in:
konsti 2023-07-07 21:11:52 +02:00 committed by GitHub
parent 0f9d7283e7
commit 0b9af031fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 328 additions and 212 deletions

View file

@ -0,0 +1,33 @@
a1 = 1 if True else 2
a2 = "this is a very long text that will make the group break to check that parentheses are added" if True else 2
# These comment should be kept in place
b1 = (
# We return "a" ...
"a" # that's our True value
# ... if this condition matches ...
if True # that's our test
# ... otherwise we return "b"
else "b" # that's our False value
)
# These only need to be stable, bonus is we also keep the order
c1 = (
"a" # 1
if # 2
True # 3
else # 4
"b" # 5
)
c2 = (
"a" # 1
# 2
if # 3
# 4
True # 5
# 6
else # 7
# 8
"b" # 9
)

View file

@ -1,8 +1,8 @@
use std::cmp::Ordering;
use ruff_text_size::TextRange;
use ruff_text_size::{TextLen, TextRange};
use rustpython_parser::ast;
use rustpython_parser::ast::{Expr, ExprSlice, Ranged};
use rustpython_parser::ast::{Expr, ExprIfExp, ExprSlice, Ranged};
use ruff_python_ast::node::{AnyNodeRef, AstNode};
use ruff_python_ast::source_code::Locator;
@ -14,7 +14,9 @@ use crate::expression::expr_slice::{assign_comment_in_slice, ExprSliceCommentSec
use crate::other::arguments::{
assign_argument_separator_comment_placement, find_argument_separators,
};
use crate::trivia::{first_non_trivia_token_rev, SimpleTokenizer, Token, TokenKind};
use crate::trivia::{
first_non_trivia_token, first_non_trivia_token_rev, SimpleTokenizer, Token, TokenKind,
};
/// Implements the custom comment placement logic.
pub(super) fn place_comment<'a>(
@ -37,6 +39,7 @@ pub(super) fn place_comment<'a>(
handle_dict_unpacking_comment,
handle_slice_comments,
handle_attribute_comment,
handle_expr_if_comment,
];
for handler in HANDLERS {
comment = match handler(comment, locator) {
@ -1154,6 +1157,82 @@ fn handle_attribute_comment<'a>(
}
}
/// Assign comments between `if` and `test` and `else` and `orelse` as leading to the respective
/// node.
///
/// ```python
/// x = (
/// "a"
/// if # leading comment of `True`
/// True
/// else # leading comment of `"b"`
/// "b"
/// )
/// ```
///
/// This placement ensures comments remain in their previous order. This an edge case that only
/// happens if the comments are in a weird position but it also doesn't hurt handling it.
fn handle_expr_if_comment<'a>(
comment: DecoratedComment<'a>,
locator: &Locator,
) -> CommentPlacement<'a> {
let Some(expr_if) = comment.enclosing_node().expr_if_exp() else {
return CommentPlacement::Default(comment);
};
let ExprIfExp {
range: _,
test,
body,
orelse,
} = expr_if;
if comment.line_position().is_own_line() {
return CommentPlacement::Default(comment);
}
// Find the if and the else
let if_token =
find_only_token_str_in_range(TextRange::new(body.end(), test.start()), locator, "if");
let else_token =
find_only_token_str_in_range(TextRange::new(test.end(), orelse.start()), locator, "else");
// Between `if` and `test`
if if_token.range.start() < comment.slice().start() && comment.slice().start() < test.start() {
return CommentPlacement::leading(test.as_ref().into(), comment);
}
// Between `else` and `orelse`
if else_token.range.start() < comment.slice().start()
&& comment.slice().start() < orelse.start()
{
return CommentPlacement::leading(orelse.as_ref().into(), comment);
}
CommentPlacement::Default(comment)
}
/// Looks for a multi char token in the range that contains no other tokens. `SimpleTokenizer` only
/// works with single char tokens so we check that we have the right token by string comparison.
fn find_only_token_str_in_range(range: TextRange, locator: &Locator, token_str: &str) -> Token {
let token =
first_non_trivia_token(range.start(), locator.contents()).expect("Expected a token");
debug_assert!(
locator.after(token.start()).starts_with(token_str),
"expected a `{token_str}` token",
);
debug_assert!(
SimpleTokenizer::new(
locator.contents(),
TextRange::new(token.start() + token_str.text_len(), range.end())
)
.skip_trivia()
.next()
.is_none(),
"Didn't expect any other token"
);
token
}
/// Returns `true` if `right` is `Some` and `left` and `right` are referentially equal.
fn are_same_optional<'a, T>(left: AnyNodeRef, right: Option<T>) -> bool
where

View file

@ -1,21 +1,42 @@
use crate::comments::Comments;
use crate::comments::{leading_comments, Comments};
use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
};
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult};
use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::prelude::{group, soft_line_break_or_space, space, text};
use ruff_formatter::{format_args, write, Buffer, FormatResult};
use rustpython_parser::ast::ExprIfExp;
#[derive(Default)]
pub struct FormatExprIfExp;
impl FormatNodeRule<ExprIfExp> for FormatExprIfExp {
fn fmt_fields(&self, _item: &ExprIfExp, f: &mut PyFormatter) -> FormatResult<()> {
fn fmt_fields(&self, item: &ExprIfExp, f: &mut PyFormatter) -> FormatResult<()> {
let ExprIfExp {
range: _,
test,
body,
orelse,
} = item;
let comments = f.context().comments().clone();
// We place `if test` and `else orelse` on a single line, so the `test` and `orelse` leading
// comments go on the line before the `if` or `else` instead of directly ahead `test` or
// `orelse`
write!(
f,
[not_yet_implemented_custom_text(
"NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false"
)]
[group(&format_args![
body.format(),
soft_line_break_or_space(),
leading_comments(comments.leading_comments(test.as_ref())),
text("if"),
space(),
test.format(),
soft_line_break_or_space(),
leading_comments(comments.leading_comments(orelse.as_ref())),
text("else"),
space(),
orelse.format()
])]
)
}
}

View file

@ -79,7 +79,7 @@ def something():
```diff
--- Black
+++ Ruff
@@ -1,90 +1,50 @@
@@ -1,20 +1,16 @@
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
- bar=(
@ -87,7 +87,9 @@ def something():
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
- ),
+ bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
+ bar=some_long_value_name_foo_bar_baz
+ if some_boolean_variable
+ else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
@ -98,33 +100,13 @@ def something():
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
- ),
+ bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
+ bar=some_long_value_name_foo_bar_baz
+ if some_boolean_variable
+ else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
- bar=a if foo else b,
+ bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
baz="hello, this is a another value",
)
-imploding_line = 1 if 1 + 1 == 2 else 0
+imploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
-exploding_line = (
- "hello this is a slightly long string"
- if some_long_value_name_foo_bar_baz
- else "this one is a little shorter"
-)
+exploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
positional_argument_test(
- some_long_value_name_foo_bar_baz
- if some_boolean_variable
- else some_fallback_value_foo_bar_baz
+ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
)
@@ -40,11 +36,9 @@
def weird_default_argument(
@ -133,21 +115,15 @@ def something():
- if SOME_CONSTANT
- else some_fallback_value_foo_bar_baz
- ),
+ x=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
+ x=some_long_value_name_foo_bar_baz
+ if SOME_CONSTANT
+ else some_fallback_value_foo_bar_baz,
):
pass
-nested = (
- "hello this is a slightly long string"
- if (
- some_long_value_name_foo_bar_baz
- if nesting_test_expressions
- else some_fallback_value_foo_bar_baz
- )
- else "this one is a little shorter"
-)
+nested = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
@@ -59,26 +53,14 @@
else "this one is a little shorter"
)
-generator_expression = (
- (
@ -174,13 +150,6 @@ def something():
)
def something():
clone._iterable_class = (
- NamedValuesListIterable
- if named
- else FlatValuesListIterable if flat else ValuesListIterable
+ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
)
```
## Ruff Output
@ -188,38 +157,58 @@ def something():
```py
long_kwargs_single_line = my_function(
foo="test, this is a sample value",
bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
bar=some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
multiline_kwargs_indented = my_function(
foo="test, this is a sample value",
bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
bar=some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz,
baz="hello, this is a another value",
)
imploding_kwargs = my_function(
foo="test, this is a sample value",
bar=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
bar=a if foo else b,
baz="hello, this is a another value",
)
imploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
imploding_line = 1 if 1 + 1 == 2 else 0
exploding_line = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
exploding_line = (
"hello this is a slightly long string"
if some_long_value_name_foo_bar_baz
else "this one is a little shorter"
)
positional_argument_test(
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
some_long_value_name_foo_bar_baz
if some_boolean_variable
else some_fallback_value_foo_bar_baz
)
def weird_default_argument(
x=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
x=some_long_value_name_foo_bar_baz
if SOME_CONSTANT
else some_fallback_value_foo_bar_baz,
):
pass
nested = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
nested = (
"hello this is a slightly long string"
if (
some_long_value_name_foo_bar_baz
if nesting_test_expressions
else some_fallback_value_foo_bar_baz
)
else "this one is a little shorter"
)
generator_expression = (NOT_YET_IMPLEMENTED_generator_key for NOT_YET_IMPLEMENTED_generator_key in [])
@ -234,7 +223,9 @@ def limit_offset_sql(self, low_mark, high_mark):
def something():
clone._iterable_class = (
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
NamedValuesListIterable
if named
else FlatValuesListIterable if flat else ValuesListIterable
)
```

View file

@ -274,7 +274,7 @@ last_call()
Name
None
True
@@ -31,33 +31,39 @@
@@ -31,18 +31,15 @@
-1
~int and not v1 ^ 123 + v2 | True
(~int) and (not ((v1 ^ (123 + v2)) | True))
@ -291,16 +291,6 @@ last_call()
- "port1": port1_resource,
- "port2": port2_resource,
-}[port_id]
-1 if True else 2
-str or None if True else str or bytes or None
-(str or None) if True else (str or bytes or None)
-str or None if (1 if True else 2) else str or bytes or None
-(str or None) if (1 if True else 2) else (str or bytes or None)
-(
- (super_long_variable_name or None)
- if (1 if super_long_test_name else 2)
- else (str or bytes or None)
-)
+lambda x: True
+lambda x: True
+lambda x: True
@ -308,25 +298,14 @@ last_call()
+lambda x: True
+manylambdas = lambda x: True
+foo = lambda x: True
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
+(NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false)
{"2.7": dead, "3.7": (long_live or die_hard)}
1 if True else 2
str or None if True else str or bytes or None
(str or None) if True else (str or bytes or None)
@@ -57,7 +54,13 @@
{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
{**a, **b, **c}
-{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
-({"a": "b"}, (True or False), (+value), "string", b"bytes") or None
+{
+ "2.7",
+ "3.6",
+ "3.7",
+ "3.8",
+ "3.9",
+ (NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false),
+}
+(
+ {"a": "b"},
+ (True or False),
@ -337,7 +316,7 @@ last_call()
()
(1,)
(1, 2)
@@ -69,40 +75,37 @@
@@ -69,40 +72,37 @@
2,
3,
]
@ -396,7 +375,7 @@ last_call()
Python3 > Python2 > COBOL
Life is Life
call()
@@ -115,10 +118,10 @@
@@ -115,10 +115,10 @@
arg,
another,
kwarg="hey",
@ -410,7 +389,7 @@ last_call()
call(**self.screen_kwargs)
call(b, **self.screen_kwargs)
lukasz.langa.pl
@@ -131,34 +134,28 @@
@@ -131,34 +131,28 @@
tuple[str, ...]
tuple[str, int, float, dict[str, int]]
tuple[
@ -458,26 +437,16 @@ last_call()
numpy[0, :]
numpy[:, i]
numpy[0, :2]
@@ -172,20 +169,27 @@
@@ -172,7 +166,7 @@
numpy[1 : c + 1, c]
numpy[-(c + 1) :, d]
numpy[:, l[-2]]
-numpy[:, ::-1]
+numpy[:, :: -1]
numpy[np.newaxis, :]
-(str or None) if (sys.version_info[0] > (3,)) else (str or bytes or None)
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
(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", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
+{
+ "2.7",
+ "3.6",
+ "3.7",
+ "3.8",
+ "3.9",
+ NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
+}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
@@ -181,11 +175,11 @@
(SomeName)
SomeName
(Good, Bad, Ugly)
@ -494,7 +463,7 @@ last_call()
{
"id": "1",
"type": "type",
@@ -200,32 +204,22 @@
@@ -200,32 +194,22 @@
c = 1
d = (1,) + a + (2,)
e = (1,).count(1)
@ -537,7 +506,7 @@ last_call()
Ø = set()
authors.łukasz.say_thanks()
mapping = {
@@ -237,29 +231,29 @@
@@ -237,29 +221,33 @@
def gen():
@ -564,7 +533,11 @@ last_call()
-), "Short message"
-assert parens is TooMany
+print(*NOT_YET_IMPLEMENTED_ExprStarred)
+print(**NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false)
+print(
+ **{1: 3}
+ if False
+ else {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
+)
+print(*NOT_YET_IMPLEMENTED_ExprStarred)
+NOT_YET_IMPLEMENTED_StmtAssert
+NOT_YET_IMPLEMENTED_StmtAssert
@ -580,7 +553,7 @@ last_call()
...
for i in call():
...
@@ -328,13 +322,18 @@
@@ -328,13 +316,18 @@
):
return True
if (
@ -602,7 +575,7 @@ last_call()
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
):
return True
@@ -342,7 +341,8 @@
@@ -342,7 +335,8 @@
~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
@ -659,23 +632,20 @@ lambda x: True
lambda x: True
manylambdas = lambda x: True
foo = lambda x: True
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
(NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false)
1 if True else 2
str or None if True else str or bytes or None
(str or None) if True else (str or bytes or None)
str or None if (1 if True else 2) else str or bytes or None
(str or None) if (1 if True else 2) else (str or bytes or None)
(
(super_long_variable_name or None)
if (1 if super_long_test_name else 2)
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), **{"3.6": verygood}}
{**a, **b, **c}
{
"2.7",
"3.6",
"3.7",
"3.8",
"3.9",
(NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false),
}
{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
(
{"a": "b"},
(True or False),
@ -790,16 +760,9 @@ numpy[-(c + 1) :, d]
numpy[:, l[-2]]
numpy[:, :: -1]
numpy[np.newaxis, :]
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
(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",
"3.6",
"3.7",
"3.8",
"3.9",
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
}
{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
(SomeName)
SomeName
@ -861,7 +824,11 @@ async def f():
print(*NOT_YET_IMPLEMENTED_ExprStarred)
print(**NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false)
print(
**{1: 3}
if False
else {NOT_IMPLEMENTED_dict_key: NOT_IMPLEMENTED_dict_value for key, value in NOT_IMPLEMENTED_dict}
)
print(*NOT_YET_IMPLEMENTED_ExprStarred)
NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert

View file

@ -211,7 +211,7 @@ d={'a':1,
# Comment 1
# Comment 2
@@ -17,30 +16,54 @@
@@ -17,30 +16,44 @@
# fmt: off
def func_no_args():
@ -268,35 +268,15 @@ d={'a':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)))
- assert task._cancel_stack[: len(old_stack)] == old_stack
+def spaces(
+ a=1,
+ b=(),
+ c=[],
+ d={},
+ e=True,
+ f=-1,
+ g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
+ h="",
+ i=r"",
+):
+ offset = attr.ib(default=attr.Factory(lambda x: True))
+ NOT_YET_IMPLEMENTED_StmtAssert
def spaces_types(
@@ -50,7 +73,7 @@
d: dict = {},
e: bool = True,
f: int = -1,
- g: int = 1 if False else 2,
+ g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
h: str = "",
i: str = r"",
):
@@ -63,55 +86,54 @@
@@ -63,55 +76,54 @@
something = {
# fmt: off
@ -371,7 +351,7 @@ d={'a':1,
# fmt: on
@@ -132,10 +154,10 @@
@@ -132,10 +144,10 @@
"""Another known limitation."""
# fmt: on
# fmt: off
@ -386,7 +366,7 @@ d={'a':1,
# fmt: on
# fmt: off
# ...but comments still get reformatted even though they should not be
@@ -153,9 +175,7 @@
@@ -153,9 +165,7 @@
)
)
# fmt: off
@ -397,7 +377,7 @@ d={'a':1,
# fmt: on
_type_comment_re = re.compile(
r"""
@@ -178,7 +198,7 @@
@@ -178,7 +188,7 @@
$
""",
# fmt: off
@ -406,7 +386,7 @@ d={'a':1,
# fmt: on
)
@@ -216,8 +236,7 @@
@@ -216,8 +226,7 @@
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
)
# fmt: off
@ -476,17 +456,7 @@ def function_signature_stress_test(
# fmt: on
def spaces(
a=1,
b=(),
c=[],
d={},
e=True,
f=-1,
g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
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 x: True))
NOT_YET_IMPLEMENTED_StmtAssert
@ -498,7 +468,7 @@ def spaces_types(
d: dict = {},
e: bool = True,
f: int = -1,
g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
g: int = 1 if False else 2,
h: str = "",
i: str = r"",
):

View file

@ -126,7 +126,7 @@ def __await__(): return (yield)
if False:
...
for i in range(10):
@@ -41,12 +40,22 @@
@@ -41,12 +40,12 @@
debug: bool = False,
**kwargs,
) -> str:
@ -134,35 +134,15 @@ def __await__(): return (yield)
+ return text[number : -1]
-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(10000, 200000)))
- assert task._cancel_stack[: len(old_stack)] == old_stack
+def spaces(
+ a=1,
+ b=(),
+ c=[],
+ d={},
+ e=True,
+ f=-1,
+ g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
+ h="",
+ i=r"",
+):
+ offset = attr.ib(default=attr.Factory(lambda x: True))
+ NOT_YET_IMPLEMENTED_StmtAssert
def spaces_types(
@@ -56,7 +65,7 @@
d: dict = {},
e: bool = True,
f: int = -1,
- g: int = 1 if False else 2,
+ g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
h: str = "",
i: str = r"",
):
@@ -64,19 +73,17 @@
@@ -64,19 +63,17 @@
def spaces2(result=_core.Value(None)):
@ -190,7 +170,7 @@ def __await__(): return (yield)
def long_lines():
@@ -135,14 +142,8 @@
@@ -135,14 +132,8 @@
a,
**kwargs,
) -> A:
@ -257,17 +237,7 @@ def function_signature_stress_test(
return text[number : -1]
def spaces(
a=1,
b=(),
c=[],
d={},
e=True,
f=-1,
g=NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
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 x: True))
NOT_YET_IMPLEMENTED_StmtAssert
@ -279,7 +249,7 @@ def spaces_types(
d: dict = {},
e: bool = True,
f: int = -1,
g: int = NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false,
g: int = 1 if False else 2,
h: str = "",
i: str = r"",
):

View file

@ -0,0 +1,84 @@
---
source: crates/ruff_python_formatter/tests/fixtures.rs
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/if.py
---
## Input
```py
a1 = 1 if True else 2
a2 = "this is a very long text that will make the group break to check that parentheses are added" if True else 2
# These comment should be kept in place
b1 = (
# We return "a" ...
"a" # that's our True value
# ... if this condition matches ...
if True # that's our test
# ... otherwise we return "b"
else "b" # that's our False value
)
# These only need to be stable, bonus is we also keep the order
c1 = (
"a" # 1
if # 2
True # 3
else # 4
"b" # 5
)
c2 = (
"a" # 1
# 2
if # 3
# 4
True # 5
# 6
else # 7
# 8
"b" # 9
)
```
## Output
```py
a1 = 1 if True else 2
a2 = (
"this is a very long text that will make the group break to check that parentheses are added"
if True
else 2
)
# These comment should be kept in place
b1 = (
# We return "a" ...
"a" # that's our True value
# ... if this condition matches ...
if True # that's our test
# ... otherwise we return "b"
else "b" # that's our False value
)
# These only need to be stable, bonus is we also keep the order
c1 = (
"a" # 1
# 2
if True # 3
# 4
else "b" # 5
)
c2 = (
"a" # 1
# 2
# 3
# 4
if True # 5
# 6
# 7
# 8
else "b" # 9
)
```