Avoid breaking call chains unnecessarily (#6488)

## Summary

This PR attempts to fix the formatting of the following expression:

```python
max_message_id = (
    Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id
)
```

Specifically, Black preserves _that_ formatting, while we do:

```python
max_message_id = (
    Message.objects.filter(recipient=recipient)
    .order_by("id")
    .reverse()[0]
    .id
)
```

The fix here is to add a group around the entire call chain.

## Test Plan

Before:

- `zulip`: 0.99702
- `django`: 0.99784
- `warehouse`: 0.99585
- `build`: 0.75623
- `transformers`: 0.99470
- `cpython`: 0.75989
- `typeshed`: 0.74853

After:

- `zulip`: 0.99703
- `django`: 0.99791
- `warehouse`: 0.99586
- `build`: 0.75623
- `transformers`: 0.99470
- `cpython`: 0.75989
- `typeshed`: 0.74853
This commit is contained in:
Charlie Marsh 2023-08-11 09:33:15 -04:00 committed by GitHub
parent b05574babd
commit f2939c678b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 122 additions and 91 deletions

View file

@ -154,4 +154,10 @@ zero(
five,
)
max_message_id = (
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id
)
max_message_id = (
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id()
)

View file

@ -35,6 +35,7 @@ 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 {
@ -45,8 +46,8 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
let comments = f.context().comments().clone();
let dangling_comments = comments.dangling_comments(item);
let leading_attribute_comments_start =
dangling_comments.partition_point(|comment| comment.line_position().is_end_of_line());
let leading_attribute_comments_start = dangling_comments
.partition_point(|comment| comment.line_position().is_end_of_line());
let (trailing_dot_comments, leading_attribute_comments) =
dangling_comments.split_at(leading_attribute_comments_start);
@ -73,7 +74,8 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
}
_ => {
// This matches [`CallChainLayout::from_expression`]
if is_expression_parenthesized(value.as_ref().into(), f.context().source()) {
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)?;
@ -135,6 +137,15 @@ impl FormatNodeRule<ExprAttribute> for FormatExprAttribute {
]
)
}
});
let is_call_chain_root = self.call_chain_layout == CallChainLayout::Default
&& call_chain_layout == CallChainLayout::Fluent;
if is_call_chain_root {
write!(f, [group(&format_inner)])
} else {
write!(f, [format_inner])
}
}
fn fmt_dangling_comments(

View file

@ -160,7 +160,13 @@ zero(
five,
)
max_message_id = (
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id
)
max_message_id = (
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id()
)
```
## Output
@ -334,6 +340,14 @@ zero(
).four(
five,
)
max_message_id = (
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id
)
max_message_id = (
Message.objects.filter(recipient=recipient).order_by("id").reverse()[0].id()
)
```