mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-03 07:04:53 +00:00
Fix can_omit_optional_parentheses
for expressions with a right most fstring (#9124)
This commit is contained in:
parent
b8fc006e52
commit
7256b882b9
3 changed files with 55 additions and 17 deletions
|
@ -319,6 +319,18 @@ expected_content = (
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Skip FString content when determining whether to omit optional parentheses or not.0
|
||||||
|
# The below expression should be parenthesized because it ends with an fstring and starts with a name.
|
||||||
|
# (Call expressions at the beginning don't count as parenthesized because they don't start with parens).
|
||||||
|
assert (
|
||||||
|
format.format_event(spec)
|
||||||
|
== f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})'
|
||||||
|
)
|
||||||
|
# Avoid parentheses for this example because it starts with a tuple expression.
|
||||||
|
assert (
|
||||||
|
(spec, format)
|
||||||
|
== f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})'
|
||||||
|
)
|
||||||
|
|
||||||
rowuses = [(1 << j) | # column ordinal
|
rowuses = [(1 << j) | # column ordinal
|
||||||
(1 << (n + i-j + n-1)) | # NW-SE ordinal
|
(1 << (n + i-j + n-1)) | # NW-SE ordinal
|
||||||
|
|
|
@ -552,18 +552,14 @@ fn can_omit_optional_parentheses(expr: &Expr, context: &PyFormatContext) -> bool
|
||||||
// Only use the layout if the first expression starts with parentheses
|
// Only use the layout if the first expression starts with parentheses
|
||||||
// or the last expression ends with parentheses of some sort, and
|
// or the last expression ends with parentheses of some sort, and
|
||||||
// those parentheses are non-empty.
|
// those parentheses are non-empty.
|
||||||
if visitor
|
visitor
|
||||||
.last
|
.last
|
||||||
.is_some_and(|last| is_parenthesized(last, context))
|
.is_some_and(|last| is_parenthesized(last, context))
|
||||||
{
|
|| visitor
|
||||||
true
|
|
||||||
} else {
|
|
||||||
visitor
|
|
||||||
.first
|
.first
|
||||||
.expression()
|
.expression()
|
||||||
.is_some_and(|first| is_parenthesized(first, context))
|
.is_some_and(|first| is_parenthesized(first, context))
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -689,16 +685,6 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
|
||||||
// Don't walk the slice, because the slice is always parenthesized.
|
// Don't walk the slice, because the slice is always parenthesized.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Expr::UnaryOp(ast::ExprUnaryOp {
|
|
||||||
range: _,
|
|
||||||
op,
|
|
||||||
operand: _,
|
|
||||||
}) => {
|
|
||||||
if op.is_invert() {
|
|
||||||
self.update_max_precedence(OperatorPrecedence::BitwiseInversion);
|
|
||||||
}
|
|
||||||
self.first.set_if_none(First::Token);
|
|
||||||
}
|
|
||||||
|
|
||||||
// `[a, b].test.test[300].dot`
|
// `[a, b].test.test[300].dot`
|
||||||
Expr::Attribute(ast::ExprAttribute {
|
Expr::Attribute(ast::ExprAttribute {
|
||||||
|
@ -727,10 +713,23 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
|
||||||
}
|
}
|
||||||
Expr::FString(ast::ExprFString { value, .. }) if value.is_implicit_concatenated() => {
|
Expr::FString(ast::ExprFString { value, .. }) if value.is_implicit_concatenated() => {
|
||||||
self.update_max_precedence(OperatorPrecedence::String);
|
self.update_max_precedence(OperatorPrecedence::String);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expressions with sub expressions but a preceding token
|
// Expressions with sub expressions but a preceding token
|
||||||
// Mark this expression as first expression and not the sub expression.
|
// Mark this expression as first expression and not the sub expression.
|
||||||
|
// Visit the sub-expressions because the sub expressions may be the end of the entire expression.
|
||||||
|
Expr::UnaryOp(ast::ExprUnaryOp {
|
||||||
|
range: _,
|
||||||
|
op,
|
||||||
|
operand: _,
|
||||||
|
}) => {
|
||||||
|
if op.is_invert() {
|
||||||
|
self.update_max_precedence(OperatorPrecedence::BitwiseInversion);
|
||||||
|
}
|
||||||
|
self.first.set_if_none(First::Token);
|
||||||
|
}
|
||||||
|
|
||||||
Expr::Lambda(_)
|
Expr::Lambda(_)
|
||||||
| Expr::Await(_)
|
| Expr::Await(_)
|
||||||
| Expr::Yield(_)
|
| Expr::Yield(_)
|
||||||
|
@ -739,6 +738,7 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
|
||||||
self.first.set_if_none(First::Token);
|
self.first.set_if_none(First::Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Terminal nodes or nodes that wrap a sub-expression (where the sub expression can never be the end).
|
||||||
Expr::Tuple(_)
|
Expr::Tuple(_)
|
||||||
| Expr::NamedExpr(_)
|
| Expr::NamedExpr(_)
|
||||||
| Expr::GeneratorExp(_)
|
| Expr::GeneratorExp(_)
|
||||||
|
@ -751,7 +751,9 @@ impl<'input> CanOmitOptionalParenthesesVisitor<'input> {
|
||||||
| Expr::EllipsisLiteral(_)
|
| Expr::EllipsisLiteral(_)
|
||||||
| Expr::Name(_)
|
| Expr::Name(_)
|
||||||
| Expr::Slice(_)
|
| Expr::Slice(_)
|
||||||
| Expr::IpyEscapeCommand(_) => {}
|
| Expr::IpyEscapeCommand(_) => {
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
walk_expr(self, expr);
|
walk_expr(self, expr);
|
||||||
|
|
|
@ -325,6 +325,18 @@ expected_content = (
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Skip FString content when determining whether to omit optional parentheses or not.0
|
||||||
|
# The below expression should be parenthesized because it ends with an fstring and starts with a name.
|
||||||
|
# (Call expressions at the beginning don't count as parenthesized because they don't start with parens).
|
||||||
|
assert (
|
||||||
|
format.format_event(spec)
|
||||||
|
== f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})'
|
||||||
|
)
|
||||||
|
# Avoid parentheses for this example because it starts with a tuple expression.
|
||||||
|
assert (
|
||||||
|
(spec, format)
|
||||||
|
== f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})'
|
||||||
|
)
|
||||||
|
|
||||||
rowuses = [(1 << j) | # column ordinal
|
rowuses = [(1 << j) | # column ordinal
|
||||||
(1 << (n + i-j + n-1)) | # NW-SE ordinal
|
(1 << (n + i-j + n-1)) | # NW-SE ordinal
|
||||||
|
@ -790,6 +802,18 @@ expected_content = (
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Skip FString content when determining whether to omit optional parentheses or not.0
|
||||||
|
# The below expression should be parenthesized because it ends with an fstring and starts with a name.
|
||||||
|
# (Call expressions at the beginning don't count as parenthesized because they don't start with parens).
|
||||||
|
assert (
|
||||||
|
format.format_event(spec)
|
||||||
|
== f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})'
|
||||||
|
)
|
||||||
|
# Avoid parentheses for this example because it starts with a tuple expression.
|
||||||
|
assert (
|
||||||
|
spec,
|
||||||
|
format,
|
||||||
|
) == f'Event("_remove_cookie", {{key:`testkey`,options:{json.dumps(options)}}})'
|
||||||
|
|
||||||
rowuses = [
|
rowuses = [
|
||||||
(1 << j) # column ordinal
|
(1 << j) # column ordinal
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue