mirror of
https://github.com/astral-sh/ruff.git
synced 2025-07-23 04:55:09 +00:00
Format target: annotation = value?
expressions (#5661)
This commit is contained in:
parent
0c8ec80d7b
commit
f1d367655b
28 changed files with 318 additions and 988 deletions
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"magic_trailing_comma": "ignore"
|
||||||
|
}
|
13
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/annotated_assign.py
vendored
Normal file
13
crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/annotated_assign.py
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
a: string
|
||||||
|
|
||||||
|
b: string = "test"
|
||||||
|
|
||||||
|
b: list[
|
||||||
|
string,
|
||||||
|
int
|
||||||
|
] = [1, 2]
|
||||||
|
|
||||||
|
b: list[
|
||||||
|
string,
|
||||||
|
int,
|
||||||
|
] = [1, 2]
|
|
@ -6,20 +6,20 @@ use ruff_text_size::TextSize;
|
||||||
use rustpython_parser::ast::Ranged;
|
use rustpython_parser::ast::Ranged;
|
||||||
|
|
||||||
/// Adds parentheses and indents `content` if it doesn't fit on a line.
|
/// Adds parentheses and indents `content` if it doesn't fit on a line.
|
||||||
pub(crate) fn optional_parentheses<'ast, T>(content: &T) -> OptionalParentheses<'_, 'ast>
|
pub(crate) fn parenthesize_if_expands<'ast, T>(content: &T) -> ParenthesizeIfExpands<'_, 'ast>
|
||||||
where
|
where
|
||||||
T: Format<PyFormatContext<'ast>>,
|
T: Format<PyFormatContext<'ast>>,
|
||||||
{
|
{
|
||||||
OptionalParentheses {
|
ParenthesizeIfExpands {
|
||||||
inner: Argument::new(content),
|
inner: Argument::new(content),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct OptionalParentheses<'a, 'ast> {
|
pub(crate) struct ParenthesizeIfExpands<'a, 'ast> {
|
||||||
inner: Argument<'a, PyFormatContext<'ast>>,
|
inner: Argument<'a, PyFormatContext<'ast>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ast> Format<PyFormatContext<'ast>> for OptionalParentheses<'_, 'ast> {
|
impl<'ast> Format<PyFormatContext<'ast>> for ParenthesizeIfExpands<'_, 'ast> {
|
||||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
|
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
|
||||||
let saved_level = f.context().node_level();
|
let saved_level = f.context().node_level();
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use rustpython_parser::ast::ExprSubscript;
|
use rustpython_parser::ast::{Expr, ExprSubscript};
|
||||||
|
|
||||||
use ruff_formatter::{format_args, write};
|
use ruff_formatter::{format_args, write};
|
||||||
use ruff_python_ast::node::AstNode;
|
use ruff_python_ast::node::AstNode;
|
||||||
|
@ -6,8 +6,10 @@ use ruff_python_ast::node::AstNode;
|
||||||
use crate::comments::trailing_comments;
|
use crate::comments::trailing_comments;
|
||||||
use crate::context::NodeLevel;
|
use crate::context::NodeLevel;
|
||||||
use crate::context::PyFormatContext;
|
use crate::context::PyFormatContext;
|
||||||
|
use crate::expression::expr_tuple::TupleParentheses;
|
||||||
use crate::expression::parentheses::{
|
use crate::expression::parentheses::{
|
||||||
default_expression_needs_parentheses, NeedsParentheses, Parentheses, Parenthesize,
|
default_expression_needs_parentheses, in_parentheses_only_group, NeedsParentheses, Parentheses,
|
||||||
|
Parenthesize,
|
||||||
};
|
};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::FormatNodeRule;
|
use crate::FormatNodeRule;
|
||||||
|
@ -42,12 +44,31 @@ impl FormatNodeRule<ExprSubscript> for FormatExprSubscript {
|
||||||
value.format().fmt(f)?;
|
value.format().fmt(f)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let format_slice = format_with(|f: &mut PyFormatter| {
|
||||||
|
let saved_level = f.context().node_level();
|
||||||
|
f.context_mut()
|
||||||
|
.set_node_level(NodeLevel::ParenthesizedExpression);
|
||||||
|
|
||||||
|
let result = if let Expr::Tuple(tuple) = slice.as_ref() {
|
||||||
|
tuple
|
||||||
|
.format()
|
||||||
|
.with_options(TupleParentheses::Subscript)
|
||||||
|
.fmt(f)
|
||||||
|
} else {
|
||||||
|
slice.format().fmt(f)
|
||||||
|
};
|
||||||
|
|
||||||
|
f.context_mut().set_node_level(saved_level);
|
||||||
|
|
||||||
|
result
|
||||||
|
});
|
||||||
|
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[group(&format_args![
|
[in_parentheses_only_group(&format_args![
|
||||||
text("["),
|
text("["),
|
||||||
trailing_comments(dangling_comments),
|
trailing_comments(dangling_comments),
|
||||||
soft_block_indent(&slice.format()),
|
soft_block_indent(&format_slice),
|
||||||
text("]")
|
text("]")
|
||||||
])]
|
])]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::builders::optional_parentheses;
|
use crate::builders::parenthesize_if_expands;
|
||||||
use crate::comments::{dangling_comments, CommentLinePosition};
|
use crate::comments::{dangling_comments, CommentLinePosition};
|
||||||
use crate::expression::parentheses::{
|
use crate::expression::parentheses::{
|
||||||
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
|
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
|
||||||
|
@ -17,6 +17,11 @@ pub enum TupleParentheses {
|
||||||
Default,
|
Default,
|
||||||
/// Effectively `Some(Parentheses)` in `Option<Parentheses>`
|
/// Effectively `Some(Parentheses)` in `Option<Parentheses>`
|
||||||
Expr(Parentheses),
|
Expr(Parentheses),
|
||||||
|
|
||||||
|
/// Black omits parentheses for tuples inside of subscripts except if the tuple is parenthesized
|
||||||
|
/// in the source code.
|
||||||
|
Subscript,
|
||||||
|
|
||||||
/// Handle the special case where we remove parentheses even if they were initially present
|
/// Handle the special case where we remove parentheses even if they were initially present
|
||||||
///
|
///
|
||||||
/// Normally, black keeps parentheses, but in the case of loops it formats
|
/// Normally, black keeps parentheses, but in the case of loops it formats
|
||||||
|
@ -86,21 +91,32 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
||||||
])]
|
])]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
[single] => {
|
[single] => match self.parentheses {
|
||||||
// A single element tuple always needs parentheses and a trailing comma
|
TupleParentheses::Subscript
|
||||||
parenthesized("(", &format_args![single.format(), &text(",")], ")").fmt(f)
|
if !is_parenthesized(*range, elts, f.context().source()) =>
|
||||||
}
|
{
|
||||||
|
write!(f, [single.format(), text(",")])
|
||||||
|
}
|
||||||
|
_ =>
|
||||||
|
// A single element tuple always needs parentheses and a trailing comma, except when inside of a subscript
|
||||||
|
{
|
||||||
|
parenthesized("(", &format_args![single.format(), text(",")], ")").fmt(f)
|
||||||
|
}
|
||||||
|
},
|
||||||
// If the tuple has parentheses, we generally want to keep them. The exception are for
|
// If the tuple has parentheses, we generally want to keep them. The exception are for
|
||||||
// loops, see `TupleParentheses::StripInsideForLoop` doc comment.
|
// loops, see `TupleParentheses::StripInsideForLoop` doc comment.
|
||||||
//
|
//
|
||||||
// Unlike other expression parentheses, tuple parentheses are part of the range of the
|
// Unlike other expression parentheses, tuple parentheses are part of the range of the
|
||||||
// tuple itself.
|
// tuple itself.
|
||||||
elts if is_parenthesized(*range, elts, f)
|
elts if is_parenthesized(*range, elts, f.context().source())
|
||||||
&& self.parentheses != TupleParentheses::StripInsideForLoop =>
|
&& self.parentheses != TupleParentheses::StripInsideForLoop =>
|
||||||
{
|
{
|
||||||
parenthesized("(", &ExprSequence::new(elts), ")").fmt(f)
|
parenthesized("(", &ExprSequence::new(elts), ")").fmt(f)
|
||||||
}
|
}
|
||||||
elts => optional_parentheses(&ExprSequence::new(elts)).fmt(f),
|
elts => match self.parentheses {
|
||||||
|
TupleParentheses::Subscript => group(&ExprSequence::new(elts)).fmt(f),
|
||||||
|
_ => parenthesize_if_expands(&ExprSequence::new(elts)).fmt(f),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,15 +157,9 @@ impl NeedsParentheses for ExprTuple {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if a tuple has already had parentheses in the input
|
/// Check if a tuple has already had parentheses in the input
|
||||||
fn is_parenthesized(
|
fn is_parenthesized(tuple_range: TextRange, elts: &[Expr], source: &str) -> bool {
|
||||||
tuple_range: TextRange,
|
|
||||||
elts: &[Expr],
|
|
||||||
f: &mut Formatter<PyFormatContext<'_>>,
|
|
||||||
) -> bool {
|
|
||||||
let parentheses = '(';
|
let parentheses = '(';
|
||||||
let first_char = &f.context().source()[usize::from(tuple_range.start())..]
|
let first_char = &source[usize::from(tuple_range.start())..].chars().next();
|
||||||
.chars()
|
|
||||||
.next();
|
|
||||||
let Some(first_char) = first_char else {
|
let Some(first_char) = first_char else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,17 +2,16 @@ use rustpython_parser::ast;
|
||||||
use rustpython_parser::ast::{Expr, Operator};
|
use rustpython_parser::ast::{Expr, Operator};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
use crate::builders::optional_parentheses;
|
use crate::builders::parenthesize_if_expands;
|
||||||
use ruff_formatter::{
|
use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions};
|
||||||
format_args, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions,
|
|
||||||
};
|
|
||||||
use ruff_python_ast::node::AnyNodeRef;
|
use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_python_ast::visitor::preorder::{walk_expr, PreorderVisitor};
|
use ruff_python_ast::visitor::preorder::{walk_expr, PreorderVisitor};
|
||||||
|
|
||||||
use crate::context::NodeLevel;
|
use crate::context::NodeLevel;
|
||||||
use crate::expression::expr_tuple::TupleParentheses;
|
use crate::expression::expr_tuple::TupleParentheses;
|
||||||
use crate::expression::parentheses::{
|
use crate::expression::parentheses::{
|
||||||
is_expression_parenthesized, parenthesized, NeedsParentheses, Parentheses, Parenthesize,
|
is_expression_parenthesized, optional_parentheses, parenthesized, NeedsParentheses,
|
||||||
|
Parentheses, Parenthesize,
|
||||||
};
|
};
|
||||||
use crate::expression::string::StringLayout;
|
use crate::expression::string::StringLayout;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
@ -106,37 +105,9 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
|
||||||
// Add optional parentheses. Ignore if the item renders parentheses itself.
|
// Add optional parentheses. Ignore if the item renders parentheses itself.
|
||||||
Parentheses::Optional => {
|
Parentheses::Optional => {
|
||||||
if can_omit_optional_parentheses(item, f.context()) {
|
if can_omit_optional_parentheses(item, f.context()) {
|
||||||
let saved_level = f.context().node_level();
|
|
||||||
|
|
||||||
// The group id is used as a condition in [`in_parentheses_only`] to create a conditional group
|
|
||||||
// that is only active if the optional parentheses group expands.
|
|
||||||
let parens_id = f.group_id("optional_parentheses");
|
|
||||||
|
|
||||||
f.context_mut()
|
|
||||||
.set_node_level(NodeLevel::Expression(Some(parens_id)));
|
|
||||||
|
|
||||||
// We can't use `soft_block_indent` here because that would always increment the indent,
|
|
||||||
// even if the group does not break (the indent is not soft). This would result in
|
|
||||||
// too deep indentations if a `parenthesized` group expands. Using `indent_if_group_breaks`
|
|
||||||
// gives us the desired *soft* indentation that is only present if the optional parentheses
|
|
||||||
// are shown.
|
|
||||||
let result = group(&format_args![
|
|
||||||
if_group_breaks(&text("(")),
|
|
||||||
indent_if_group_breaks(
|
|
||||||
&format_args![soft_line_break(), format_expr],
|
|
||||||
parens_id
|
|
||||||
),
|
|
||||||
soft_line_break(),
|
|
||||||
if_group_breaks(&text(")"))
|
|
||||||
])
|
|
||||||
.with_group_id(Some(parens_id))
|
|
||||||
.fmt(f);
|
|
||||||
|
|
||||||
f.context_mut().set_node_level(saved_level);
|
|
||||||
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
optional_parentheses(&format_expr).fmt(f)
|
optional_parentheses(&format_expr).fmt(f)
|
||||||
|
} else {
|
||||||
|
parenthesize_if_expands(&format_expr).fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Parentheses::Custom | Parentheses::Never => {
|
Parentheses::Custom | Parentheses::Never => {
|
||||||
|
|
|
@ -178,6 +178,57 @@ impl<'ast> Format<PyFormatContext<'ast>> for FormatParenthesized<'_, 'ast> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wraps an expression in parentheses only if it still does not fit after expanding all expressions that start or end with
|
||||||
|
/// a parentheses (`()`, `[]`, `{}`).
|
||||||
|
pub(crate) fn optional_parentheses<'content, 'ast, Content>(
|
||||||
|
content: &'content Content,
|
||||||
|
) -> OptionalParentheses<'content, 'ast>
|
||||||
|
where
|
||||||
|
Content: Format<PyFormatContext<'ast>>,
|
||||||
|
{
|
||||||
|
OptionalParentheses {
|
||||||
|
content: Argument::new(content),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct OptionalParentheses<'content, 'ast> {
|
||||||
|
content: Argument<'content, PyFormatContext<'ast>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'ast> Format<PyFormatContext<'ast>> for OptionalParentheses<'_, 'ast> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<PyFormatContext<'ast>>) -> FormatResult<()> {
|
||||||
|
let saved_level = f.context().node_level();
|
||||||
|
|
||||||
|
// The group id is used as a condition in [`in_parentheses_only`] to create a conditional group
|
||||||
|
// that is only active if the optional parentheses group expands.
|
||||||
|
let parens_id = f.group_id("optional_parentheses");
|
||||||
|
|
||||||
|
f.context_mut()
|
||||||
|
.set_node_level(NodeLevel::Expression(Some(parens_id)));
|
||||||
|
|
||||||
|
// We can't use `soft_block_indent` here because that would always increment the indent,
|
||||||
|
// even if the group does not break (the indent is not soft). This would result in
|
||||||
|
// too deep indentations if a `parenthesized` group expands. Using `indent_if_group_breaks`
|
||||||
|
// gives us the desired *soft* indentation that is only present if the optional parentheses
|
||||||
|
// are shown.
|
||||||
|
let result = group(&format_args![
|
||||||
|
if_group_breaks(&text("(")),
|
||||||
|
indent_if_group_breaks(
|
||||||
|
&format_args![soft_line_break(), Arguments::from(&self.content)],
|
||||||
|
parens_id
|
||||||
|
),
|
||||||
|
soft_line_break(),
|
||||||
|
if_group_breaks(&text(")"))
|
||||||
|
])
|
||||||
|
.with_group_id(Some(parens_id))
|
||||||
|
.fmt(f);
|
||||||
|
|
||||||
|
f.context_mut().set_node_level(saved_level);
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Makes `content` a group, but only if the outer expression is parenthesized (a list, parenthesized expression, dict, ...)
|
/// Makes `content` a group, but only if the outer expression is parenthesized (a list, parenthesized expression, dict, ...)
|
||||||
/// or if the expression gets parenthesized because it expands over multiple lines.
|
/// or if the expression gets parenthesized because it expands over multiple lines.
|
||||||
pub(crate) fn in_parentheses_only_group<'content, 'ast, Content>(
|
pub(crate) fn in_parentheses_only_group<'content, 'ast, Content>(
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::builders::optional_parentheses;
|
use crate::builders::parenthesize_if_expands;
|
||||||
use crate::comments::{leading_comments, trailing_comments};
|
use crate::comments::{leading_comments, trailing_comments};
|
||||||
use crate::expression::parentheses::Parentheses;
|
use crate::expression::parentheses::Parentheses;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
@ -48,7 +48,7 @@ impl<'a> Format<PyFormatContext<'_>> for FormatString<'a> {
|
||||||
let format_continuation = FormatStringContinuation::new(self.constant, self.layout);
|
let format_continuation = FormatStringContinuation::new(self.constant, self.layout);
|
||||||
|
|
||||||
if let StringLayout::Default(Some(Parentheses::Custom)) = self.layout {
|
if let StringLayout::Default(Some(Parentheses::Custom)) = self.layout {
|
||||||
optional_parentheses(&format_continuation).fmt(f)
|
parenthesize_if_expands(&format_continuation).fmt(f)
|
||||||
} else {
|
} else {
|
||||||
format_continuation.fmt(f)
|
format_continuation.fmt(f)
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,11 +280,9 @@ if True:
|
||||||
#[test]
|
#[test]
|
||||||
fn quick_test() {
|
fn quick_test() {
|
||||||
let src = r#"
|
let src = r#"
|
||||||
if [
|
def foo() -> tuple[int, int, int,]:
|
||||||
aaaaaa,
|
return 2
|
||||||
BBBB,ccccccccc,ddddddd,eeeeeeeeee,ffffff
|
|
||||||
] & bbbbbbbbbbbbbbbbbbddddddddddddddddddddddddddddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:
|
|
||||||
...
|
|
||||||
"#;
|
"#;
|
||||||
// Tokenize once
|
// Tokenize once
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
|
use crate::prelude::*;
|
||||||
use ruff_formatter::{write, Buffer, FormatResult};
|
use crate::FormatNodeRule;
|
||||||
|
use ruff_formatter::write;
|
||||||
use rustpython_parser::ast::StmtAnnAssign;
|
use rustpython_parser::ast::StmtAnnAssign;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -7,6 +8,23 @@ pub struct FormatStmtAnnAssign;
|
||||||
|
|
||||||
impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
|
impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
|
||||||
fn fmt_fields(&self, item: &StmtAnnAssign, f: &mut PyFormatter) -> FormatResult<()> {
|
fn fmt_fields(&self, item: &StmtAnnAssign, f: &mut PyFormatter) -> FormatResult<()> {
|
||||||
write!(f, [not_yet_implemented(item)])
|
let StmtAnnAssign {
|
||||||
|
range: _,
|
||||||
|
target,
|
||||||
|
annotation,
|
||||||
|
value,
|
||||||
|
simple: _,
|
||||||
|
} = item;
|
||||||
|
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
[target.format(), text(":"), space(), annotation.format()]
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if let Some(value) = value {
|
||||||
|
write!(f, [space(), text("="), space(), value.format()])?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
use crate::context::PyFormatContext;
|
|
||||||
use crate::expression::parentheses::Parenthesize;
|
|
||||||
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
|
||||||
use ruff_formatter::formatter::Formatter;
|
|
||||||
use ruff_formatter::prelude::{space, text};
|
|
||||||
use ruff_formatter::{write, Buffer, Format, FormatResult};
|
|
||||||
use rustpython_parser::ast::Expr;
|
|
||||||
use rustpython_parser::ast::StmtAssign;
|
use rustpython_parser::ast::StmtAssign;
|
||||||
|
|
||||||
|
use ruff_formatter::write;
|
||||||
|
|
||||||
|
use crate::expression::parentheses::Parenthesize;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::FormatNodeRule;
|
||||||
|
|
||||||
// Note: This currently does wrap but not the black way so the types below likely need to be
|
// Note: This currently does wrap but not the black way so the types below likely need to be
|
||||||
// replaced entirely
|
// replaced entirely
|
||||||
//
|
//
|
||||||
|
@ -22,32 +21,11 @@ impl FormatNodeRule<StmtAssign> for FormatStmtAssign {
|
||||||
value,
|
value,
|
||||||
type_comment: _,
|
type_comment: _,
|
||||||
} = item;
|
} = item;
|
||||||
write!(
|
|
||||||
f,
|
|
||||||
[
|
|
||||||
LhsAssignList::new(targets),
|
|
||||||
value.format().with_options(Parenthesize::IfBreaks)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
for target in targets {
|
||||||
struct LhsAssignList<'a> {
|
write!(f, [target.format(), space(), text("="), space()])?;
|
||||||
lhs_assign_list: &'a [Expr],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> LhsAssignList<'a> {
|
|
||||||
const fn new(lhs_assign_list: &'a [Expr]) -> Self {
|
|
||||||
Self { lhs_assign_list }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Format<PyFormatContext<'_>> for LhsAssignList<'_> {
|
|
||||||
fn fmt(&self, f: &mut Formatter<PyFormatContext<'_>>) -> FormatResult<()> {
|
|
||||||
for element in self.lhs_assign_list {
|
|
||||||
write!(f, [&element.format(), space(), text("="), space(),])?;
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
|
write!(f, [value.format().with_options(Parenthesize::IfBreaks)])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::builders::{optional_parentheses, PyFormatterExtensions};
|
use crate::builders::{parenthesize_if_expands, PyFormatterExtensions};
|
||||||
use crate::comments::dangling_node_comments;
|
use crate::comments::dangling_node_comments;
|
||||||
use crate::expression::parentheses::Parenthesize;
|
use crate::expression::parentheses::Parenthesize;
|
||||||
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
||||||
|
@ -36,7 +36,7 @@ impl FormatNodeRule<StmtDelete> for FormatStmtDelete {
|
||||||
}
|
}
|
||||||
targets => {
|
targets => {
|
||||||
let item = format_with(|f| f.join_comma_separated().nodes(targets.iter()).finish());
|
let item = format_with(|f| f.join_comma_separated().nodes(targets.iter()).finish());
|
||||||
optional_parentheses(&item).fmt(f)
|
parenthesize_if_expands(&item).fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::comments::{leading_comments, trailing_comments};
|
use crate::comments::{leading_comments, trailing_comments};
|
||||||
use crate::context::NodeLevel;
|
use crate::context::NodeLevel;
|
||||||
use crate::expression::parentheses::Parenthesize;
|
use crate::expression::parentheses::{optional_parentheses, Parenthesize};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::trivia::{lines_after, skip_trailing_trivia};
|
use crate::trivia::{lines_after, skip_trailing_trivia};
|
||||||
use crate::FormatNodeRule;
|
use crate::FormatNodeRule;
|
||||||
|
@ -97,9 +97,9 @@ impl FormatRule<AnyFunctionDefinition<'_>, PyFormatContext<'_>> for FormatAnyFun
|
||||||
space(),
|
space(),
|
||||||
text("->"),
|
text("->"),
|
||||||
space(),
|
space(),
|
||||||
return_annotation
|
optional_parentheses(
|
||||||
.format()
|
&return_annotation.format().with_options(Parenthesize::Never)
|
||||||
.with_options(Parenthesize::IfBreaks)
|
)
|
||||||
]
|
]
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::builders::{optional_parentheses, PyFormatterExtensions};
|
use crate::builders::{parenthesize_if_expands, PyFormatterExtensions};
|
||||||
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
||||||
use ruff_formatter::prelude::{dynamic_text, format_with, space, text};
|
use ruff_formatter::prelude::{dynamic_text, format_with, space, text};
|
||||||
use ruff_formatter::{write, Buffer, Format, FormatResult};
|
use ruff_formatter::{write, Buffer, Format, FormatResult};
|
||||||
|
@ -43,6 +43,6 @@ impl FormatNodeRule<StmtImportFrom> for FormatStmtImportFrom {
|
||||||
.entries(names.iter().map(|name| (name, name.format())))
|
.entries(names.iter().map(|name| (name, name.format())))
|
||||||
.finish()
|
.finish()
|
||||||
});
|
});
|
||||||
optional_parentheses(&names).fmt(f)
|
parenthesize_if_expands(&names).fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ use ruff_python_ast::node::AnyNodeRef;
|
||||||
use ruff_text_size::TextRange;
|
use ruff_text_size::TextRange;
|
||||||
use rustpython_parser::ast::{Ranged, StmtAsyncWith, StmtWith, Suite, WithItem};
|
use rustpython_parser::ast::{Ranged, StmtAsyncWith, StmtWith, Suite, WithItem};
|
||||||
|
|
||||||
use crate::builders::optional_parentheses;
|
use crate::builders::parenthesize_if_expands;
|
||||||
use crate::comments::trailing_comments;
|
use crate::comments::trailing_comments;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use crate::FormatNodeRule;
|
use crate::FormatNodeRule;
|
||||||
|
@ -80,7 +80,7 @@ impl Format<PyFormatContext<'_>> for AnyStatementWith<'_> {
|
||||||
[
|
[
|
||||||
text("with"),
|
text("with"),
|
||||||
space(),
|
space(),
|
||||||
group(&optional_parentheses(&joined_items)),
|
group(&parenthesize_if_expands(&joined_items)),
|
||||||
text(":"),
|
text(":"),
|
||||||
trailing_comments(dangling_comments),
|
trailing_comments(dangling_comments),
|
||||||
block_indent(&self.body().format())
|
block_indent(&self.body().format())
|
||||||
|
|
|
@ -11,7 +11,15 @@ fn black_compatibility() {
|
||||||
let test_file = |input_path: &Path| {
|
let test_file = |input_path: &Path| {
|
||||||
let content = fs::read_to_string(input_path).unwrap();
|
let content = fs::read_to_string(input_path).unwrap();
|
||||||
|
|
||||||
let options = PyFormatOptions::default();
|
let options_path = input_path.with_extension("options.json");
|
||||||
|
|
||||||
|
let options: PyFormatOptions = if let Ok(options_file) = fs::File::open(options_path) {
|
||||||
|
let reader = BufReader::new(options_file);
|
||||||
|
serde_json::from_reader(reader).expect("Options to be a valid Json file")
|
||||||
|
} else {
|
||||||
|
PyFormatOptions::default()
|
||||||
|
};
|
||||||
|
|
||||||
let printed = format_module(&content, options.clone()).unwrap_or_else(|err| {
|
let printed = format_module(&content, options.clone()).unwrap_or_else(|err| {
|
||||||
panic!(
|
panic!(
|
||||||
"Formatting of {} to succeed but encountered error {err}",
|
"Formatting of {} to succeed but encountered error {err}",
|
||||||
|
|
|
@ -44,11 +44,8 @@ class DebugVisitor(Visitor[T]):
|
||||||
```diff
|
```diff
|
||||||
--- Black
|
--- Black
|
||||||
+++ Ruff
|
+++ Ruff
|
||||||
@@ -1,26 +1,26 @@
|
@@ -3,24 +3,24 @@
|
||||||
@dataclass
|
tree_depth: int = 0
|
||||||
class DebugVisitor(Visitor[T]):
|
|
||||||
- tree_depth: int = 0
|
|
||||||
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
|
|
||||||
def visit_default(self, node: LN) -> Iterator[T]:
|
def visit_default(self, node: LN) -> Iterator[T]:
|
||||||
- indent = ' ' * (2 * self.tree_depth)
|
- indent = ' ' * (2 * self.tree_depth)
|
||||||
|
@ -79,13 +76,6 @@ class DebugVisitor(Visitor[T]):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def show(cls, code: str) -> None:
|
def show(cls, code: str) -> None:
|
||||||
@@ -28,5 +28,5 @@
|
|
||||||
|
|
||||||
Convenience method for debugging.
|
|
||||||
"""
|
|
||||||
- v: DebugVisitor[None] = DebugVisitor()
|
|
||||||
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
list(v.visit(lib2to3_parse(code)))
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ruff Output
|
## Ruff Output
|
||||||
|
@ -93,7 +83,7 @@ class DebugVisitor(Visitor[T]):
|
||||||
```py
|
```py
|
||||||
@dataclass
|
@dataclass
|
||||||
class DebugVisitor(Visitor[T]):
|
class DebugVisitor(Visitor[T]):
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
tree_depth: int = 0
|
||||||
|
|
||||||
def visit_default(self, node: LN) -> Iterator[T]:
|
def visit_default(self, node: LN) -> Iterator[T]:
|
||||||
indent = " " * (2 * self.tree_depth)
|
indent = " " * (2 * self.tree_depth)
|
||||||
|
@ -121,7 +111,7 @@ class DebugVisitor(Visitor[T]):
|
||||||
|
|
||||||
Convenience method for debugging.
|
Convenience method for debugging.
|
||||||
"""
|
"""
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
v: DebugVisitor[None] = DebugVisitor()
|
||||||
list(v.visit(lib2to3_parse(code)))
|
list(v.visit(lib2to3_parse(code)))
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -67,13 +67,13 @@ def eggs() -> Union[str, int]: ...
|
||||||
- def BMethod(self, arg: List[str]) -> None: ...
|
- def BMethod(self, arg: List[str]) -> None: ...
|
||||||
+ def BMethod(self, arg: List[str]) -> None:
|
+ def BMethod(self, arg: List[str]) -> None:
|
||||||
+ ...
|
+ ...
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+class C:
|
||||||
|
+ ...
|
||||||
|
|
||||||
-class C: ...
|
-class C: ...
|
||||||
|
|
||||||
+class C:
|
|
||||||
+ ...
|
|
||||||
+
|
|
||||||
+
|
|
||||||
@hmm
|
@hmm
|
||||||
-class D: ...
|
-class D: ...
|
||||||
+class D:
|
+class D:
|
||||||
|
@ -89,29 +89,28 @@ def eggs() -> Union[str, int]: ...
|
||||||
-def foo() -> None: ...
|
-def foo() -> None: ...
|
||||||
+def foo() -> None:
|
+def foo() -> None:
|
||||||
+ ...
|
+ ...
|
||||||
+
|
|
||||||
+
|
-class F(A, C): ...
|
||||||
|
|
||||||
|
-def spam() -> None: ...
|
||||||
+class F(A, C):
|
+class F(A, C):
|
||||||
+ ...
|
+ ...
|
||||||
+
|
+
|
||||||
+
|
+
|
||||||
+def spam() -> None:
|
+def spam() -> None:
|
||||||
+ ...
|
+ ...
|
||||||
|
+
|
||||||
-class F(A, C): ...
|
+
|
||||||
|
|
||||||
-def spam() -> None: ...
|
|
||||||
@overload
|
@overload
|
||||||
-def spam(arg: str) -> str: ...
|
-def spam(arg: str) -> str: ...
|
||||||
+def spam(arg: str) -> str:
|
+def spam(arg: str) -> str:
|
||||||
+ ...
|
+ ...
|
||||||
+
|
+
|
||||||
+
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
|
|
||||||
-var: int = 1
|
var: int = 1
|
||||||
|
|
||||||
-def eggs() -> Union[str, int]: ...
|
-def eggs() -> Union[str, int]: ...
|
||||||
|
+
|
||||||
+def eggs() -> Union[str, int]:
|
+def eggs() -> Union[str, int]:
|
||||||
+ ...
|
+ ...
|
||||||
```
|
```
|
||||||
|
@ -172,7 +171,7 @@ def spam(arg: str) -> str:
|
||||||
...
|
...
|
||||||
|
|
||||||
|
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
var: int = 1
|
||||||
|
|
||||||
|
|
||||||
def eggs() -> Union[str, int]:
|
def eggs() -> Union[str, int]:
|
||||||
|
|
|
@ -417,7 +417,7 @@ long_unmergable_string_with_pragma = (
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z,
|
z,
|
||||||
@@ -243,21 +225,13 @@
|
@@ -243,7 +225,7 @@
|
||||||
func_with_bad_parens(
|
func_with_bad_parens(
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
|
@ -426,24 +426,7 @@ long_unmergable_string_with_pragma = (
|
||||||
z,
|
z,
|
||||||
)
|
)
|
||||||
|
|
||||||
-annotated_variable: Final = (
|
@@ -271,10 +253,10 @@
|
||||||
- "This is a large "
|
|
||||||
- + STRING
|
|
||||||
- + " that has been "
|
|
||||||
- + CONCATENATED
|
|
||||||
- + "using the '+' operator."
|
|
||||||
-)
|
|
||||||
-annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
|
||||||
-annotated_variable: Literal[
|
|
||||||
- "fakse_literal"
|
|
||||||
-] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
|
|
||||||
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
|
|
||||||
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
|
|
||||||
@@ -271,10 +245,10 @@
|
|
||||||
|
|
||||||
|
|
||||||
def foo():
|
def foo():
|
||||||
|
@ -692,9 +675,17 @@ func_with_bad_parens(
|
||||||
z,
|
z,
|
||||||
)
|
)
|
||||||
|
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
annotated_variable: Final = (
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
"This is a large "
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
+ STRING
|
||||||
|
+ " that has been "
|
||||||
|
+ CONCATENATED
|
||||||
|
+ "using the '+' operator."
|
||||||
|
)
|
||||||
|
annotated_variable: Final = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
||||||
|
annotated_variable: Literal[
|
||||||
|
"fakse_literal"
|
||||||
|
] = "This is a large string that has a type annotation attached to it. A type annotation should NOT stop a long string from being wrapped."
|
||||||
|
|
||||||
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
|
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\"
|
||||||
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
|
backslashes = "This is a really long string with \"embedded\" double quotes and 'single' quotes that also handles checking for an even number of backslashes \\\\"
|
||||||
|
|
|
@ -147,8 +147,7 @@ match bar1:
|
||||||
|
|
||||||
|
|
||||||
match = 1
|
match = 1
|
||||||
-case: int = re.match(something)
|
case: int = re.match(something)
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
|
|
||||||
-match re.match(case):
|
-match re.match(case):
|
||||||
- case type("match", match):
|
- case type("match", match):
|
||||||
|
@ -214,21 +213,19 @@ match bar1:
|
||||||
|
|
||||||
- case case:
|
- case case:
|
||||||
- pass
|
- pass
|
||||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
-
|
||||||
|
-
|
||||||
|
|
||||||
-match match:
|
-match match:
|
||||||
- case case:
|
- case case:
|
||||||
- pass
|
- pass
|
||||||
|
-
|
||||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
|
|
||||||
|
|
||||||
-match a, *b(), c:
|
-match a, *b(), c:
|
||||||
- case d, *f, g:
|
- case d, *f, g:
|
||||||
- pass
|
- pass
|
||||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
|
||||||
|
|
||||||
|
|
||||||
|
-
|
||||||
-match something:
|
-match something:
|
||||||
- case {
|
- case {
|
||||||
- "key": key as key_1,
|
- "key": key as key_1,
|
||||||
|
@ -237,28 +234,30 @@ match bar1:
|
||||||
- pass
|
- pass
|
||||||
- case {"maybe": something(complicated as this) as that}:
|
- case {"maybe": something(complicated as this) as that}:
|
||||||
- pass
|
- pass
|
||||||
-
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
|
|
||||||
|
|
||||||
-match something:
|
-match something:
|
||||||
- case 1 as a:
|
- case 1 as a:
|
||||||
- pass
|
- pass
|
||||||
|
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
|
|
||||||
- case 2 as b, 3 as c:
|
- case 2 as b, 3 as c:
|
||||||
- pass
|
- pass
|
||||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
|
||||||
|
|
||||||
- case 4 as d, (5 as e), (6 | 7 as g), *h:
|
- case 4 as d, (5 as e), (6 | 7 as g), *h:
|
||||||
- pass
|
- pass
|
||||||
|
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
|
|
||||||
|
|
||||||
-
|
|
||||||
-match bar1:
|
-match bar1:
|
||||||
- case Foo(aa=Callable() as aa, bb=int()):
|
- case Foo(aa=Callable() as aa, bb=int()):
|
||||||
- print(bar1.aa, bar1.bb)
|
- print(bar1.aa, bar1.bb)
|
||||||
- case _:
|
- case _:
|
||||||
- print("no match", "\n")
|
- print("no match", "\n")
|
||||||
-
|
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
-
|
|
||||||
|
|
||||||
-match bar1:
|
-match bar1:
|
||||||
- case Foo(
|
- case Foo(
|
||||||
- normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
|
- normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
|
||||||
|
@ -276,7 +275,7 @@ NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
|
|
||||||
|
|
||||||
match = 1
|
match = 1
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
case: int = re.match(something)
|
||||||
|
|
||||||
NOT_YET_IMPLEMENTED_StmtMatch
|
NOT_YET_IMPLEMENTED_StmtMatch
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ def t():
|
||||||
```diff
|
```diff
|
||||||
--- Black
|
--- Black
|
||||||
+++ Ruff
|
+++ Ruff
|
||||||
@@ -8,14 +8,14 @@
|
@@ -8,7 +8,7 @@
|
||||||
|
|
||||||
def starred_yield():
|
def starred_yield():
|
||||||
my_list = ["value2", "value3"]
|
my_list = ["value2", "value3"]
|
||||||
|
@ -40,16 +40,12 @@ def t():
|
||||||
|
|
||||||
|
|
||||||
# all right hand side expressions allowed in regular assignments are now also allowed in
|
# all right hand side expressions allowed in regular assignments are now also allowed in
|
||||||
# annotated assignments
|
@@ -18,4 +18,4 @@
|
||||||
-a: Tuple[str, int] = "1", 2
|
|
||||||
-a: Tuple[int, ...] = b, *c, d
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
|
|
||||||
|
|
||||||
def t():
|
def t():
|
||||||
- a: str = yield "a"
|
- a: str = yield "a"
|
||||||
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
|
+ a: str = NOT_YET_IMPLEMENTED_ExprYield
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ruff Output
|
## Ruff Output
|
||||||
|
@ -70,12 +66,12 @@ def starred_yield():
|
||||||
|
|
||||||
# all right hand side expressions allowed in regular assignments are now also allowed in
|
# all right hand side expressions allowed in regular assignments are now also allowed in
|
||||||
# annotated assignments
|
# annotated assignments
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
a: Tuple[str, int] = "1", 2
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
a: Tuple[int, ...] = b, *c, d
|
||||||
|
|
||||||
|
|
||||||
def t():
|
def t():
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
a: str = NOT_YET_IMPLEMENTED_ExprYield
|
||||||
```
|
```
|
||||||
|
|
||||||
## Black Output
|
## Black Output
|
||||||
|
|
|
@ -357,38 +357,7 @@ last_call()
|
||||||
) # note: no trailing comma pre-3.6
|
) # note: no trailing comma pre-3.6
|
||||||
call(*gidgets[:2])
|
call(*gidgets[:2])
|
||||||
call(a, *gidgets[:2])
|
call(a, *gidgets[:2])
|
||||||
@@ -131,34 +131,28 @@
|
@@ -152,13 +152,13 @@
|
||||||
tuple[str, ...]
|
|
||||||
tuple[str, int, float, dict[str, int]]
|
|
||||||
tuple[
|
|
||||||
- str,
|
|
||||||
- int,
|
|
||||||
- float,
|
|
||||||
- dict[str, int],
|
|
||||||
+ (
|
|
||||||
+ str,
|
|
||||||
+ int,
|
|
||||||
+ float,
|
|
||||||
+ dict[str, int],
|
|
||||||
+ )
|
|
||||||
]
|
|
||||||
-very_long_variable_name_filters: t.List[
|
|
||||||
- t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]],
|
|
||||||
-]
|
|
||||||
-xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
|
|
||||||
- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
|
||||||
-)
|
|
||||||
-xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
|
|
||||||
- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
|
||||||
-)
|
|
||||||
-xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod(
|
|
||||||
- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
|
||||||
-) # type: ignore
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign # type: ignore
|
|
||||||
slice[0]
|
|
||||||
slice[0:1]
|
slice[0:1]
|
||||||
slice[0:1:2]
|
slice[0:1:2]
|
||||||
slice[:]
|
slice[:]
|
||||||
|
@ -405,7 +374,7 @@ last_call()
|
||||||
numpy[0, :]
|
numpy[0, :]
|
||||||
numpy[:, i]
|
numpy[:, i]
|
||||||
numpy[0, :2]
|
numpy[0, :2]
|
||||||
@@ -172,7 +166,7 @@
|
@@ -172,7 +172,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]]
|
||||||
|
@ -414,7 +383,7 @@ last_call()
|
||||||
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)
|
||||||
{"2.7": dead, "3.7": long_live or die_hard}
|
{"2.7": dead, "3.7": long_live or die_hard}
|
||||||
@@ -181,10 +175,10 @@
|
@@ -181,10 +181,10 @@
|
||||||
(SomeName)
|
(SomeName)
|
||||||
SomeName
|
SomeName
|
||||||
(Good, Bad, Ugly)
|
(Good, Bad, Ugly)
|
||||||
|
@ -429,11 +398,10 @@ last_call()
|
||||||
(*starred,)
|
(*starred,)
|
||||||
{
|
{
|
||||||
"id": "1",
|
"id": "1",
|
||||||
@@ -207,25 +201,15 @@
|
@@ -208,24 +208,14 @@
|
||||||
)
|
|
||||||
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
|
what_is_up_with_those_new_coord_names = (coord_names | set(vars_to_create)) - set(
|
||||||
vars_to_remove
|
vars_to_remove
|
||||||
-)
|
)
|
||||||
-result = (
|
-result = (
|
||||||
- session.query(models.Customer.id)
|
- session.query(models.Customer.id)
|
||||||
- .filter(
|
- .filter(
|
||||||
|
@ -441,7 +409,7 @@ last_call()
|
||||||
- )
|
- )
|
||||||
- .order_by(models.Customer.id.asc())
|
- .order_by(models.Customer.id.asc())
|
||||||
- .all()
|
- .all()
|
||||||
)
|
-)
|
||||||
-result = (
|
-result = (
|
||||||
- session.query(models.Customer.id)
|
- session.query(models.Customer.id)
|
||||||
- .filter(
|
- .filter(
|
||||||
|
@ -463,7 +431,7 @@ last_call()
|
||||||
Ø = set()
|
Ø = set()
|
||||||
authors.łukasz.say_thanks()
|
authors.łukasz.say_thanks()
|
||||||
mapping = {
|
mapping = {
|
||||||
@@ -237,10 +221,10 @@
|
@@ -237,10 +227,10 @@
|
||||||
|
|
||||||
|
|
||||||
def gen():
|
def gen():
|
||||||
|
@ -478,7 +446,7 @@ last_call()
|
||||||
|
|
||||||
|
|
||||||
async def f():
|
async def f():
|
||||||
@@ -248,18 +232,22 @@
|
@@ -248,18 +238,22 @@
|
||||||
|
|
||||||
|
|
||||||
print(*[] or [1])
|
print(*[] or [1])
|
||||||
|
@ -509,7 +477,7 @@ last_call()
|
||||||
...
|
...
|
||||||
for i in call():
|
for i in call():
|
||||||
...
|
...
|
||||||
@@ -328,13 +316,18 @@
|
@@ -328,13 +322,18 @@
|
||||||
):
|
):
|
||||||
return True
|
return True
|
||||||
if (
|
if (
|
||||||
|
@ -531,7 +499,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 +335,8 @@
|
@@ -342,7 +341,8 @@
|
||||||
~aaaaaaaaaaaaaaaa.a
|
~aaaaaaaaaaaaaaaa.a
|
||||||
+ aaaaaaaaaaaaaaaa.b
|
+ aaaaaaaaaaaaaaaa.b
|
||||||
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
|
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
|
||||||
|
@ -679,17 +647,23 @@ dict[str, int]
|
||||||
tuple[str, ...]
|
tuple[str, ...]
|
||||||
tuple[str, int, float, dict[str, int]]
|
tuple[str, int, float, dict[str, int]]
|
||||||
tuple[
|
tuple[
|
||||||
(
|
str,
|
||||||
str,
|
int,
|
||||||
int,
|
float,
|
||||||
float,
|
dict[str, int],
|
||||||
dict[str, int],
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
very_long_variable_name_filters: t.List[
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
t.Tuple[str, t.Union[str, t.List[t.Optional[str]]]],
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
]
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign # type: ignore
|
xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
|
||||||
|
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
||||||
|
)
|
||||||
|
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore
|
||||||
|
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
||||||
|
)
|
||||||
|
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod(
|
||||||
|
sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)
|
||||||
|
) # type: ignore
|
||||||
slice[0]
|
slice[0]
|
||||||
slice[0:1]
|
slice[0:1]
|
||||||
slice[0:1:2]
|
slice[0:1:2]
|
||||||
|
|
|
@ -276,7 +276,7 @@ d={'a':1,
|
||||||
|
|
||||||
|
|
||||||
def spaces_types(
|
def spaces_types(
|
||||||
@@ -63,55 +76,54 @@
|
@@ -63,15 +76,15 @@
|
||||||
|
|
||||||
something = {
|
something = {
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -290,18 +290,12 @@ d={'a':1,
|
||||||
# fmt: off
|
# fmt: off
|
||||||
- 'some big and',
|
- 'some big and',
|
||||||
- 'complex subscript',
|
- 'complex subscript',
|
||||||
- # fmt: on
|
+ "some big and",
|
||||||
- goes + here,
|
+ "complex subscript",
|
||||||
- andhere,
|
# fmt: on
|
||||||
+ (
|
goes + here,
|
||||||
+ "some big and",
|
andhere,
|
||||||
+ "complex subscript",
|
@@ -80,38 +93,35 @@
|
||||||
+ # fmt: on
|
|
||||||
+ goes + here,
|
|
||||||
+ andhere,
|
|
||||||
+ )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def import_as_names():
|
def import_as_names():
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -351,7 +345,7 @@ d={'a':1,
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
|
|
||||||
@@ -132,10 +144,10 @@
|
@@ -132,10 +142,10 @@
|
||||||
"""Another known limitation."""
|
"""Another known limitation."""
|
||||||
# fmt: on
|
# fmt: on
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -366,7 +360,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 +165,7 @@
|
@@ -153,9 +163,7 @@
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -377,7 +371,7 @@ d={'a':1,
|
||||||
# fmt: on
|
# fmt: on
|
||||||
_type_comment_re = re.compile(
|
_type_comment_re = re.compile(
|
||||||
r"""
|
r"""
|
||||||
@@ -178,7 +188,7 @@
|
@@ -178,7 +186,7 @@
|
||||||
$
|
$
|
||||||
""",
|
""",
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -386,7 +380,7 @@ d={'a':1,
|
||||||
# fmt: on
|
# fmt: on
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -216,8 +226,7 @@
|
@@ -216,8 +224,7 @@
|
||||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||||
)
|
)
|
||||||
# fmt: off
|
# fmt: off
|
||||||
|
@ -488,13 +482,11 @@ something = {
|
||||||
def subscriptlist():
|
def subscriptlist():
|
||||||
atom[
|
atom[
|
||||||
# fmt: off
|
# fmt: off
|
||||||
(
|
"some big and",
|
||||||
"some big and",
|
"complex subscript",
|
||||||
"complex subscript",
|
# fmt: on
|
||||||
# fmt: on
|
goes + here,
|
||||||
goes + here,
|
andhere,
|
||||||
andhere,
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,348 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/function_trailing_comma.py
|
|
||||||
---
|
|
||||||
## Input
|
|
||||||
|
|
||||||
```py
|
|
||||||
def f(a,):
|
|
||||||
d = {'key': 'value',}
|
|
||||||
tup = (1,)
|
|
||||||
|
|
||||||
def f2(a,b,):
|
|
||||||
d = {'key': 'value', 'key2': 'value2',}
|
|
||||||
tup = (1,2,)
|
|
||||||
|
|
||||||
def f(a:int=1,):
|
|
||||||
call(arg={'explode': 'this',})
|
|
||||||
call2(arg=[1,2,3],)
|
|
||||||
x = {
|
|
||||||
"a": 1,
|
|
||||||
"b": 2,
|
|
||||||
}["a"]
|
|
||||||
if a == {"a": 1,"b": 2,"c": 3,"d": 4,"e": 5,"f": 6,"g": 7,"h": 8,}["a"]:
|
|
||||||
pass
|
|
||||||
|
|
||||||
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
|
|
||||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
||||||
]:
|
|
||||||
json = {"k": {"k2": {"k3": [1,]}}}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# The type annotation shouldn't get a trailing comma since that would change its type.
|
|
||||||
# Relevant bug report: https://github.com/psf/black/issues/2381.
|
|
||||||
def some_function_with_a_really_long_name() -> (
|
|
||||||
returning_a_deeply_nested_import_of_a_type_i_suppose
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def some_method_with_a_really_long_name(very_long_parameter_so_yeah: str, another_long_parameter: int) -> (
|
|
||||||
another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def func() -> (
|
|
||||||
also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(this_shouldn_t_get_a_trailing_comma_too)
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def func() -> ((also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
))
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Make sure inner one-element tuple won't explode
|
|
||||||
some_module.some_function(
|
|
||||||
argument1, (one_element_tuple,), argument4, argument5, argument6
|
|
||||||
)
|
|
||||||
|
|
||||||
# Inner trailing comma causes outer to explode
|
|
||||||
some_module.some_function(
|
|
||||||
argument1, (one, two,), argument4, argument5, argument6
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Differences
|
|
||||||
|
|
||||||
```diff
|
|
||||||
--- Black
|
|
||||||
+++ Ruff
|
|
||||||
@@ -52,9 +52,9 @@
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
-def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> (
|
|
||||||
- Set["xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]
|
|
||||||
-):
|
|
||||||
+def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
|
|
||||||
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
||||||
+]:
|
|
||||||
json = {
|
|
||||||
"k": {
|
|
||||||
"k2": {
|
|
||||||
@@ -80,18 +80,14 @@
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
-def func() -> (
|
|
||||||
- also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
- this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
- )
|
|
||||||
+def func() -> also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
+ this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
-def func() -> (
|
|
||||||
- also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
- this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
- )
|
|
||||||
+def func() -> also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
+ this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ruff Output
|
|
||||||
|
|
||||||
```py
|
|
||||||
def f(
|
|
||||||
a,
|
|
||||||
):
|
|
||||||
d = {
|
|
||||||
"key": "value",
|
|
||||||
}
|
|
||||||
tup = (1,)
|
|
||||||
|
|
||||||
|
|
||||||
def f2(
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
):
|
|
||||||
d = {
|
|
||||||
"key": "value",
|
|
||||||
"key2": "value2",
|
|
||||||
}
|
|
||||||
tup = (
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def f(
|
|
||||||
a: int = 1,
|
|
||||||
):
|
|
||||||
call(
|
|
||||||
arg={
|
|
||||||
"explode": "this",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
call2(
|
|
||||||
arg=[1, 2, 3],
|
|
||||||
)
|
|
||||||
x = {
|
|
||||||
"a": 1,
|
|
||||||
"b": 2,
|
|
||||||
}["a"]
|
|
||||||
if (
|
|
||||||
a
|
|
||||||
== {
|
|
||||||
"a": 1,
|
|
||||||
"b": 2,
|
|
||||||
"c": 3,
|
|
||||||
"d": 4,
|
|
||||||
"e": 5,
|
|
||||||
"f": 6,
|
|
||||||
"g": 7,
|
|
||||||
"h": 8,
|
|
||||||
}["a"]
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
|
|
||||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|
||||||
]:
|
|
||||||
json = {
|
|
||||||
"k": {
|
|
||||||
"k2": {
|
|
||||||
"k3": [
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# The type annotation shouldn't get a trailing comma since that would change its type.
|
|
||||||
# Relevant bug report: https://github.com/psf/black/issues/2381.
|
|
||||||
def some_function_with_a_really_long_name() -> (
|
|
||||||
returning_a_deeply_nested_import_of_a_type_i_suppose
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def some_method_with_a_really_long_name(
|
|
||||||
very_long_parameter_so_yeah: str, another_long_parameter: int
|
|
||||||
) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def func() -> also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def func() -> also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Make sure inner one-element tuple won't explode
|
|
||||||
some_module.some_function(
|
|
||||||
argument1, (one_element_tuple,), argument4, argument5, argument6
|
|
||||||
)
|
|
||||||
|
|
||||||
# Inner trailing comma causes outer to explode
|
|
||||||
some_module.some_function(
|
|
||||||
argument1,
|
|
||||||
(
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
),
|
|
||||||
argument4,
|
|
||||||
argument5,
|
|
||||||
argument6,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Output
|
|
||||||
|
|
||||||
```py
|
|
||||||
def f(
|
|
||||||
a,
|
|
||||||
):
|
|
||||||
d = {
|
|
||||||
"key": "value",
|
|
||||||
}
|
|
||||||
tup = (1,)
|
|
||||||
|
|
||||||
|
|
||||||
def f2(
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
):
|
|
||||||
d = {
|
|
||||||
"key": "value",
|
|
||||||
"key2": "value2",
|
|
||||||
}
|
|
||||||
tup = (
|
|
||||||
1,
|
|
||||||
2,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def f(
|
|
||||||
a: int = 1,
|
|
||||||
):
|
|
||||||
call(
|
|
||||||
arg={
|
|
||||||
"explode": "this",
|
|
||||||
}
|
|
||||||
)
|
|
||||||
call2(
|
|
||||||
arg=[1, 2, 3],
|
|
||||||
)
|
|
||||||
x = {
|
|
||||||
"a": 1,
|
|
||||||
"b": 2,
|
|
||||||
}["a"]
|
|
||||||
if (
|
|
||||||
a
|
|
||||||
== {
|
|
||||||
"a": 1,
|
|
||||||
"b": 2,
|
|
||||||
"c": 3,
|
|
||||||
"d": 4,
|
|
||||||
"e": 5,
|
|
||||||
"f": 6,
|
|
||||||
"g": 7,
|
|
||||||
"h": 8,
|
|
||||||
}["a"]
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> (
|
|
||||||
Set["xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]
|
|
||||||
):
|
|
||||||
json = {
|
|
||||||
"k": {
|
|
||||||
"k2": {
|
|
||||||
"k3": [
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
# The type annotation shouldn't get a trailing comma since that would change its type.
|
|
||||||
# Relevant bug report: https://github.com/psf/black/issues/2381.
|
|
||||||
def some_function_with_a_really_long_name() -> (
|
|
||||||
returning_a_deeply_nested_import_of_a_type_i_suppose
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def some_method_with_a_really_long_name(
|
|
||||||
very_long_parameter_so_yeah: str, another_long_parameter: int
|
|
||||||
) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def func() -> (
|
|
||||||
also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
)
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def func() -> (
|
|
||||||
also_super_long_type_annotation_that_may_cause_an_AST_related_crash_in_black(
|
|
||||||
this_shouldn_t_get_a_trailing_comma_too
|
|
||||||
)
|
|
||||||
):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
# Make sure inner one-element tuple won't explode
|
|
||||||
some_module.some_function(
|
|
||||||
argument1, (one_element_tuple,), argument4, argument5, argument6
|
|
||||||
)
|
|
||||||
|
|
||||||
# Inner trailing comma causes outer to explode
|
|
||||||
some_module.some_function(
|
|
||||||
argument1,
|
|
||||||
(
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
),
|
|
||||||
argument4,
|
|
||||||
argument5,
|
|
||||||
argument6,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -1,113 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/one_element_subscript.py
|
|
||||||
---
|
|
||||||
## Input
|
|
||||||
|
|
||||||
```py
|
|
||||||
# We should not treat the trailing comma
|
|
||||||
# in a single-element subscript.
|
|
||||||
a: tuple[int,]
|
|
||||||
b = tuple[int,]
|
|
||||||
|
|
||||||
# The magic comma still applies to multi-element subscripts.
|
|
||||||
c: tuple[int, int,]
|
|
||||||
d = tuple[int, int,]
|
|
||||||
|
|
||||||
# Magic commas still work as expected for non-subscripts.
|
|
||||||
small_list = [1,]
|
|
||||||
list_of_types = [tuple[int,],]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Differences
|
|
||||||
|
|
||||||
```diff
|
|
||||||
--- Black
|
|
||||||
+++ Ruff
|
|
||||||
@@ -1,16 +1,15 @@
|
|
||||||
# We should not treat the trailing comma
|
|
||||||
# in a single-element subscript.
|
|
||||||
-a: tuple[int,]
|
|
||||||
-b = tuple[int,]
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+b = tuple[(int,)]
|
|
||||||
|
|
||||||
# The magic comma still applies to multi-element subscripts.
|
|
||||||
-c: tuple[
|
|
||||||
- int,
|
|
||||||
- int,
|
|
||||||
-]
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
d = tuple[
|
|
||||||
- int,
|
|
||||||
- int,
|
|
||||||
+ (
|
|
||||||
+ int,
|
|
||||||
+ int,
|
|
||||||
+ )
|
|
||||||
]
|
|
||||||
|
|
||||||
# Magic commas still work as expected for non-subscripts.
|
|
||||||
@@ -18,5 +17,5 @@
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
list_of_types = [
|
|
||||||
- tuple[int,],
|
|
||||||
+ tuple[(int,)],
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ruff Output
|
|
||||||
|
|
||||||
```py
|
|
||||||
# We should not treat the trailing comma
|
|
||||||
# in a single-element subscript.
|
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
b = tuple[(int,)]
|
|
||||||
|
|
||||||
# The magic comma still applies to multi-element subscripts.
|
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
d = tuple[
|
|
||||||
(
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Magic commas still work as expected for non-subscripts.
|
|
||||||
small_list = [
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
list_of_types = [
|
|
||||||
tuple[(int,)],
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Output
|
|
||||||
|
|
||||||
```py
|
|
||||||
# We should not treat the trailing comma
|
|
||||||
# in a single-element subscript.
|
|
||||||
a: tuple[int,]
|
|
||||||
b = tuple[int,]
|
|
||||||
|
|
||||||
# The magic comma still applies to multi-element subscripts.
|
|
||||||
c: tuple[
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
]
|
|
||||||
d = tuple[
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
]
|
|
||||||
|
|
||||||
# Magic commas still work as expected for non-subscripts.
|
|
||||||
small_list = [
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
list_of_types = [
|
|
||||||
tuple[int,],
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -122,37 +122,6 @@ def foo() -> tuple[int, int, int,]:
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
@@ -99,22 +103,22 @@
|
|
||||||
return 2
|
|
||||||
|
|
||||||
|
|
||||||
-def foo() -> (
|
|
||||||
- tuple[
|
|
||||||
+def foo() -> tuple[
|
|
||||||
+ (
|
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
|
||||||
- ]
|
|
||||||
-):
|
|
||||||
+ )
|
|
||||||
+]:
|
|
||||||
return 2
|
|
||||||
|
|
||||||
|
|
||||||
# Magic trailing comma example
|
|
||||||
-def foo() -> (
|
|
||||||
- tuple[
|
|
||||||
+def foo() -> tuple[
|
|
||||||
+ (
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
- ]
|
|
||||||
-):
|
|
||||||
+ )
|
|
||||||
+]:
|
|
||||||
return 2
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Ruff Output
|
## Ruff Output
|
||||||
|
@ -263,24 +232,24 @@ def foo() -> tuple[int, int, int]:
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
def foo() -> tuple[
|
def foo() -> (
|
||||||
(
|
tuple[
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
||||||
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
|
||||||
)
|
]
|
||||||
]:
|
):
|
||||||
return 2
|
return 2
|
||||||
|
|
||||||
|
|
||||||
# Magic trailing comma example
|
# Magic trailing comma example
|
||||||
def foo() -> tuple[
|
def foo() -> (
|
||||||
(
|
tuple[
|
||||||
int,
|
int,
|
||||||
int,
|
int,
|
||||||
int,
|
int,
|
||||||
)
|
]
|
||||||
]:
|
):
|
||||||
return 2
|
return 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -1,227 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/skip_magic_trailing_comma.py
|
|
||||||
---
|
|
||||||
## Input
|
|
||||||
|
|
||||||
```py
|
|
||||||
# We should not remove the trailing comma in a single-element subscript.
|
|
||||||
a: tuple[int,]
|
|
||||||
b = tuple[int,]
|
|
||||||
|
|
||||||
# But commas in multiple element subscripts should be removed.
|
|
||||||
c: tuple[int, int,]
|
|
||||||
d = tuple[int, int,]
|
|
||||||
|
|
||||||
# Remove commas for non-subscripts.
|
|
||||||
small_list = [1,]
|
|
||||||
list_of_types = [tuple[int,],]
|
|
||||||
small_set = {1,}
|
|
||||||
set_of_types = {tuple[int,],}
|
|
||||||
|
|
||||||
# Except single element tuples
|
|
||||||
small_tuple = (1,)
|
|
||||||
|
|
||||||
# Trailing commas in multiple chained non-nested parens.
|
|
||||||
zero(
|
|
||||||
one,
|
|
||||||
).two(
|
|
||||||
three,
|
|
||||||
).four(
|
|
||||||
five,
|
|
||||||
)
|
|
||||||
|
|
||||||
func1(arg1).func2(arg2,).func3(arg3).func4(arg4,).func5(arg5)
|
|
||||||
|
|
||||||
(
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
d,
|
|
||||||
) = func1(
|
|
||||||
arg1
|
|
||||||
) and func2(arg2)
|
|
||||||
|
|
||||||
func(
|
|
||||||
argument1,
|
|
||||||
(
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
),
|
|
||||||
argument4,
|
|
||||||
argument5,
|
|
||||||
argument6,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Differences
|
|
||||||
|
|
||||||
```diff
|
|
||||||
--- Black
|
|
||||||
+++ Ruff
|
|
||||||
@@ -1,25 +1,58 @@
|
|
||||||
# We should not remove the trailing comma in a single-element subscript.
|
|
||||||
-a: tuple[int,]
|
|
||||||
-b = tuple[int,]
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+b = tuple[(int,)]
|
|
||||||
|
|
||||||
# But commas in multiple element subscripts should be removed.
|
|
||||||
-c: tuple[int, int]
|
|
||||||
-d = tuple[int, int]
|
|
||||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
+d = tuple[
|
|
||||||
+ (
|
|
||||||
+ int,
|
|
||||||
+ int,
|
|
||||||
+ )
|
|
||||||
+]
|
|
||||||
|
|
||||||
# Remove commas for non-subscripts.
|
|
||||||
-small_list = [1]
|
|
||||||
-list_of_types = [tuple[int,]]
|
|
||||||
+small_list = [
|
|
||||||
+ 1,
|
|
||||||
+]
|
|
||||||
+list_of_types = [
|
|
||||||
+ tuple[(int,)],
|
|
||||||
+]
|
|
||||||
small_set = {1}
|
|
||||||
-set_of_types = {tuple[int,]}
|
|
||||||
+set_of_types = {tuple[(int,)]}
|
|
||||||
|
|
||||||
# Except single element tuples
|
|
||||||
small_tuple = (1,)
|
|
||||||
|
|
||||||
# Trailing commas in multiple chained non-nested parens.
|
|
||||||
-zero(one).two(three).four(five)
|
|
||||||
+zero(
|
|
||||||
+ one,
|
|
||||||
+).two(
|
|
||||||
+ three,
|
|
||||||
+).four(
|
|
||||||
+ five,
|
|
||||||
+)
|
|
||||||
|
|
||||||
-func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5)
|
|
||||||
+func1(arg1).func2(
|
|
||||||
+ arg2,
|
|
||||||
+).func3(arg3).func4(
|
|
||||||
+ arg4,
|
|
||||||
+).func5(arg5)
|
|
||||||
|
|
||||||
-(a, b, c, d) = func1(arg1) and func2(arg2)
|
|
||||||
+(
|
|
||||||
+ a,
|
|
||||||
+ b,
|
|
||||||
+ c,
|
|
||||||
+ d,
|
|
||||||
+) = func1(arg1) and func2(arg2)
|
|
||||||
|
|
||||||
-func(argument1, (one, two), argument4, argument5, argument6)
|
|
||||||
+func(
|
|
||||||
+ argument1,
|
|
||||||
+ (
|
|
||||||
+ one,
|
|
||||||
+ two,
|
|
||||||
+ ),
|
|
||||||
+ argument4,
|
|
||||||
+ argument5,
|
|
||||||
+ argument6,
|
|
||||||
+)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ruff Output
|
|
||||||
|
|
||||||
```py
|
|
||||||
# We should not remove the trailing comma in a single-element subscript.
|
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
b = tuple[(int,)]
|
|
||||||
|
|
||||||
# But commas in multiple element subscripts should be removed.
|
|
||||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
|
||||||
d = tuple[
|
|
||||||
(
|
|
||||||
int,
|
|
||||||
int,
|
|
||||||
)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Remove commas for non-subscripts.
|
|
||||||
small_list = [
|
|
||||||
1,
|
|
||||||
]
|
|
||||||
list_of_types = [
|
|
||||||
tuple[(int,)],
|
|
||||||
]
|
|
||||||
small_set = {1}
|
|
||||||
set_of_types = {tuple[(int,)]}
|
|
||||||
|
|
||||||
# Except single element tuples
|
|
||||||
small_tuple = (1,)
|
|
||||||
|
|
||||||
# Trailing commas in multiple chained non-nested parens.
|
|
||||||
zero(
|
|
||||||
one,
|
|
||||||
).two(
|
|
||||||
three,
|
|
||||||
).four(
|
|
||||||
five,
|
|
||||||
)
|
|
||||||
|
|
||||||
func1(arg1).func2(
|
|
||||||
arg2,
|
|
||||||
).func3(arg3).func4(
|
|
||||||
arg4,
|
|
||||||
).func5(arg5)
|
|
||||||
|
|
||||||
(
|
|
||||||
a,
|
|
||||||
b,
|
|
||||||
c,
|
|
||||||
d,
|
|
||||||
) = func1(arg1) and func2(arg2)
|
|
||||||
|
|
||||||
func(
|
|
||||||
argument1,
|
|
||||||
(
|
|
||||||
one,
|
|
||||||
two,
|
|
||||||
),
|
|
||||||
argument4,
|
|
||||||
argument5,
|
|
||||||
argument6,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Output
|
|
||||||
|
|
||||||
```py
|
|
||||||
# We should not remove the trailing comma in a single-element subscript.
|
|
||||||
a: tuple[int,]
|
|
||||||
b = tuple[int,]
|
|
||||||
|
|
||||||
# But commas in multiple element subscripts should be removed.
|
|
||||||
c: tuple[int, int]
|
|
||||||
d = tuple[int, int]
|
|
||||||
|
|
||||||
# Remove commas for non-subscripts.
|
|
||||||
small_list = [1]
|
|
||||||
list_of_types = [tuple[int,]]
|
|
||||||
small_set = {1}
|
|
||||||
set_of_types = {tuple[int,]}
|
|
||||||
|
|
||||||
# Except single element tuples
|
|
||||||
small_tuple = (1,)
|
|
||||||
|
|
||||||
# Trailing commas in multiple chained non-nested parens.
|
|
||||||
zero(one).two(three).four(five)
|
|
||||||
|
|
||||||
func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5)
|
|
||||||
|
|
||||||
(a, b, c, d) = func1(arg1) and func2(arg2)
|
|
||||||
|
|
||||||
func(argument1, (one, two), argument4, argument5, argument6)
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/expression/annotated_assign.py
|
||||||
|
---
|
||||||
|
## Input
|
||||||
|
```py
|
||||||
|
a: string
|
||||||
|
|
||||||
|
b: string = "test"
|
||||||
|
|
||||||
|
b: list[
|
||||||
|
string,
|
||||||
|
int
|
||||||
|
] = [1, 2]
|
||||||
|
|
||||||
|
b: list[
|
||||||
|
string,
|
||||||
|
int,
|
||||||
|
] = [1, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output
|
||||||
|
```py
|
||||||
|
a: string
|
||||||
|
|
||||||
|
b: string = "test"
|
||||||
|
|
||||||
|
b: list[string, int] = [1, 2]
|
||||||
|
|
||||||
|
b: list[
|
||||||
|
string,
|
||||||
|
int,
|
||||||
|
] = [1, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue