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

@ -476,8 +476,9 @@ where
orelse, orelse,
range: _range, range: _range,
}) => { }) => {
visitor.visit_expr(test); // `body if test else orelse`
visitor.visit_expr(body); visitor.visit_expr(body);
visitor.visit_expr(test);
visitor.visit_expr(orelse); visitor.visit_expr(orelse);
} }

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 std::cmp::Ordering;
use ruff_text_size::TextRange; use ruff_text_size::{TextLen, TextRange};
use rustpython_parser::ast; 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::node::{AnyNodeRef, AstNode};
use ruff_python_ast::source_code::Locator; 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::{ use crate::other::arguments::{
assign_argument_separator_comment_placement, find_argument_separators, 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. /// Implements the custom comment placement logic.
pub(super) fn place_comment<'a>( pub(super) fn place_comment<'a>(
@ -37,6 +39,7 @@ pub(super) fn place_comment<'a>(
handle_dict_unpacking_comment, handle_dict_unpacking_comment,
handle_slice_comments, handle_slice_comments,
handle_attribute_comment, handle_attribute_comment,
handle_expr_if_comment,
]; ];
for handler in HANDLERS { for handler in HANDLERS {
comment = match handler(comment, locator) { 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. /// 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 fn are_same_optional<'a, T>(left: AnyNodeRef, right: Option<T>) -> bool
where where

View file

@ -1,21 +1,42 @@
use crate::comments::Comments; use crate::comments::{leading_comments, Comments};
use crate::expression::parentheses::{ use crate::expression::parentheses::{
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize, default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
}; };
use crate::{not_yet_implemented_custom_text, FormatNodeRule, PyFormatter}; use crate::{AsFormat, FormatNodeRule, PyFormatter};
use ruff_formatter::{write, Buffer, FormatResult}; 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; use rustpython_parser::ast::ExprIfExp;
#[derive(Default)] #[derive(Default)]
pub struct FormatExprIfExp; pub struct FormatExprIfExp;
impl FormatNodeRule<ExprIfExp> for 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!( write!(
f, f,
[not_yet_implemented_custom_text( [group(&format_args![
"NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false" 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 ```diff
--- Black --- Black
+++ Ruff +++ Ruff
@@ -1,90 +1,50 @@ @@ -1,20 +1,16 @@
long_kwargs_single_line = my_function( long_kwargs_single_line = my_function(
foo="test, this is a sample value", foo="test, this is a sample value",
- bar=( - bar=(
@ -87,7 +87,9 @@ def something():
- if some_boolean_variable - if some_boolean_variable
- else some_fallback_value_foo_bar_baz - 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", baz="hello, this is a another value",
) )
@ -98,33 +100,13 @@ def something():
- if some_boolean_variable - if some_boolean_variable
- else some_fallback_value_foo_bar_baz - 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", baz="hello, this is a another value",
) )
imploding_kwargs = my_function( @@ -40,11 +36,9 @@
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
)
def weird_default_argument( def weird_default_argument(
@ -133,21 +115,15 @@ def something():
- if SOME_CONSTANT - if SOME_CONSTANT
- else some_fallback_value_foo_bar_baz - 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 pass
@@ -59,26 +53,14 @@
-nested = ( else "this one is a little shorter"
- "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
-generator_expression = ( -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 ## Ruff Output
@ -188,38 +157,58 @@ def something():
```py ```py
long_kwargs_single_line = my_function( long_kwargs_single_line = my_function(
foo="test, this is a sample value", 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", baz="hello, this is a another value",
) )
multiline_kwargs_indented = my_function( multiline_kwargs_indented = my_function(
foo="test, this is a sample value", 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", baz="hello, this is a another value",
) )
imploding_kwargs = my_function( imploding_kwargs = my_function(
foo="test, this is a sample value", 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", 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( 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( 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 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 []) 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(): def something():
clone._iterable_class = ( 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 Name
None None
True True
@@ -31,33 +31,39 @@ @@ -31,18 +31,15 @@
-1 -1
~int and not v1 ^ 123 + v2 | True ~int and not v1 ^ 123 + v2 | True
(~int) and (not ((v1 ^ (123 + v2)) | True)) (~int) and (not ((v1 ^ (123 + v2)) | True))
@ -291,16 +291,6 @@ last_call()
- "port1": port1_resource, - "port1": port1_resource,
- "port2": port2_resource, - "port2": port2_resource,
-}[port_id] -}[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 +lambda x: True
+lambda x: True +lambda x: True
@ -308,25 +298,14 @@ last_call()
+lambda x: True +lambda x: True
+manylambdas = lambda x: True +manylambdas = lambda x: True
+foo = lambda x: True +foo = lambda x: True
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false 1 if True else 2
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false str or None if True else str or bytes or None
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false (str or None) if True else (str or bytes or None)
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false @@ -57,7 +54,13 @@
+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)}
{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}} {"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
{**a, **b, **c} {**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 -({"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"}, + {"a": "b"},
+ (True or False), + (True or False),
@ -337,7 +316,7 @@ last_call()
() ()
(1,) (1,)
(1, 2) (1, 2)
@@ -69,40 +75,37 @@ @@ -69,40 +72,37 @@
2, 2,
3, 3,
] ]
@ -396,7 +375,7 @@ last_call()
Python3 > Python2 > COBOL Python3 > Python2 > COBOL
Life is Life Life is Life
call() call()
@@ -115,10 +118,10 @@ @@ -115,10 +115,10 @@
arg, arg,
another, another,
kwarg="hey", kwarg="hey",
@ -410,7 +389,7 @@ last_call()
call(**self.screen_kwargs) call(**self.screen_kwargs)
call(b, **self.screen_kwargs) call(b, **self.screen_kwargs)
lukasz.langa.pl lukasz.langa.pl
@@ -131,34 +134,28 @@ @@ -131,34 +131,28 @@
tuple[str, ...] tuple[str, ...]
tuple[str, int, float, dict[str, int]] tuple[str, int, float, dict[str, int]]
tuple[ tuple[
@ -458,26 +437,16 @@ last_call()
numpy[0, :] numpy[0, :]
numpy[:, i] numpy[:, i]
numpy[0, :2] numpy[0, :2]
@@ -172,20 +169,27 @@ @@ -172,7 +166,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]]
-numpy[:, ::-1] -numpy[:, ::-1]
+numpy[:, :: -1] +numpy[:, :: -1]
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)
+NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false
{"2.7": dead, "3.7": long_live or die_hard} {"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"} @@ -181,11 +175,11 @@
+{
+ "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]
(SomeName) (SomeName)
SomeName SomeName
(Good, Bad, Ugly) (Good, Bad, Ugly)
@ -494,7 +463,7 @@ last_call()
{ {
"id": "1", "id": "1",
"type": "type", "type": "type",
@@ -200,32 +204,22 @@ @@ -200,32 +194,22 @@
c = 1 c = 1
d = (1,) + a + (2,) d = (1,) + a + (2,)
e = (1,).count(1) e = (1,).count(1)
@ -537,7 +506,7 @@ last_call()
Ø = set() Ø = set()
authors.łukasz.say_thanks() authors.łukasz.say_thanks()
mapping = { mapping = {
@@ -237,29 +231,29 @@ @@ -237,29 +221,33 @@
def gen(): def gen():
@ -564,7 +533,11 @@ last_call()
-), "Short message" -), "Short message"
-assert parens is TooMany -assert parens is TooMany
+print(*NOT_YET_IMPLEMENTED_ExprStarred) +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) +print(*NOT_YET_IMPLEMENTED_ExprStarred)
+NOT_YET_IMPLEMENTED_StmtAssert +NOT_YET_IMPLEMENTED_StmtAssert
+NOT_YET_IMPLEMENTED_StmtAssert +NOT_YET_IMPLEMENTED_StmtAssert
@ -580,7 +553,7 @@ last_call()
... ...
for i in call(): for i in call():
... ...
@@ -328,13 +322,18 @@ @@ -328,13 +316,18 @@
): ):
return True return True
if ( if (
@ -602,7 +575,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 +335,8 @@
~aaaaaaaaaaaaaaaa.a ~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b + aaaaaaaaaaaaaaaa.b
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
@ -659,23 +632,20 @@ lambda x: True
lambda x: True lambda x: True
manylambdas = lambda x: True manylambdas = lambda x: True
foo = lambda x: True foo = lambda x: True
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false 1 if True else 2
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false str or None if True else str or bytes or None
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false (str or None) if True else (str or bytes or None)
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false str or None if (1 if True else 2) else str or bytes or None
NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false (str or None) if (1 if True else 2) else (str or bytes or None)
(NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false) (
(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)}
{"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}} {"2.7": dead, "3.7": (long_live or die_hard), **{"3.6": verygood}}
{**a, **b, **c} {**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",
(NOT_IMPLEMENTED_true if NOT_IMPLEMENTED_cond else NOT_IMPLEMENTED_false),
}
( (
{"a": "b"}, {"a": "b"},
(True or False), (True or False),
@ -790,16 +760,9 @@ numpy[-(c + 1) :, d]
numpy[:, l[-2]] numpy[:, l[-2]]
numpy[:, :: -1] numpy[:, :: -1]
numpy[np.newaxis, :] 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": 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] [1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
(SomeName) (SomeName)
SomeName SomeName
@ -861,7 +824,11 @@ async def f():
print(*NOT_YET_IMPLEMENTED_ExprStarred) 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) print(*NOT_YET_IMPLEMENTED_ExprStarred)
NOT_YET_IMPLEMENTED_StmtAssert NOT_YET_IMPLEMENTED_StmtAssert
NOT_YET_IMPLEMENTED_StmtAssert NOT_YET_IMPLEMENTED_StmtAssert

View file

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

View file

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