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;
|
||||
|
||||
/// 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
|
||||
T: Format<PyFormatContext<'ast>>,
|
||||
{
|
||||
OptionalParentheses {
|
||||
ParenthesizeIfExpands {
|
||||
inner: Argument::new(content),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct OptionalParentheses<'a, 'ast> {
|
||||
pub(crate) struct ParenthesizeIfExpands<'a, '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<()> {
|
||||
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_python_ast::node::AstNode;
|
||||
|
@ -6,8 +6,10 @@ use ruff_python_ast::node::AstNode;
|
|||
use crate::comments::trailing_comments;
|
||||
use crate::context::NodeLevel;
|
||||
use crate::context::PyFormatContext;
|
||||
use crate::expression::expr_tuple::TupleParentheses;
|
||||
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::FormatNodeRule;
|
||||
|
@ -42,12 +44,31 @@ impl FormatNodeRule<ExprSubscript> for FormatExprSubscript {
|
|||
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!(
|
||||
f,
|
||||
[group(&format_args![
|
||||
[in_parentheses_only_group(&format_args![
|
||||
text("["),
|
||||
trailing_comments(dangling_comments),
|
||||
soft_block_indent(&slice.format()),
|
||||
soft_block_indent(&format_slice),
|
||||
text("]")
|
||||
])]
|
||||
)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::builders::optional_parentheses;
|
||||
use crate::builders::parenthesize_if_expands;
|
||||
use crate::comments::{dangling_comments, CommentLinePosition};
|
||||
use crate::expression::parentheses::{
|
||||
default_expression_needs_parentheses, parenthesized, NeedsParentheses, Parentheses,
|
||||
|
@ -17,6 +17,11 @@ pub enum TupleParentheses {
|
|||
Default,
|
||||
/// Effectively `Some(Parentheses)` in `Option<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
|
||||
///
|
||||
/// Normally, black keeps parentheses, but in the case of loops it formats
|
||||
|
@ -86,21 +91,32 @@ impl FormatNodeRule<ExprTuple> for FormatExprTuple {
|
|||
])]
|
||||
)
|
||||
}
|
||||
[single] => {
|
||||
// A single element tuple always needs parentheses and a trailing comma
|
||||
parenthesized("(", &format_args![single.format(), &text(",")], ")").fmt(f)
|
||||
}
|
||||
[single] => match self.parentheses {
|
||||
TupleParentheses::Subscript
|
||||
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
|
||||
// loops, see `TupleParentheses::StripInsideForLoop` doc comment.
|
||||
//
|
||||
// Unlike other expression parentheses, tuple parentheses are part of the range of the
|
||||
// tuple itself.
|
||||
elts if is_parenthesized(*range, elts, f)
|
||||
elts if is_parenthesized(*range, elts, f.context().source())
|
||||
&& self.parentheses != TupleParentheses::StripInsideForLoop =>
|
||||
{
|
||||
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
|
||||
fn is_parenthesized(
|
||||
tuple_range: TextRange,
|
||||
elts: &[Expr],
|
||||
f: &mut Formatter<PyFormatContext<'_>>,
|
||||
) -> bool {
|
||||
fn is_parenthesized(tuple_range: TextRange, elts: &[Expr], source: &str) -> bool {
|
||||
let parentheses = '(';
|
||||
let first_char = &f.context().source()[usize::from(tuple_range.start())..]
|
||||
.chars()
|
||||
.next();
|
||||
let first_char = &source[usize::from(tuple_range.start())..].chars().next();
|
||||
let Some(first_char) = first_char else {
|
||||
return false;
|
||||
};
|
||||
|
|
|
@ -2,17 +2,16 @@ use rustpython_parser::ast;
|
|||
use rustpython_parser::ast::{Expr, Operator};
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use crate::builders::optional_parentheses;
|
||||
use ruff_formatter::{
|
||||
format_args, FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions,
|
||||
};
|
||||
use crate::builders::parenthesize_if_expands;
|
||||
use ruff_formatter::{FormatOwnedWithRule, FormatRefWithRule, FormatRule, FormatRuleWithOptions};
|
||||
use ruff_python_ast::node::AnyNodeRef;
|
||||
use ruff_python_ast::visitor::preorder::{walk_expr, PreorderVisitor};
|
||||
|
||||
use crate::context::NodeLevel;
|
||||
use crate::expression::expr_tuple::TupleParentheses;
|
||||
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::prelude::*;
|
||||
|
@ -106,37 +105,9 @@ impl FormatRule<Expr, PyFormatContext<'_>> for FormatExpr {
|
|||
// Add optional parentheses. Ignore if the item renders parentheses itself.
|
||||
Parentheses::Optional => {
|
||||
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)
|
||||
} else {
|
||||
parenthesize_if_expands(&format_expr).fmt(f)
|
||||
}
|
||||
}
|
||||
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, ...)
|
||||
/// or if the expression gets parenthesized because it expands over multiple lines.
|
||||
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::expression::parentheses::Parentheses;
|
||||
use crate::prelude::*;
|
||||
|
@ -48,7 +48,7 @@ impl<'a> Format<PyFormatContext<'_>> for FormatString<'a> {
|
|||
let format_continuation = FormatStringContinuation::new(self.constant, 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 {
|
||||
format_continuation.fmt(f)
|
||||
}
|
||||
|
|
|
@ -280,11 +280,9 @@ if True:
|
|||
#[test]
|
||||
fn quick_test() {
|
||||
let src = r#"
|
||||
if [
|
||||
aaaaaa,
|
||||
BBBB,ccccccccc,ddddddd,eeeeeeeeee,ffffff
|
||||
] & bbbbbbbbbbbbbbbbbbddddddddddddddddddddddddddddbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:
|
||||
...
|
||||
def foo() -> tuple[int, int, int,]:
|
||||
return 2
|
||||
|
||||
"#;
|
||||
// Tokenize once
|
||||
let mut tokens = Vec::new();
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::{not_yet_implemented, FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::{write, Buffer, FormatResult};
|
||||
use crate::prelude::*;
|
||||
use crate::FormatNodeRule;
|
||||
use ruff_formatter::write;
|
||||
use rustpython_parser::ast::StmtAnnAssign;
|
||||
|
||||
#[derive(Default)]
|
||||
|
@ -7,6 +8,23 @@ pub struct FormatStmtAnnAssign;
|
|||
|
||||
impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
|
||||
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 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
|
||||
// replaced entirely
|
||||
//
|
||||
|
@ -22,32 +21,11 @@ impl FormatNodeRule<StmtAssign> for FormatStmtAssign {
|
|||
value,
|
||||
type_comment: _,
|
||||
} = item;
|
||||
write!(
|
||||
f,
|
||||
[
|
||||
LhsAssignList::new(targets),
|
||||
value.format().with_options(Parenthesize::IfBreaks)
|
||||
]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct LhsAssignList<'a> {
|
||||
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(),])?;
|
||||
for target in targets {
|
||||
write!(f, [target.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::expression::parentheses::Parenthesize;
|
||||
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
||||
|
@ -36,7 +36,7 @@ impl FormatNodeRule<StmtDelete> for FormatStmtDelete {
|
|||
}
|
||||
targets => {
|
||||
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::context::NodeLevel;
|
||||
use crate::expression::parentheses::Parenthesize;
|
||||
use crate::expression::parentheses::{optional_parentheses, Parenthesize};
|
||||
use crate::prelude::*;
|
||||
use crate::trivia::{lines_after, skip_trailing_trivia};
|
||||
use crate::FormatNodeRule;
|
||||
|
@ -97,9 +97,9 @@ impl FormatRule<AnyFunctionDefinition<'_>, PyFormatContext<'_>> for FormatAnyFun
|
|||
space(),
|
||||
text("->"),
|
||||
space(),
|
||||
return_annotation
|
||||
.format()
|
||||
.with_options(Parenthesize::IfBreaks)
|
||||
optional_parentheses(
|
||||
&return_annotation.format().with_options(Parenthesize::Never)
|
||||
)
|
||||
]
|
||||
)?;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::builders::{optional_parentheses, PyFormatterExtensions};
|
||||
use crate::builders::{parenthesize_if_expands, PyFormatterExtensions};
|
||||
use crate::{AsFormat, FormatNodeRule, PyFormatter};
|
||||
use ruff_formatter::prelude::{dynamic_text, format_with, space, text};
|
||||
use ruff_formatter::{write, Buffer, Format, FormatResult};
|
||||
|
@ -43,6 +43,6 @@ impl FormatNodeRule<StmtImportFrom> for FormatStmtImportFrom {
|
|||
.entries(names.iter().map(|name| (name, name.format())))
|
||||
.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 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::prelude::*;
|
||||
use crate::FormatNodeRule;
|
||||
|
@ -80,7 +80,7 @@ impl Format<PyFormatContext<'_>> for AnyStatementWith<'_> {
|
|||
[
|
||||
text("with"),
|
||||
space(),
|
||||
group(&optional_parentheses(&joined_items)),
|
||||
group(&parenthesize_if_expands(&joined_items)),
|
||||
text(":"),
|
||||
trailing_comments(dangling_comments),
|
||||
block_indent(&self.body().format())
|
||||
|
|
|
@ -11,7 +11,15 @@ fn black_compatibility() {
|
|||
let test_file = |input_path: &Path| {
|
||||
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| {
|
||||
panic!(
|
||||
"Formatting of {} to succeed but encountered error {err}",
|
||||
|
|
|
@ -44,11 +44,8 @@ class DebugVisitor(Visitor[T]):
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -1,26 +1,26 @@
|
||||
@dataclass
|
||||
class DebugVisitor(Visitor[T]):
|
||||
- tree_depth: int = 0
|
||||
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
@@ -3,24 +3,24 @@
|
||||
tree_depth: int = 0
|
||||
|
||||
def visit_default(self, node: LN) -> Iterator[T]:
|
||||
- indent = ' ' * (2 * self.tree_depth)
|
||||
|
@ -79,13 +76,6 @@ class DebugVisitor(Visitor[T]):
|
|||
|
||||
@classmethod
|
||||
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
|
||||
|
@ -93,7 +83,7 @@ class DebugVisitor(Visitor[T]):
|
|||
```py
|
||||
@dataclass
|
||||
class DebugVisitor(Visitor[T]):
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
tree_depth: int = 0
|
||||
|
||||
def visit_default(self, node: LN) -> Iterator[T]:
|
||||
indent = " " * (2 * self.tree_depth)
|
||||
|
@ -121,7 +111,7 @@ class DebugVisitor(Visitor[T]):
|
|||
|
||||
Convenience method for debugging.
|
||||
"""
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
v: DebugVisitor[None] = DebugVisitor()
|
||||
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:
|
||||
+ ...
|
||||
+
|
||||
+
|
||||
+class C:
|
||||
+ ...
|
||||
|
||||
-class C: ...
|
||||
|
||||
+class C:
|
||||
+ ...
|
||||
+
|
||||
+
|
||||
@hmm
|
||||
-class D: ...
|
||||
+class D:
|
||||
|
@ -89,29 +89,28 @@ def eggs() -> Union[str, int]: ...
|
|||
-def foo() -> None: ...
|
||||
+def foo() -> None:
|
||||
+ ...
|
||||
+
|
||||
+
|
||||
|
||||
-class F(A, C): ...
|
||||
|
||||
-def spam() -> None: ...
|
||||
+class F(A, C):
|
||||
+ ...
|
||||
+
|
||||
+
|
||||
+def spam() -> None:
|
||||
+ ...
|
||||
|
||||
-class F(A, C): ...
|
||||
|
||||
-def spam() -> None: ...
|
||||
+
|
||||
+
|
||||
@overload
|
||||
-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]:
|
||||
+ ...
|
||||
```
|
||||
|
@ -172,7 +171,7 @@ def spam(arg: str) -> str:
|
|||
...
|
||||
|
||||
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
var: int = 1
|
||||
|
||||
|
||||
def eggs() -> Union[str, int]:
|
||||
|
|
|
@ -417,7 +417,7 @@ long_unmergable_string_with_pragma = (
|
|||
x,
|
||||
y,
|
||||
z,
|
||||
@@ -243,21 +225,13 @@
|
||||
@@ -243,7 +225,7 @@
|
||||
func_with_bad_parens(
|
||||
x,
|
||||
y,
|
||||
|
@ -426,24 +426,7 @@ long_unmergable_string_with_pragma = (
|
|||
z,
|
||||
)
|
||||
|
||||
-annotated_variable: Final = (
|
||||
- "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 @@
|
||||
@@ -271,10 +253,10 @@
|
||||
|
||||
|
||||
def foo():
|
||||
|
@ -692,9 +675,17 @@ func_with_bad_parens(
|
|||
z,
|
||||
)
|
||||
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
annotated_variable: Final = (
|
||||
"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."
|
||||
|
||||
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
|
||||
-case: int = re.match(something)
|
||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
case: int = re.match(something)
|
||||
|
||||
-match re.match(case):
|
||||
- case type("match", match):
|
||||
|
@ -214,21 +213,19 @@ match bar1:
|
|||
|
||||
- case case:
|
||||
- pass
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
||||
-
|
||||
-
|
||||
-match match:
|
||||
- case case:
|
||||
- pass
|
||||
-
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
||||
-match a, *b(), c:
|
||||
- case d, *f, g:
|
||||
- pass
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
||||
-
|
||||
-match something:
|
||||
- case {
|
||||
- "key": key as key_1,
|
||||
|
@ -237,28 +234,30 @@ match bar1:
|
|||
- pass
|
||||
- case {"maybe": something(complicated as this) as that}:
|
||||
- pass
|
||||
-
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
||||
-match something:
|
||||
- case 1 as a:
|
||||
- pass
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
- case 2 as b, 3 as c:
|
||||
- pass
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
- case 4 as d, (5 as e), (6 | 7 as g), *h:
|
||||
- pass
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
||||
-
|
||||
-match bar1:
|
||||
- case Foo(aa=Callable() as aa, bb=int()):
|
||||
- print(bar1.aa, bar1.bb)
|
||||
- case _:
|
||||
- print("no match", "\n")
|
||||
-
|
||||
-
|
||||
+NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
||||
-match bar1:
|
||||
- case Foo(
|
||||
- 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
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
case: int = re.match(something)
|
||||
|
||||
NOT_YET_IMPLEMENTED_StmtMatch
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ def t():
|
|||
```diff
|
||||
--- Black
|
||||
+++ Ruff
|
||||
@@ -8,14 +8,14 @@
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
def starred_yield():
|
||||
my_list = ["value2", "value3"]
|
||||
|
@ -40,16 +40,12 @@ def t():
|
|||
|
||||
|
||||
# all right hand side expressions allowed in regular assignments are now also allowed in
|
||||
# annotated assignments
|
||||
-a: Tuple[str, int] = "1", 2
|
||||
-a: Tuple[int, ...] = b, *c, d
|
||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
+NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
@@ -18,4 +18,4 @@
|
||||
|
||||
|
||||
def t():
|
||||
- a: str = yield "a"
|
||||
+ NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
+ a: str = NOT_YET_IMPLEMENTED_ExprYield
|
||||
```
|
||||
|
||||
## Ruff Output
|
||||
|
@ -70,12 +66,12 @@ def starred_yield():
|
|||
|
||||
# all right hand side expressions allowed in regular assignments are now also allowed in
|
||||
# annotated assignments
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
a: Tuple[str, int] = "1", 2
|
||||
a: Tuple[int, ...] = b, *c, d
|
||||
|
||||
|
||||
def t():
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
a: str = NOT_YET_IMPLEMENTED_ExprYield
|
||||
```
|
||||
|
||||
## Black Output
|
||||
|
|
|
@ -357,38 +357,7 @@ last_call()
|
|||
) # note: no trailing comma pre-3.6
|
||||
call(*gidgets[:2])
|
||||
call(a, *gidgets[:2])
|
||||
@@ -131,34 +131,28 @@
|
||||
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]
|
||||
@@ -152,13 +152,13 @@
|
||||
slice[0:1]
|
||||
slice[0:1:2]
|
||||
slice[:]
|
||||
|
@ -405,7 +374,7 @@ last_call()
|
|||
numpy[0, :]
|
||||
numpy[:, i]
|
||||
numpy[0, :2]
|
||||
@@ -172,7 +166,7 @@
|
||||
@@ -172,7 +172,7 @@
|
||||
numpy[1 : c + 1, c]
|
||||
numpy[-(c + 1) :, d]
|
||||
numpy[:, l[-2]]
|
||||
|
@ -414,7 +383,7 @@ last_call()
|
|||
numpy[np.newaxis, :]
|
||||
(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}
|
||||
@@ -181,10 +175,10 @@
|
||||
@@ -181,10 +181,10 @@
|
||||
(SomeName)
|
||||
SomeName
|
||||
(Good, Bad, Ugly)
|
||||
|
@ -429,11 +398,10 @@ last_call()
|
|||
(*starred,)
|
||||
{
|
||||
"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(
|
||||
vars_to_remove
|
||||
-)
|
||||
)
|
||||
-result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
|
@ -441,7 +409,7 @@ last_call()
|
|||
- )
|
||||
- .order_by(models.Customer.id.asc())
|
||||
- .all()
|
||||
)
|
||||
-)
|
||||
-result = (
|
||||
- session.query(models.Customer.id)
|
||||
- .filter(
|
||||
|
@ -463,7 +431,7 @@ last_call()
|
|||
Ø = set()
|
||||
authors.łukasz.say_thanks()
|
||||
mapping = {
|
||||
@@ -237,10 +221,10 @@
|
||||
@@ -237,10 +227,10 @@
|
||||
|
||||
|
||||
def gen():
|
||||
|
@ -478,7 +446,7 @@ last_call()
|
|||
|
||||
|
||||
async def f():
|
||||
@@ -248,18 +232,22 @@
|
||||
@@ -248,18 +238,22 @@
|
||||
|
||||
|
||||
print(*[] or [1])
|
||||
|
@ -509,7 +477,7 @@ last_call()
|
|||
...
|
||||
for i in call():
|
||||
...
|
||||
@@ -328,13 +316,18 @@
|
||||
@@ -328,13 +322,18 @@
|
||||
):
|
||||
return True
|
||||
if (
|
||||
|
@ -531,7 +499,7 @@ last_call()
|
|||
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
|
||||
):
|
||||
return True
|
||||
@@ -342,7 +335,8 @@
|
||||
@@ -342,7 +341,8 @@
|
||||
~aaaaaaaaaaaaaaaa.a
|
||||
+ aaaaaaaaaaaaaaaa.b
|
||||
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
|
||||
|
@ -679,17 +647,23 @@ dict[str, int]
|
|||
tuple[str, ...]
|
||||
tuple[str, int, float, dict[str, int]]
|
||||
tuple[
|
||||
(
|
||||
str,
|
||||
int,
|
||||
float,
|
||||
dict[str, int],
|
||||
)
|
||||
str,
|
||||
int,
|
||||
float,
|
||||
dict[str, int],
|
||||
]
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign
|
||||
NOT_YET_IMPLEMENTED_StmtAnnAssign # type: ignore
|
||||
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
|
||||
slice[0]
|
||||
slice[0:1]
|
||||
slice[0:1:2]
|
||||
|
|
|
@ -276,7 +276,7 @@ d={'a':1,
|
|||
|
||||
|
||||
def spaces_types(
|
||||
@@ -63,55 +76,54 @@
|
||||
@@ -63,15 +76,15 @@
|
||||
|
||||
something = {
|
||||
# fmt: off
|
||||
|
@ -290,18 +290,12 @@ d={'a':1,
|
|||
# fmt: off
|
||||
- 'some big and',
|
||||
- 'complex subscript',
|
||||
- # fmt: on
|
||||
- goes + here,
|
||||
- andhere,
|
||||
+ (
|
||||
+ "some big and",
|
||||
+ "complex subscript",
|
||||
+ # fmt: on
|
||||
+ goes + here,
|
||||
+ andhere,
|
||||
+ )
|
||||
]
|
||||
|
||||
+ "some big and",
|
||||
+ "complex subscript",
|
||||
# fmt: on
|
||||
goes + here,
|
||||
andhere,
|
||||
@@ -80,38 +93,35 @@
|
||||
|
||||
def import_as_names():
|
||||
# fmt: off
|
||||
|
@ -351,7 +345,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
|
||||
|
||||
@@ -132,10 +144,10 @@
|
||||
@@ -132,10 +142,10 @@
|
||||
"""Another known limitation."""
|
||||
# fmt: on
|
||||
# fmt: off
|
||||
|
@ -366,7 +360,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
# fmt: off
|
||||
# ...but comments still get reformatted even though they should not be
|
||||
@@ -153,9 +165,7 @@
|
||||
@@ -153,9 +163,7 @@
|
||||
)
|
||||
)
|
||||
# fmt: off
|
||||
|
@ -377,7 +371,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
_type_comment_re = re.compile(
|
||||
r"""
|
||||
@@ -178,7 +188,7 @@
|
||||
@@ -178,7 +186,7 @@
|
||||
$
|
||||
""",
|
||||
# fmt: off
|
||||
|
@ -386,7 +380,7 @@ d={'a':1,
|
|||
# fmt: on
|
||||
)
|
||||
|
||||
@@ -216,8 +226,7 @@
|
||||
@@ -216,8 +224,7 @@
|
||||
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
|
||||
)
|
||||
# fmt: off
|
||||
|
@ -488,13 +482,11 @@ something = {
|
|||
def subscriptlist():
|
||||
atom[
|
||||
# fmt: off
|
||||
(
|
||||
"some big and",
|
||||
"complex subscript",
|
||||
# fmt: on
|
||||
goes + here,
|
||||
andhere,
|
||||
)
|
||||
"some big and",
|
||||
"complex subscript",
|
||||
# fmt: on
|
||||
goes + here,
|
||||
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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
@ -263,24 +232,24 @@ def foo() -> tuple[int, int, int]:
|
|||
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
|
||||
```
|
||||
|
||||
|
|
|
@ -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