mirror of
https://github.com/astral-sh/ruff.git
synced 2025-08-04 10:48:32 +00:00
Preserve parentheses around partial call chains (#7109)
This commit is contained in:
parent
7be28a38c5
commit
ece30e7c69
4 changed files with 207 additions and 38 deletions
|
@ -161,3 +161,58 @@ max_message_id = (
|
|||
max_message_id = (
|
||||
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id()
|
||||
)
|
||||
|
||||
# Parentheses with fluent style within and outside of the parentheses.
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
)
|
||||
.groupby(1,)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
( # foo
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
)
|
||||
.groupby(1,)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
)
|
||||
.sum()
|
||||
)
|
||||
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
)
|
||||
.sum()
|
||||
.bar()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
.bar()
|
||||
)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
.bar()
|
||||
)
|
||||
.sum()
|
||||
.baz()
|
||||
)
|
||||
|
||||
|
|
|
@ -37,49 +37,45 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
|
|||
let call_chain_layout = self.call_chain_layout.apply_in_node(item, f);
|
||||
|
||||
let format_inner = format_with(|f: &mut PyFormatter| {
|
||||
let needs_parentheses = matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ExprConstant {
|
||||
value: Constant::Int(_) | Constant::Float(_),
|
||||
..
|
||||
})
|
||||
);
|
||||
let parenthesize_value =
|
||||
// If the value is an integer, we need to parenthesize it to avoid a syntax error.
|
||||
matches!(
|
||||
value.as_ref(),
|
||||
Expr::Constant(ExprConstant {
|
||||
value: Constant::Int(_) | Constant::Float(_),
|
||||
..
|
||||
})
|
||||
) || is_expression_parenthesized(value.into(), f.context().source());
|
||||
|
||||
if needs_parentheses {
|
||||
value.format().with_options(Parentheses::Always).fmt(f)?;
|
||||
} else if call_chain_layout == CallChainLayout::Fluent {
|
||||
match value.as_ref() {
|
||||
Expr::Attribute(expr) => {
|
||||
expr.format().with_options(call_chain_layout).fmt(f)?;
|
||||
}
|
||||
Expr::Call(expr) => {
|
||||
expr.format().with_options(call_chain_layout).fmt(f)?;
|
||||
if call_chain_layout == CallChainLayout::Fluent {
|
||||
// Format the dot on its own line
|
||||
if call_chain_layout == CallChainLayout::Fluent {
|
||||
if parenthesize_value {
|
||||
// Don't propagate the call chain layout.
|
||||
value.format().with_options(Parentheses::Always).fmt(f)?;
|
||||
|
||||
// Format the dot on its own line.
|
||||
soft_line_break().fmt(f)?;
|
||||
} else {
|
||||
match value.as_ref() {
|
||||
Expr::Attribute(expr) => {
|
||||
expr.format().with_options(call_chain_layout).fmt(f)?;
|
||||
}
|
||||
Expr::Call(expr) => {
|
||||
expr.format().with_options(call_chain_layout).fmt(f)?;
|
||||
soft_line_break().fmt(f)?;
|
||||
}
|
||||
}
|
||||
Expr::Subscript(expr) => {
|
||||
expr.format().with_options(call_chain_layout).fmt(f)?;
|
||||
if call_chain_layout == CallChainLayout::Fluent {
|
||||
// Format the dot on its own line
|
||||
Expr::Subscript(expr) => {
|
||||
expr.format().with_options(call_chain_layout).fmt(f)?;
|
||||
soft_line_break().fmt(f)?;
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
// This matches [`CallChainLayout::from_expression`]
|
||||
if is_expression_parenthesized(value.as_ref().into(), f.context().source())
|
||||
{
|
||||
value.format().with_options(Parentheses::Always).fmt(f)?;
|
||||
// Format the dot on its own line
|
||||
soft_line_break().fmt(f)?;
|
||||
} else {
|
||||
value.format().fmt(f)?;
|
||||
_ => {
|
||||
value.format().with_options(Parentheses::Never).fmt(f)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if parenthesize_value {
|
||||
value.format().with_options(Parentheses::Always).fmt(f)?;
|
||||
} else {
|
||||
value.format().fmt(f)?;
|
||||
value.format().with_options(Parentheses::Never).fmt(f)?;
|
||||
}
|
||||
|
||||
// Identify dangling comments before and after the dot:
|
||||
|
|
|
@ -630,20 +630,21 @@ impl CallChainLayout {
|
|||
loop {
|
||||
match expr {
|
||||
ExpressionRef::Attribute(ast::ExprAttribute { value, .. }) => {
|
||||
expr = ExpressionRef::from(value.as_ref());
|
||||
// ```
|
||||
// f().g
|
||||
// ^^^ value
|
||||
// data[:100].T
|
||||
// ^^^^^^^^^^ value
|
||||
// ```
|
||||
if matches!(value.as_ref(), Expr::Call(_) | Expr::Subscript(_)) {
|
||||
attributes_after_parentheses += 1;
|
||||
} else if is_expression_parenthesized(expr, source) {
|
||||
if is_expression_parenthesized(value.into(), source) {
|
||||
// `(a).b`. We preserve these parentheses so don't recurse
|
||||
attributes_after_parentheses += 1;
|
||||
break;
|
||||
} else if matches!(value.as_ref(), Expr::Call(_) | Expr::Subscript(_)) {
|
||||
attributes_after_parentheses += 1;
|
||||
}
|
||||
|
||||
expr = ExpressionRef::from(value.as_ref());
|
||||
}
|
||||
// ```
|
||||
// f()
|
||||
|
@ -666,9 +667,11 @@ impl CallChainLayout {
|
|||
if is_expression_parenthesized(expr, source) {
|
||||
attributes_after_parentheses += 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// We preserve these parentheses so don't recurse
|
||||
if is_expression_parenthesized(expr, source) {
|
||||
break;
|
||||
|
|
|
@ -167,6 +167,61 @@ max_message_id = (
|
|||
max_message_id = (
|
||||
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id()
|
||||
)
|
||||
|
||||
# Parentheses with fluent style within and outside of the parentheses.
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
)
|
||||
.groupby(1,)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
( # foo
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
)
|
||||
.groupby(1,)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
)
|
||||
.sum()
|
||||
)
|
||||
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
)
|
||||
.sum()
|
||||
.bar()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
.bar()
|
||||
)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(1,)
|
||||
.bar()
|
||||
)
|
||||
.sum()
|
||||
.baz()
|
||||
)
|
||||
|
||||
```
|
||||
|
||||
## Output
|
||||
|
@ -350,6 +405,66 @@ max_message_id = (
|
|||
max_message_id = (
|
||||
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id()
|
||||
)
|
||||
|
||||
# Parentheses with fluent style within and outside of the parentheses.
|
||||
(
|
||||
(df1_aaaaaaaaaaaa.merge())
|
||||
.groupby(
|
||||
1,
|
||||
)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
( # foo
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
)
|
||||
.groupby(
|
||||
1,
|
||||
)
|
||||
.sum()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge().groupby(
|
||||
1,
|
||||
)
|
||||
).sum()
|
||||
)
|
||||
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge().groupby(
|
||||
1,
|
||||
)
|
||||
)
|
||||
.sum()
|
||||
.bar()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(
|
||||
1,
|
||||
)
|
||||
.bar()
|
||||
).sum()
|
||||
)
|
||||
|
||||
(
|
||||
(
|
||||
df1_aaaaaaaaaaaa.merge()
|
||||
.groupby(
|
||||
1,
|
||||
)
|
||||
.bar()
|
||||
)
|
||||
.sum()
|
||||
.baz()
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue