formatter: Remove CST and old formatting (#4730)

This commit is contained in:
Micha Reiser 2023-05-31 08:27:23 +02:00 committed by GitHub
parent d7a4999915
commit 06bcb85f81
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
85 changed files with 5335 additions and 13272 deletions

View file

@ -1,125 +0,0 @@
use crate::cst::visitor;
use crate::cst::visitor::Visitor;
use crate::cst::{
Alias, Arg, Body, BoolOp, CmpOp, Excepthandler, Expr, Keyword, Operator, Pattern, SliceIndex,
Stmt, UnaryOp,
};
use crate::trivia::{decorate_trivia, TriviaIndex, TriviaToken};
struct AttachmentVisitor {
index: TriviaIndex,
}
impl<'a> Visitor<'a> for AttachmentVisitor {
fn visit_body(&mut self, body: &'a mut Body) {
let trivia = self.index.body.remove(&body.id());
if let Some(comments) = trivia {
body.trivia.extend(comments);
}
visitor::walk_body(self, body);
}
fn visit_stmt(&mut self, stmt: &'a mut Stmt) {
let trivia = self.index.stmt.remove(&stmt.id());
if let Some(comments) = trivia {
stmt.trivia.extend(comments);
}
visitor::walk_stmt(self, stmt);
}
fn visit_expr(&mut self, expr: &'a mut Expr) {
let trivia = self.index.expr.remove(&expr.id());
if let Some(comments) = trivia {
expr.trivia.extend(comments);
}
visitor::walk_expr(self, expr);
}
fn visit_alias(&mut self, alias: &'a mut Alias) {
let trivia = self.index.alias.remove(&alias.id());
if let Some(comments) = trivia {
alias.trivia.extend(comments);
}
visitor::walk_alias(self, alias);
}
fn visit_arg(&mut self, arg: &'a mut Arg) {
let trivia = self.index.arg.remove(&arg.id());
if let Some(comments) = trivia {
arg.trivia.extend(comments);
}
visitor::walk_arg(self, arg);
}
fn visit_excepthandler(&mut self, excepthandler: &'a mut Excepthandler) {
let trivia = self.index.excepthandler.remove(&excepthandler.id());
if let Some(comments) = trivia {
excepthandler.trivia.extend(comments);
}
visitor::walk_excepthandler(self, excepthandler);
}
fn visit_keyword(&mut self, keyword: &'a mut Keyword) {
let trivia = self.index.keyword.remove(&keyword.id());
if let Some(comments) = trivia {
keyword.trivia.extend(comments);
}
visitor::walk_keyword(self, keyword);
}
fn visit_bool_op(&mut self, bool_op: &'a mut BoolOp) {
let trivia = self.index.bool_op.remove(&bool_op.id());
if let Some(comments) = trivia {
bool_op.trivia.extend(comments);
}
visitor::walk_bool_op(self, bool_op);
}
fn visit_unary_op(&mut self, unary_op: &'a mut UnaryOp) {
let trivia = self.index.unary_op.remove(&unary_op.id());
if let Some(comments) = trivia {
unary_op.trivia.extend(comments);
}
visitor::walk_unary_op(self, unary_op);
}
fn visit_cmp_op(&mut self, cmp_op: &'a mut CmpOp) {
let trivia = self.index.cmp_op.remove(&cmp_op.id());
if let Some(comments) = trivia {
cmp_op.trivia.extend(comments);
}
visitor::walk_cmp_op(self, cmp_op);
}
fn visit_operator(&mut self, operator: &'a mut Operator) {
let trivia = self.index.operator.remove(&operator.id());
if let Some(comments) = trivia {
operator.trivia.extend(comments);
}
visitor::walk_operator(self, operator);
}
fn visit_slice_index(&mut self, slice_index: &'a mut SliceIndex) {
let trivia = self.index.slice_index.remove(&slice_index.id());
if let Some(comments) = trivia {
slice_index.trivia.extend(comments);
}
visitor::walk_slice_index(self, slice_index);
}
fn visit_pattern(&mut self, pattern: &'a mut Pattern) {
let trivia = self.index.pattern.remove(&pattern.id());
if let Some(comments) = trivia {
pattern.trivia.extend(comments);
}
visitor::walk_pattern(self, pattern);
}
}
pub(crate) fn attach(python_cst: &mut [Stmt], trivia: Vec<TriviaToken>) {
let index = decorate_trivia(trivia, python_cst);
let mut visitor = AttachmentVisitor { index };
for stmt in python_cst {
visitor.visit_stmt(stmt);
}
}

View file

@ -1,138 +0,0 @@
use ruff_python_ast::source_code::Locator;
use ruff_text_size::{TextLen, TextRange, TextSize};
use rustpython_parser::ast::Ranged;
/// Return `true` if the given string is a radix literal (e.g., `0b101`).
pub(crate) fn is_radix_literal(content: &str) -> bool {
content.starts_with("0b")
|| content.starts_with("0o")
|| content.starts_with("0x")
|| content.starts_with("0B")
|| content.starts_with("0O")
|| content.starts_with("0X")
}
/// Find the first token in the given range that satisfies the given predicate.
pub(crate) fn find_tok(
range: TextRange,
locator: &Locator,
f: impl Fn(rustpython_parser::Tok) -> bool,
) -> TextRange {
for (tok, tok_range) in rustpython_parser::lexer::lex_starts_at(
&locator.contents()[range],
rustpython_parser::Mode::Module,
range.start(),
)
.flatten()
{
if f(tok) {
return tok_range;
}
}
unreachable!("Failed to find token in range {:?}", range)
}
/// Expand the range of a compound statement.
///
/// `location` is the start of the compound statement (e.g., the `if` in `if x:`).
/// `end_location` is the end of the last statement in the body.
pub(crate) fn expand_indented_block(
location: TextSize,
end_location: TextSize,
locator: &Locator,
) -> TextRange {
let contents = locator.contents();
// Find the colon, which indicates the end of the header.
let mut nesting = 0;
let mut colon = None;
for (tok, tok_range) in rustpython_parser::lexer::lex_starts_at(
&contents[TextRange::new(location, end_location)],
rustpython_parser::Mode::Module,
location,
)
.flatten()
{
match tok {
rustpython_parser::Tok::Colon if nesting == 0 => {
colon = Some(tok_range.start());
break;
}
rustpython_parser::Tok::Lpar
| rustpython_parser::Tok::Lsqb
| rustpython_parser::Tok::Lbrace => nesting += 1,
rustpython_parser::Tok::Rpar
| rustpython_parser::Tok::Rsqb
| rustpython_parser::Tok::Rbrace => nesting -= 1,
_ => {}
}
}
let colon_location = colon.unwrap();
// From here, we have two options: simple statement or compound statement.
let indent = rustpython_parser::lexer::lex_starts_at(
&contents[TextRange::new(colon_location, end_location)],
rustpython_parser::Mode::Module,
colon_location,
)
.flatten()
.find_map(|(tok, range)| match tok {
rustpython_parser::Tok::Indent => Some(range.end()),
_ => None,
});
let line_end = locator.line_end(end_location);
let Some(indent_end) = indent else {
// Simple statement: from the colon to the end of the line.
return TextRange::new(colon_location, line_end);
};
let indent_width = indent_end - locator.line_start(indent_end);
// Compound statement: from the colon to the end of the block.
// For each line that follows, check that there's no content up to the expected indent.
let mut offset = TextSize::default();
let mut line_offset = TextSize::default();
// Issue, body goes to far.. it includes the whole try including the catch
let rest = &contents[usize::from(line_end)..];
for (relative_offset, c) in rest.char_indices() {
if line_offset < indent_width && !c.is_whitespace() {
break; // Found end of block
}
match c {
'\n' | '\r' => {
// Ignore empty lines
if line_offset > TextSize::from(0) {
offset = TextSize::try_from(relative_offset).unwrap() + TextSize::from(1);
}
line_offset = TextSize::from(0);
}
_ => {
line_offset += c.text_len();
}
}
}
// Reached end of file
let end = if line_offset >= indent_width {
contents.text_len()
} else {
line_end + offset
};
TextRange::new(colon_location, end)
}
/// Return true if the `orelse` block of an `if` statement is an `elif` statement.
pub(crate) fn is_elif(orelse: &[rustpython_parser::ast::Stmt], locator: &Locator) -> bool {
if orelse.len() == 1 && matches!(orelse[0], rustpython_parser::ast::Stmt::If { .. }) {
let contents = locator.after(orelse[0].start());
if contents.starts_with("elif") {
return true;
}
}
false
}

File diff suppressed because it is too large Load diff

View file

@ -1,634 +0,0 @@
use rustpython_parser::ast::Constant;
use crate::cst::{
Alias, Arg, Arguments, Body, BoolOp, CmpOp, Comprehension, Excepthandler, ExcepthandlerKind,
Expr, ExprContext, ExprKind, Keyword, MatchCase, Operator, Pattern, PatternKind, SliceIndex,
SliceIndexKind, Stmt, StmtKind, UnaryOp, Withitem,
};
pub(crate) trait Visitor<'a> {
fn visit_stmt(&mut self, stmt: &'a mut Stmt) {
walk_stmt(self, stmt);
}
fn visit_annotation(&mut self, expr: &'a mut Expr) {
walk_expr(self, expr);
}
fn visit_expr(&mut self, expr: &'a mut Expr) {
walk_expr(self, expr);
}
fn visit_constant(&mut self, constant: &'a mut Constant) {
walk_constant(self, constant);
}
fn visit_expr_context(&mut self, expr_context: &'a mut ExprContext) {
walk_expr_context(self, expr_context);
}
fn visit_bool_op(&mut self, bool_op: &'a mut BoolOp) {
walk_bool_op(self, bool_op);
}
fn visit_operator(&mut self, operator: &'a mut Operator) {
walk_operator(self, operator);
}
fn visit_unary_op(&mut self, unary_op: &'a mut UnaryOp) {
walk_unary_op(self, unary_op);
}
fn visit_cmp_op(&mut self, cmp_op: &'a mut CmpOp) {
walk_cmp_op(self, cmp_op);
}
fn visit_comprehension(&mut self, comprehension: &'a mut Comprehension) {
walk_comprehension(self, comprehension);
}
fn visit_excepthandler(&mut self, excepthandler: &'a mut Excepthandler) {
walk_excepthandler(self, excepthandler);
}
fn visit_slice_index(&mut self, slice_index: &'a mut SliceIndex) {
walk_slice_index(self, slice_index);
}
fn visit_format_spec(&mut self, format_spec: &'a mut Expr) {
walk_expr(self, format_spec);
}
fn visit_arguments(&mut self, arguments: &'a mut Arguments) {
walk_arguments(self, arguments);
}
fn visit_arg(&mut self, arg: &'a mut Arg) {
walk_arg(self, arg);
}
fn visit_keyword(&mut self, keyword: &'a mut Keyword) {
walk_keyword(self, keyword);
}
fn visit_alias(&mut self, alias: &'a mut Alias) {
walk_alias(self, alias);
}
fn visit_withitem(&mut self, withitem: &'a mut Withitem) {
walk_withitem(self, withitem);
}
fn visit_match_case(&mut self, match_case: &'a mut MatchCase) {
walk_match_case(self, match_case);
}
fn visit_pattern(&mut self, pattern: &'a mut Pattern) {
walk_pattern(self, pattern);
}
fn visit_body(&mut self, body: &'a mut Body) {
walk_body(self, body);
}
}
pub(crate) fn walk_body<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, body: &'a mut Body) {
for stmt in &mut body.node {
visitor.visit_stmt(stmt);
}
}
pub(crate) fn walk_stmt<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, stmt: &'a mut Stmt) {
match &mut stmt.node {
StmtKind::FunctionDef {
args,
body,
decorator_list,
returns,
..
} => {
visitor.visit_arguments(args);
for expr in decorator_list {
visitor.visit_expr(expr);
}
for expr in returns {
visitor.visit_annotation(expr);
}
visitor.visit_body(body);
}
StmtKind::AsyncFunctionDef {
args,
body,
decorator_list,
returns,
..
} => {
visitor.visit_arguments(args);
for expr in decorator_list {
visitor.visit_expr(expr);
}
for expr in returns {
visitor.visit_annotation(expr);
}
visitor.visit_body(body);
}
StmtKind::ClassDef {
bases,
keywords,
body,
decorator_list,
..
} => {
for expr in bases {
visitor.visit_expr(expr);
}
for keyword in keywords {
visitor.visit_keyword(keyword);
}
for expr in decorator_list {
visitor.visit_expr(expr);
}
visitor.visit_body(body);
}
StmtKind::Return { value } => {
if let Some(expr) = value {
visitor.visit_expr(expr);
}
}
StmtKind::Delete { targets } => {
for expr in targets {
visitor.visit_expr(expr);
}
}
StmtKind::Assign { targets, value, .. } => {
visitor.visit_expr(value);
for expr in targets {
visitor.visit_expr(expr);
}
}
StmtKind::AugAssign { target, op, value } => {
visitor.visit_expr(target);
visitor.visit_operator(op);
visitor.visit_expr(value);
}
StmtKind::AnnAssign {
target,
annotation,
value,
..
} => {
visitor.visit_annotation(annotation);
if let Some(expr) = value {
visitor.visit_expr(expr);
}
visitor.visit_expr(target);
}
StmtKind::For {
target,
iter,
body,
orelse,
..
} => {
visitor.visit_expr(iter);
visitor.visit_expr(target);
visitor.visit_body(body);
if let Some(orelse) = orelse {
visitor.visit_body(orelse);
}
}
StmtKind::AsyncFor {
target,
iter,
body,
orelse,
..
} => {
visitor.visit_expr(iter);
visitor.visit_expr(target);
visitor.visit_body(body);
if let Some(orelse) = orelse {
visitor.visit_body(orelse);
}
}
StmtKind::While { test, body, orelse } => {
visitor.visit_expr(test);
visitor.visit_body(body);
if let Some(orelse) = orelse {
visitor.visit_body(orelse);
}
}
StmtKind::If {
test, body, orelse, ..
} => {
visitor.visit_expr(test);
visitor.visit_body(body);
if let Some(orelse) = orelse {
visitor.visit_body(orelse);
}
}
StmtKind::With { items, body, .. } => {
for withitem in items {
visitor.visit_withitem(withitem);
}
visitor.visit_body(body);
}
StmtKind::AsyncWith { items, body, .. } => {
for withitem in items {
visitor.visit_withitem(withitem);
}
visitor.visit_body(body);
}
StmtKind::Match { subject, cases } => {
visitor.visit_expr(subject);
for match_case in cases {
visitor.visit_match_case(match_case);
}
}
StmtKind::Raise { exc, cause } => {
if let Some(expr) = exc {
visitor.visit_expr(expr);
};
if let Some(expr) = cause {
visitor.visit_expr(expr);
};
}
StmtKind::Try {
body,
handlers,
orelse,
finalbody,
} => {
visitor.visit_body(body);
for excepthandler in handlers {
visitor.visit_excepthandler(excepthandler);
}
if let Some(orelse) = orelse {
visitor.visit_body(orelse);
}
if let Some(finalbody) = finalbody {
visitor.visit_body(finalbody);
}
}
StmtKind::TryStar {
body,
handlers,
orelse,
finalbody,
} => {
visitor.visit_body(body);
for excepthandler in handlers {
visitor.visit_excepthandler(excepthandler);
}
if let Some(orelse) = orelse {
visitor.visit_body(orelse);
}
if let Some(finalbody) = finalbody {
visitor.visit_body(finalbody);
}
}
StmtKind::Assert { test, msg } => {
visitor.visit_expr(test);
if let Some(expr) = msg {
visitor.visit_expr(expr);
}
}
StmtKind::Import { names } => {
for alias in names {
visitor.visit_alias(alias);
}
}
StmtKind::ImportFrom { names, .. } => {
for alias in names {
visitor.visit_alias(alias);
}
}
StmtKind::Global { .. } => {}
StmtKind::Nonlocal { .. } => {}
StmtKind::Expr { value } => visitor.visit_expr(value),
StmtKind::Pass => {}
StmtKind::Break => {}
StmtKind::Continue => {}
}
}
pub(crate) fn walk_expr<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, expr: &'a mut Expr) {
match &mut expr.node {
ExprKind::BoolOp { ops, values } => {
for op in ops {
visitor.visit_bool_op(op);
}
for value in values {
visitor.visit_expr(value);
}
}
ExprKind::NamedExpr { target, value } => {
visitor.visit_expr(target);
visitor.visit_expr(value);
}
ExprKind::BinOp { left, op, right } => {
visitor.visit_expr(left);
visitor.visit_operator(op);
visitor.visit_expr(right);
}
ExprKind::UnaryOp { op, operand } => {
visitor.visit_unary_op(op);
visitor.visit_expr(operand);
}
ExprKind::Lambda { args, body } => {
visitor.visit_arguments(args);
visitor.visit_expr(body);
}
ExprKind::IfExp { test, body, orelse } => {
visitor.visit_expr(test);
visitor.visit_expr(body);
visitor.visit_expr(orelse);
}
ExprKind::Dict { keys, values } => {
for expr in keys.iter_mut().flatten() {
visitor.visit_expr(expr);
}
for expr in values {
visitor.visit_expr(expr);
}
}
ExprKind::Set { elts } => {
for expr in elts {
visitor.visit_expr(expr);
}
}
ExprKind::ListComp { elt, generators } => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
}
visitor.visit_expr(elt);
}
ExprKind::SetComp { elt, generators } => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
}
visitor.visit_expr(elt);
}
ExprKind::DictComp {
key,
value,
generators,
} => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
}
visitor.visit_expr(key);
visitor.visit_expr(value);
}
ExprKind::GeneratorExp { elt, generators } => {
for comprehension in generators {
visitor.visit_comprehension(comprehension);
}
visitor.visit_expr(elt);
}
ExprKind::Await { value } => visitor.visit_expr(value),
ExprKind::Yield { value } => {
if let Some(expr) = value {
visitor.visit_expr(expr);
}
}
ExprKind::YieldFrom { value } => visitor.visit_expr(value),
ExprKind::Compare {
left,
ops,
comparators,
} => {
visitor.visit_expr(left);
for cmpop in ops {
visitor.visit_cmp_op(cmpop);
}
for expr in comparators {
visitor.visit_expr(expr);
}
}
ExprKind::Call {
func,
args,
keywords,
} => {
visitor.visit_expr(func);
for expr in args {
visitor.visit_expr(expr);
}
for keyword in keywords {
visitor.visit_keyword(keyword);
}
}
ExprKind::FormattedValue {
value, format_spec, ..
} => {
visitor.visit_expr(value);
if let Some(expr) = format_spec {
visitor.visit_format_spec(expr);
}
}
ExprKind::JoinedStr { values } => {
for expr in values {
visitor.visit_expr(expr);
}
}
ExprKind::Constant { value, .. } => visitor.visit_constant(value),
ExprKind::Attribute { value, ctx, .. } => {
visitor.visit_expr(value);
visitor.visit_expr_context(ctx);
}
ExprKind::Subscript { value, slice, ctx } => {
visitor.visit_expr(value);
visitor.visit_expr(slice);
visitor.visit_expr_context(ctx);
}
ExprKind::Starred { value, ctx } => {
visitor.visit_expr(value);
visitor.visit_expr_context(ctx);
}
ExprKind::Name { ctx, .. } => {
visitor.visit_expr_context(ctx);
}
ExprKind::List { elts, ctx } => {
for expr in elts {
visitor.visit_expr(expr);
}
visitor.visit_expr_context(ctx);
}
ExprKind::Tuple { elts, ctx } => {
for expr in elts {
visitor.visit_expr(expr);
}
visitor.visit_expr_context(ctx);
}
ExprKind::Slice { lower, upper, step } => {
visitor.visit_slice_index(lower);
visitor.visit_slice_index(upper);
if let Some(expr) = step {
visitor.visit_slice_index(expr);
}
}
}
}
pub(crate) fn walk_constant<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
constant: &'a mut Constant,
) {
if let Constant::Tuple(constants) = constant {
for constant in constants {
visitor.visit_constant(constant);
}
}
}
pub(crate) fn walk_comprehension<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
comprehension: &'a mut Comprehension,
) {
visitor.visit_expr(&mut comprehension.iter);
visitor.visit_expr(&mut comprehension.target);
for expr in &mut comprehension.ifs {
visitor.visit_expr(expr);
}
}
pub(crate) fn walk_excepthandler<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
excepthandler: &'a mut Excepthandler,
) {
match &mut excepthandler.node {
ExcepthandlerKind::ExceptHandler { type_, body, .. } => {
if let Some(expr) = type_ {
visitor.visit_expr(expr);
}
visitor.visit_body(body);
}
}
}
pub(crate) fn walk_slice_index<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
slice_index: &'a mut SliceIndex,
) {
match &mut slice_index.node {
SliceIndexKind::Empty => {}
SliceIndexKind::Index { value } => {
visitor.visit_expr(value);
}
}
}
pub(crate) fn walk_arguments<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
arguments: &'a mut Arguments,
) {
for arg in &mut arguments.posonlyargs {
visitor.visit_arg(arg);
}
for arg in &mut arguments.args {
visitor.visit_arg(arg);
}
if let Some(arg) = &mut arguments.vararg {
visitor.visit_arg(arg);
}
for arg in &mut arguments.kwonlyargs {
visitor.visit_arg(arg);
}
for expr in &mut arguments.kw_defaults {
visitor.visit_expr(expr);
}
if let Some(arg) = &mut arguments.kwarg {
visitor.visit_arg(arg);
}
for expr in &mut arguments.defaults {
visitor.visit_expr(expr);
}
}
pub(crate) fn walk_arg<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, arg: &'a mut Arg) {
if let Some(expr) = &mut arg.node.annotation {
visitor.visit_annotation(expr);
}
}
pub(crate) fn walk_keyword<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, keyword: &'a mut Keyword) {
visitor.visit_expr(&mut keyword.node.value);
}
pub(crate) fn walk_withitem<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
withitem: &'a mut Withitem,
) {
visitor.visit_expr(&mut withitem.context_expr);
if let Some(expr) = &mut withitem.optional_vars {
visitor.visit_expr(expr);
}
}
pub(crate) fn walk_match_case<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
match_case: &'a mut MatchCase,
) {
visitor.visit_pattern(&mut match_case.pattern);
if let Some(expr) = &mut match_case.guard {
visitor.visit_expr(expr);
}
visitor.visit_body(&mut match_case.body);
}
pub(crate) fn walk_pattern<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, pattern: &'a mut Pattern) {
match &mut pattern.node {
PatternKind::MatchValue { value } => visitor.visit_expr(value),
PatternKind::MatchSingleton { value } => visitor.visit_constant(value),
PatternKind::MatchSequence { patterns } => {
for pattern in patterns {
visitor.visit_pattern(pattern);
}
}
PatternKind::MatchMapping { keys, patterns, .. } => {
for expr in keys {
visitor.visit_expr(expr);
}
for pattern in patterns {
visitor.visit_pattern(pattern);
}
}
PatternKind::MatchClass {
cls,
patterns,
kwd_patterns,
..
} => {
visitor.visit_expr(cls);
for pattern in patterns {
visitor.visit_pattern(pattern);
}
for pattern in kwd_patterns {
visitor.visit_pattern(pattern);
}
}
PatternKind::MatchStar { .. } => {}
PatternKind::MatchAs { pattern, .. } => {
if let Some(pattern) = pattern {
visitor.visit_pattern(pattern);
}
}
PatternKind::MatchOr { patterns } => {
for pattern in patterns {
visitor.visit_pattern(pattern);
}
}
}
}
#[allow(unused_variables)]
pub(crate) fn walk_expr_context<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
expr_context: &'a mut ExprContext,
) {
}
#[allow(unused_variables)]
pub(crate) fn walk_bool_op<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, bool_op: &'a mut BoolOp) {}
#[allow(unused_variables)]
pub(crate) fn walk_operator<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
operator: &'a mut Operator,
) {
}
#[allow(unused_variables)]
pub(crate) fn walk_unary_op<'a, V: Visitor<'a> + ?Sized>(
visitor: &mut V,
unary_op: &'a mut UnaryOp,
) {
}
#[allow(unused_variables)]
pub(crate) fn walk_cmp_op<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, cmp_op: &'a mut CmpOp) {}
#[allow(unused_variables)]
pub(crate) fn walk_alias<'a, V: Visitor<'a> + ?Sized>(visitor: &mut V, alias: &'a mut Alias) {}

View file

@ -1,33 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::Alias;
use crate::format::comments::end_of_line_comments;
pub(crate) struct FormatAlias<'a> {
item: &'a Alias,
}
impl AsFormat<ASTFormatContext<'_>> for Alias {
type Format<'a> = FormatAlias<'a>;
fn format(&self) -> Self::Format<'_> {
FormatAlias { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatAlias<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let alias = self.item;
write!(f, [dynamic_text(&alias.name, None)])?;
if let Some(asname) = &alias.asname {
write!(f, [text(" as ")])?;
write!(f, [dynamic_text(asname, None)])?;
}
write!(f, [end_of_line_comments(alias)])?;
Ok(())
}
}

View file

@ -1,32 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::Arg;
use crate::format::comments::end_of_line_comments;
pub(crate) struct FormatArg<'a> {
item: &'a Arg,
}
impl AsFormat<ASTFormatContext<'_>> for Arg {
type Format<'a> = FormatArg<'a>;
fn format(&self) -> Self::Format<'_> {
FormatArg { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatArg<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let arg = self.item;
write!(f, [dynamic_text(&arg.arg, None)])?;
if let Some(annotation) = &arg.annotation {
write!(f, [text(": ")])?;
write!(f, [annotation.format()])?;
}
write!(f, [end_of_line_comments(arg)])?;
Ok(())
}
}

View file

@ -1,121 +0,0 @@
use crate::prelude::*;
use ruff_formatter::{format_args, write, Format};
use crate::cst::Arguments;
pub(crate) struct FormatArguments<'a> {
item: &'a Arguments,
}
impl AsFormat<ASTFormatContext<'_>> for Arguments {
type Format<'a> = FormatArguments<'a>;
fn format(&self) -> Self::Format<'_> {
FormatArguments { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatArguments<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let args = self.item;
let mut first = true;
let defaults_start = args.posonlyargs.len() + args.args.len() - args.defaults.len();
for (i, arg) in args.posonlyargs.iter().chain(&args.args).enumerate() {
if !std::mem::take(&mut first) {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
}
write!(
f,
[group(&format_args![format_with(|f| {
write!(f, [arg.format()])?;
if let Some(i) = i.checked_sub(defaults_start) {
if arg.annotation.is_some() {
write!(f, [space()])?;
write!(f, [text("=")])?;
write!(f, [space()])?;
} else {
write!(f, [text("=")])?;
}
write!(f, [args.defaults[i].format()])?;
}
Ok(())
})])]
)?;
if i + 1 == args.posonlyargs.len() {
if !std::mem::take(&mut first) {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
}
write!(f, [text("/")])?;
}
}
if let Some(vararg) = &args.vararg {
if !std::mem::take(&mut first) {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
}
first = false;
write!(f, [text("*")])?;
write!(f, [vararg.format()])?;
} else if !args.kwonlyargs.is_empty() {
if !std::mem::take(&mut first) {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
}
first = false;
write!(f, [text("*")])?;
}
let defaults_start = args.kwonlyargs.len() - args.kw_defaults.len();
for (i, kwarg) in args.kwonlyargs.iter().enumerate() {
if !std::mem::take(&mut first) {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
}
write!(
f,
[group(&format_args![format_with(|f| {
write!(f, [kwarg.format()])?;
if let Some(default) = i
.checked_sub(defaults_start)
.and_then(|i| args.kw_defaults.get(i))
{
if kwarg.annotation.is_some() {
write!(f, [space()])?;
write!(f, [text("=")])?;
write!(f, [space()])?;
} else {
write!(f, [text("=")])?;
}
write!(f, [default.format()])?;
}
Ok(())
})])]
)?;
}
if let Some(kwarg) = &args.kwarg {
if !std::mem::take(&mut first) {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
}
write!(f, [text("**")])?;
write!(f, [kwarg.format()])?;
}
if !first {
write!(f, [if_group_breaks(&text(","))])?;
}
Ok(())
}
}

View file

@ -1,34 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::{BoolOp, BoolOpKind};
use crate::format::comments::{end_of_line_comments, leading_comments, trailing_comments};
pub(crate) struct FormatBoolOp<'a> {
item: &'a BoolOp,
}
impl AsFormat<ASTFormatContext<'_>> for BoolOp {
type Format<'a> = FormatBoolOp<'a>;
fn format(&self) -> Self::Format<'_> {
FormatBoolOp { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatBoolOp<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let bool_op = self.item;
write!(f, [leading_comments(bool_op)])?;
write!(
f,
[text(match bool_op.node {
BoolOpKind::And => "and",
BoolOpKind::Or => "or",
})]
)?;
write!(f, [end_of_line_comments(bool_op)])?;
write!(f, [trailing_comments(bool_op)])?;
Ok(())
}
}

View file

@ -1,101 +0,0 @@
use crate::prelude::*;
use ruff_formatter::{write, Format};
use ruff_text_size::TextRange;
use crate::cst::{Body, Stmt};
use crate::trivia::{Relationship, TriviaKind};
#[derive(Copy, Clone)]
pub(crate) struct Block<'a> {
body: &'a Body,
}
impl Format<ASTFormatContext<'_>> for Block<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
for (i, stmt) in self.body.iter().enumerate() {
if i > 0 {
write!(f, [hard_line_break()])?;
}
write!(f, [stmt.format()])?;
}
for trivia in &self.body.trivia {
if matches!(trivia.relationship, Relationship::Dangling) {
match trivia.kind {
TriviaKind::EmptyLine => {
write!(f, [empty_line()])?;
}
TriviaKind::OwnLineComment(range) => {
write!(f, [literal(range, ContainsNewlines::No), hard_line_break()])?;
}
_ => {}
}
}
}
Ok(())
}
}
#[inline]
pub(crate) fn block(body: &Body) -> Block {
Block { body }
}
#[derive(Copy, Clone)]
pub(crate) struct Statements<'a> {
suite: &'a [Stmt],
}
impl Format<ASTFormatContext<'_>> for Statements<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
for (i, stmt) in self.suite.iter().enumerate() {
if i > 0 {
write!(f, [hard_line_break()])?;
}
write!(f, [stmt.format()])?;
}
Ok(())
}
}
pub(crate) fn statements(suite: &[Stmt]) -> Statements {
Statements { suite }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) struct Literal {
range: TextRange,
}
impl Format<ASTFormatContext<'_>> for Literal {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
source_text_slice(self.range, ContainsNewlines::Detect).fmt(f)
}
}
#[inline]
pub(crate) const fn literal(
range: TextRange,
newlines: ContainsNewlines,
) -> SourceTextSliceBuilder {
source_text_slice(range, newlines)
}
pub(crate) const fn join_names(names: &[String]) -> JoinNames {
JoinNames { names }
}
pub(crate) struct JoinNames<'a> {
names: &'a [String],
}
impl<Context> Format<Context> for JoinNames<'_> {
fn fmt(&self, f: &mut Formatter<Context>) -> FormatResult<()> {
let mut join = f.join_with(text(", "));
for name in self.names {
join.entry(&dynamic_text(name, None));
}
join.finish()
}
}

View file

@ -1,42 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::{CmpOp, CmpOpKind};
use crate::format::comments::{end_of_line_comments, leading_comments, trailing_comments};
pub(crate) struct FormatCmpOp<'a> {
item: &'a CmpOp,
}
impl AsFormat<ASTFormatContext<'_>> for CmpOp {
type Format<'a> = FormatCmpOp<'a>;
fn format(&self) -> Self::Format<'_> {
FormatCmpOp { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatCmpOp<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let cmp_op = self.item;
write!(f, [leading_comments(cmp_op)])?;
write!(
f,
[text(match cmp_op.node {
CmpOpKind::Eq => "==",
CmpOpKind::NotEq => "!=",
CmpOpKind::Lt => "<",
CmpOpKind::LtE => "<=",
CmpOpKind::Gt => ">",
CmpOpKind::GtE => ">=",
CmpOpKind::Is => "is",
CmpOpKind::IsNot => "is not",
CmpOpKind::In => "in",
CmpOpKind::NotIn => "not in",
})]
)?;
write!(f, [end_of_line_comments(cmp_op)])?;
write!(f, [trailing_comments(cmp_op)])?;
Ok(())
}
}

View file

@ -1,117 +0,0 @@
use crate::prelude::*;
use ruff_formatter::{write, Format};
use crate::cst::Attributed;
use crate::format::builders::literal;
use crate::trivia::TriviaKind;
#[derive(Debug)]
pub(crate) struct LeadingComments<'a, T> {
item: &'a Attributed<T>,
}
impl<T> Format<ASTFormatContext<'_>> for LeadingComments<'_, T> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
for trivia in &self.item.trivia {
if trivia.relationship.is_leading() {
match trivia.kind {
TriviaKind::EmptyLine => {
write!(f, [empty_line()])?;
}
TriviaKind::OwnLineComment(range) => {
write!(f, [literal(range, ContainsNewlines::No), hard_line_break()])?;
}
_ => {}
}
}
}
Ok(())
}
}
#[inline]
pub(crate) const fn leading_comments<T>(item: &Attributed<T>) -> LeadingComments<'_, T> {
LeadingComments { item }
}
#[derive(Debug)]
pub(crate) struct TrailingComments<'a, T> {
item: &'a Attributed<T>,
}
impl<T> Format<ASTFormatContext<'_>> for TrailingComments<'_, T> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
for trivia in &self.item.trivia {
if trivia.relationship.is_trailing() {
match trivia.kind {
TriviaKind::EmptyLine => {
write!(f, [empty_line()])?;
}
TriviaKind::OwnLineComment(range) => {
write!(f, [literal(range, ContainsNewlines::No), hard_line_break()])?;
}
_ => {}
}
}
}
Ok(())
}
}
#[inline]
pub(crate) const fn trailing_comments<T>(item: &Attributed<T>) -> TrailingComments<'_, T> {
TrailingComments { item }
}
#[derive(Debug)]
pub(crate) struct EndOfLineComments<'a, T> {
item: &'a Attributed<T>,
}
impl<T> Format<ASTFormatContext<'_>> for EndOfLineComments<'_, T> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let mut first = true;
for range in self
.item
.trivia
.iter()
.filter_map(|trivia| trivia.kind.end_of_line_comment())
{
if std::mem::take(&mut first) {
write!(f, [line_suffix(&text(" "))])?;
}
write!(f, [line_suffix(&literal(range, ContainsNewlines::No))])?;
}
Ok(())
}
}
#[inline]
pub(crate) const fn end_of_line_comments<T>(item: &Attributed<T>) -> EndOfLineComments<'_, T> {
EndOfLineComments { item }
}
#[derive(Debug)]
pub(crate) struct DanglingComments<'a, T> {
item: &'a Attributed<T>,
}
impl<T> Format<ASTFormatContext<'_>> for DanglingComments<'_, T> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
for trivia in &self.item.trivia {
if trivia.relationship.is_dangling() {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [hard_line_break()])?;
write!(f, [literal(range, ContainsNewlines::No)])?;
write!(f, [hard_line_break()])?;
}
}
}
Ok(())
}
}
#[inline]
pub(crate) const fn dangling_comments<T>(item: &Attributed<T>) -> DanglingComments<'_, T> {
DanglingComments { item }
}

View file

@ -1,45 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::Comprehension;
pub(crate) struct FormatComprehension<'a> {
item: &'a Comprehension,
}
impl AsFormat<ASTFormatContext<'_>> for Comprehension {
type Format<'a> = FormatComprehension<'a>;
fn format(&self) -> Self::Format<'_> {
FormatComprehension { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatComprehension<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let comprehension = self.item;
write!(f, [soft_line_break_or_space()])?;
if comprehension.is_async > 0 {
write!(f, [text("async")])?;
write!(f, [space()])?;
}
write!(f, [text("for")])?;
write!(f, [space()])?;
// TODO(charlie): If this is an unparenthesized tuple, we need to avoid expanding it.
// Should this be set on the context?
write!(f, [group(&comprehension.target.format())])?;
write!(f, [space()])?;
write!(f, [text("in")])?;
write!(f, [space()])?;
write!(f, [group(&comprehension.iter.format())])?;
for if_clause in &comprehension.ifs {
write!(f, [soft_line_break_or_space()])?;
write!(f, [text("if")])?;
write!(f, [space()])?;
write!(f, [if_clause.format()])?;
}
Ok(())
}
}

View file

@ -1,39 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::{Excepthandler, ExcepthandlerKind};
use crate::format::builders::block;
use crate::format::comments::end_of_line_comments;
pub(crate) struct FormatExcepthandler<'a> {
item: &'a Excepthandler,
}
impl AsFormat<ASTFormatContext<'_>> for Excepthandler {
type Format<'a> = FormatExcepthandler<'a>;
fn format(&self) -> Self::Format<'_> {
FormatExcepthandler { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatExcepthandler<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let excepthandler = self.item;
let ExcepthandlerKind::ExceptHandler { type_, name, body } = &excepthandler.node;
write!(f, [text("except")])?;
if let Some(type_) = &type_ {
write!(f, [space(), type_.format()])?;
if let Some(name) = &name {
write!(f, [space(), text("as"), space(), dynamic_text(name, None)])?;
}
}
write!(f, [text(":")])?;
write!(f, [end_of_line_comments(excepthandler)])?;
write!(f, [block_indent(&block(body))])?;
Ok(())
}
}

View file

@ -1,892 +0,0 @@
#![allow(unused_variables, clippy::too_many_arguments)]
use rustpython_parser::ast::{Constant, ConversionFlag};
use crate::prelude::*;
use ruff_formatter::{format_args, write};
use crate::cst::{
Arguments, BoolOp, CmpOp, Comprehension, Expr, ExprKind, Keyword, Operator, OperatorKind,
SliceIndex, SliceIndexKind, UnaryOp, UnaryOpKind,
};
use crate::format::builders::literal;
use crate::format::comments::{dangling_comments, end_of_line_comments, leading_comments};
use crate::format::helpers::{is_self_closing, is_simple_power, is_simple_slice};
use crate::format::numbers::{complex_literal, float_literal, int_literal};
use crate::format::strings::string_literal;
use crate::trivia::{Parenthesize, TriviaKind};
pub(crate) struct FormatExpr<'a> {
item: &'a Expr,
}
fn format_starred(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: &Expr,
) -> FormatResult<()> {
write!(f, [text("*"), value.format()])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_name(f: &mut Formatter<ASTFormatContext>, expr: &Expr, _id: &str) -> FormatResult<()> {
write!(f, [literal(expr.range(), ContainsNewlines::No)])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_subscript(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: &Expr,
slice: &Expr,
) -> FormatResult<()> {
write!(f, [value.format()])?;
write!(f, [text("[")])?;
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [slice.format()])?;
// Apply any dangling comments.
for trivia in &expr.trivia {
if trivia.relationship.is_dangling() {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [expand_parent()])?;
write!(f, [hard_line_break()])?;
write!(f, [literal(range, ContainsNewlines::No)])?;
}
}
}
Ok(())
}))])]
)?;
write!(f, [text("]")])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_tuple(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
elts: &[Expr],
) -> FormatResult<()> {
// If we're already parenthesized, avoid adding any "mandatory" parentheses.
// TODO(charlie): We also need to parenthesize tuples on the right-hand side of an
// assignment if the target is exploded. And sometimes the tuple gets exploded, like
// if the LHS is an exploded list? Lots of edge cases here.
if elts.len() == 1 {
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [elts[0].format()])?;
write!(f, [text(",")])?;
Ok(())
}))])]
)?;
} else if !elts.is_empty() {
write!(
f,
[group(&format_with(
|f: &mut Formatter<ASTFormatContext>| {
if expr.parentheses.is_if_expanded() {
write!(f, [if_group_breaks(&text("("))])?;
}
if matches!(
expr.parentheses,
Parenthesize::IfExpanded | Parenthesize::Always
) {
write!(
f,
[soft_block_indent(&format_with(
|f: &mut Formatter<ASTFormatContext>| {
let magic_trailing_comma = expr
.trivia
.iter()
.any(|c| c.kind.is_magic_trailing_comma());
let is_unbroken =
!f.context().locator().contains_line_break(expr.range());
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, elt) in elts.iter().enumerate() {
write!(f, [elt.format()])?;
if i < elts.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
if magic_trailing_comma || is_unbroken {
write!(f, [if_group_breaks(&text(","))])?;
}
}
}
Ok(())
}
))]
)?;
} else {
let magic_trailing_comma =
expr.trivia.iter().any(|c| c.kind.is_magic_trailing_comma());
let is_unbroken = !f.context().locator().contains_line_break(expr.range());
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, elt) in elts.iter().enumerate() {
write!(f, [elt.format()])?;
if i < elts.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
if magic_trailing_comma || is_unbroken {
write!(f, [if_group_breaks(&text(","))])?;
}
}
}
}
if expr.parentheses.is_if_expanded() {
write!(f, [if_group_breaks(&text(")"))])?;
}
Ok(())
}
))]
)?;
}
Ok(())
}
fn format_slice(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
lower: &SliceIndex,
upper: &SliceIndex,
step: Option<&SliceIndex>,
) -> FormatResult<()> {
// https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#slices
let lower_is_simple = if let SliceIndexKind::Index { value } = &lower.node {
is_simple_slice(value)
} else {
true
};
let upper_is_simple = if let SliceIndexKind::Index { value } = &upper.node {
is_simple_slice(value)
} else {
true
};
let step_is_simple = step.map_or(true, |step| {
if let SliceIndexKind::Index { value } = &step.node {
is_simple_slice(value)
} else {
true
}
});
let is_simple = lower_is_simple && upper_is_simple && step_is_simple;
write!(
f,
[group(&format_with(|f| {
if let SliceIndexKind::Index { value } = &lower.node {
write!(f, [value.format()])?;
}
write!(f, [dangling_comments(lower)])?;
if matches!(lower.node, SliceIndexKind::Index { .. }) {
if !is_simple {
write!(f, [space()])?;
}
}
write!(f, [text(":")])?;
write!(f, [end_of_line_comments(lower)])?;
if let SliceIndexKind::Index { value } = &upper.node {
if !is_simple {
write!(f, [space()])?;
}
write!(f, [if_group_breaks(&soft_line_break())])?;
write!(f, [value.format()])?;
}
write!(f, [dangling_comments(upper)])?;
write!(f, [end_of_line_comments(upper)])?;
if let Some(step) = step {
if matches!(upper.node, SliceIndexKind::Index { .. }) {
if !is_simple {
write!(f, [space()])?;
}
}
write!(f, [text(":")])?;
if let SliceIndexKind::Index { value } = &step.node {
if !is_simple {
write!(f, [space()])?;
}
write!(f, [if_group_breaks(&soft_line_break())])?;
write!(f, [value.format()])?;
}
write!(f, [dangling_comments(step)])?;
write!(f, [end_of_line_comments(step)])?;
}
Ok(())
}))]
)?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_formatted_value(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: &Expr,
_conversion: ConversionFlag,
format_spec: Option<&Expr>,
) -> FormatResult<()> {
write!(f, [text("!")])?;
write!(f, [value.format()])?;
if let Some(format_spec) = format_spec {
write!(f, [text(":")])?;
write!(f, [format_spec.format()])?;
}
Ok(())
}
fn format_list(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
elts: &[Expr],
) -> FormatResult<()> {
write!(f, [text("[")])?;
if !elts.is_empty() {
let magic_trailing_comma = expr.trivia.iter().any(|c| c.kind.is_magic_trailing_comma());
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, elt) in elts.iter().enumerate() {
write!(f, [elt.format()])?;
if i < elts.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
Ok(())
}))])]
)?;
}
write!(f, [text("]")])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_set(f: &mut Formatter<ASTFormatContext>, expr: &Expr, elts: &[Expr]) -> FormatResult<()> {
if elts.is_empty() {
write!(f, [text("set()")])?;
Ok(())
} else {
write!(f, [text("{")])?;
if !elts.is_empty() {
let magic_trailing_comma = expr.trivia.iter().any(|c| c.kind.is_magic_trailing_comma());
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, elt) in elts.iter().enumerate() {
write!(f, [group(&format_args![elt.format()])])?;
if i < elts.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
if magic_trailing_comma {
write!(f, [if_group_breaks(&text(","))])?;
}
}
}
Ok(())
}))])]
)?;
}
write!(f, [text("}")])?;
Ok(())
}
}
fn format_call(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
func: &Expr,
args: &[Expr],
keywords: &[Keyword],
) -> FormatResult<()> {
write!(f, [func.format()])?;
if args.is_empty() && keywords.is_empty() {
write!(f, [text("(")])?;
write!(f, [text(")")])?;
write!(f, [end_of_line_comments(expr)])?;
} else {
write!(f, [text("(")])?;
write!(f, [end_of_line_comments(expr)])?;
let magic_trailing_comma = expr.trivia.iter().any(|c| c.kind.is_magic_trailing_comma());
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, arg) in args.iter().enumerate() {
write!(f, [group(&format_args![arg.format()])])?;
if i < args.len() - 1 || !keywords.is_empty() {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
if magic_trailing_comma || (args.len() + keywords.len() > 1) {
write!(f, [if_group_breaks(&text(","))])?;
}
}
}
for (i, keyword) in keywords.iter().enumerate() {
write!(
f,
[group(&format_args![&format_with(|f| {
write!(f, [keyword.format()])?;
Ok(())
})])]
)?;
if i < keywords.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
if magic_trailing_comma || (args.len() + keywords.len() > 1) {
write!(f, [if_group_breaks(&text(","))])?;
}
}
}
write!(f, [dangling_comments(expr)])?;
Ok(())
}))])]
)?;
write!(f, [text(")")])?;
}
Ok(())
}
fn format_list_comp(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
elt: &Expr,
generators: &[Comprehension],
) -> FormatResult<()> {
write!(f, [text("[")])?;
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [elt.format()])?;
for generator in generators {
write!(f, [generator.format()])?;
}
Ok(())
}))])]
)?;
write!(f, [text("]")])?;
Ok(())
}
fn format_set_comp(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
elt: &Expr,
generators: &[Comprehension],
) -> FormatResult<()> {
write!(f, [text("{")])?;
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [elt.format()])?;
for generator in generators {
write!(f, [generator.format()])?;
}
Ok(())
}))])]
)?;
write!(f, [text("}")])?;
Ok(())
}
fn format_dict_comp(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
key: &Expr,
value: &Expr,
generators: &[Comprehension],
) -> FormatResult<()> {
write!(f, [text("{")])?;
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [key.format()])?;
write!(f, [text(":")])?;
write!(f, [space()])?;
write!(f, [value.format()])?;
for generator in generators {
write!(f, [generator.format()])?;
}
Ok(())
}))])]
)?;
write!(f, [text("}")])?;
Ok(())
}
fn format_generator_exp(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
elt: &Expr,
generators: &[Comprehension],
) -> FormatResult<()> {
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [elt.format()])?;
for generator in generators {
write!(f, [generator.format()])?;
}
Ok(())
}))])]
)?;
Ok(())
}
fn format_await(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: &Expr,
) -> FormatResult<()> {
write!(f, [text("await")])?;
write!(f, [space()])?;
if is_self_closing(value) {
write!(f, [group(&format_args![value.format()])])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_args![value.format()]),
if_group_breaks(&text(")")),
])]
)?;
}
Ok(())
}
fn format_yield(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: Option<&Expr>,
) -> FormatResult<()> {
write!(f, [text("yield")])?;
if let Some(value) = value {
write!(f, [space()])?;
if is_self_closing(value) {
write!(f, [group(&format_args![value.format()])])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_args![value.format()]),
if_group_breaks(&text(")")),
])]
)?;
}
}
Ok(())
}
fn format_yield_from(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: &Expr,
) -> FormatResult<()> {
write!(
f,
[group(&format_args![soft_block_indent(&format_with(|f| {
write!(f, [text("yield")])?;
write!(f, [space()])?;
write!(f, [text("from")])?;
write!(f, [space()])?;
if is_self_closing(value) {
write!(f, [value.format()])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_args![value.format()]),
if_group_breaks(&text(")")),
])]
)?;
}
Ok(())
})),])]
)?;
Ok(())
}
fn format_compare(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
left: &Expr,
ops: &[CmpOp],
comparators: &[Expr],
) -> FormatResult<()> {
write!(f, [group(&format_args![left.format()])])?;
for (i, op) in ops.iter().enumerate() {
write!(f, [soft_line_break_or_space()])?;
write!(f, [op.format()])?;
write!(f, [space()])?;
write!(f, [group(&format_args![comparators[i].format()])])?;
}
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_joined_str(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
_values: &[Expr],
) -> FormatResult<()> {
write!(f, [literal(expr.range(), ContainsNewlines::Detect)])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_constant(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
constant: &Constant,
_kind: Option<&str>,
) -> FormatResult<()> {
match constant {
Constant::Ellipsis => write!(f, [text("...")])?,
Constant::None => write!(f, [text("None")])?,
Constant::Bool(value) => {
if *value {
write!(f, [text("True")])?;
} else {
write!(f, [text("False")])?;
}
}
Constant::Int(_) => write!(f, [int_literal(expr.range())])?,
Constant::Float(_) => write!(f, [float_literal(expr.range())])?,
Constant::Str(_) => write!(f, [string_literal(expr)])?,
Constant::Bytes(_) => write!(f, [string_literal(expr)])?,
Constant::Complex { .. } => write!(f, [complex_literal(expr.range())])?,
Constant::Tuple(_) => unreachable!("Constant::Tuple should be handled by format_tuple"),
}
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_dict(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
keys: &[Option<Expr>],
values: &[Expr],
) -> FormatResult<()> {
write!(f, [text("{")])?;
if !keys.is_empty() {
let magic_trailing_comma = expr.trivia.iter().any(|c| c.kind.is_magic_trailing_comma());
write!(
f,
[soft_block_indent(&format_with(|f| {
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, (k, v)) in keys.iter().zip(values).enumerate() {
if let Some(k) = k {
write!(f, [k.format()])?;
write!(f, [text(":")])?;
write!(f, [space()])?;
if is_self_closing(v) {
write!(f, [v.format()])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_args![v.format()]),
if_group_breaks(&text(")")),
])]
)?;
}
} else {
write!(f, [text("**")])?;
if is_self_closing(v) {
write!(f, [v.format()])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_args![v.format()]),
if_group_breaks(&text(")")),
])]
)?;
}
}
if i < keys.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
Ok(())
}))]
)?;
}
write!(f, [text("}")])?;
Ok(())
}
fn format_attribute(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
value: &Expr,
attr: &str,
) -> FormatResult<()> {
write!(f, [value.format()])?;
write!(f, [text(".")])?;
write!(f, [dynamic_text(attr, None)])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_named_expr(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
target: &Expr,
value: &Expr,
) -> FormatResult<()> {
write!(f, [target.format()])?;
write!(f, [text(":=")])?;
write!(f, [space()])?;
write!(f, [group(&format_args![value.format()])])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_bool_op(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
ops: &[BoolOp],
values: &[Expr],
) -> FormatResult<()> {
write!(f, [group(&format_args![values[0].format()])])?;
for (op, value) in ops.iter().zip(&values[1..]) {
write!(f, [soft_line_break_or_space()])?;
write!(f, [op.format()])?;
write!(f, [space()])?;
write!(f, [group(&format_args![value.format()])])?;
}
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_bin_op(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
left: &Expr,
op: &Operator,
right: &Expr,
) -> FormatResult<()> {
// https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#line-breaks-binary-operators
let is_simple =
matches!(op.node, OperatorKind::Pow) && is_simple_power(left) && is_simple_power(right);
write!(f, [left.format()])?;
if !is_simple {
write!(f, [soft_line_break_or_space()])?;
}
write!(f, [op.format()])?;
if !is_simple {
write!(f, [space()])?;
}
write!(f, [group(&right.format())])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_unary_op(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
op: &UnaryOp,
operand: &Expr,
) -> FormatResult<()> {
write!(f, [op.format()])?;
// TODO(charlie): Do this in the normalization pass.
if !matches!(op.node, UnaryOpKind::Not)
&& matches!(
operand.node,
ExprKind::BoolOp { .. } | ExprKind::Compare { .. } | ExprKind::BinOp { .. }
)
{
let parenthesized = operand.parentheses.is_always();
if !parenthesized {
write!(f, [text("(")])?;
}
write!(f, [operand.format()])?;
if !parenthesized {
write!(f, [text(")")])?;
}
} else {
write!(f, [operand.format()])?;
}
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_lambda(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
args: &Arguments,
body: &Expr,
) -> FormatResult<()> {
write!(f, [text("lambda")])?;
if !args.args.is_empty() || args.kwarg.is_some() || args.vararg.is_some() {
write!(f, [space()])?;
write!(f, [args.format()])?;
}
write!(f, [text(":")])?;
write!(f, [space()])?;
write!(f, [body.format()])?;
write!(f, [end_of_line_comments(expr)])?;
Ok(())
}
fn format_if_exp(
f: &mut Formatter<ASTFormatContext>,
expr: &Expr,
test: &Expr,
body: &Expr,
orelse: &Expr,
) -> FormatResult<()> {
write!(f, [group(&format_args![body.format()])])?;
write!(f, [soft_line_break_or_space()])?;
write!(f, [text("if")])?;
write!(f, [space()])?;
write!(f, [group(&format_args![test.format()])])?;
write!(f, [soft_line_break_or_space()])?;
write!(f, [text("else")])?;
write!(f, [space()])?;
write!(f, [group(&format_args![orelse.format()])])?;
Ok(())
}
impl Format<ASTFormatContext<'_>> for FormatExpr<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
if self.item.parentheses.is_always() {
write!(f, [text("(")])?;
}
write!(f, [leading_comments(self.item)])?;
match &self.item.node {
ExprKind::BoolOp { ops, values } => format_bool_op(f, self.item, ops, values),
ExprKind::NamedExpr { target, value } => format_named_expr(f, self.item, target, value),
ExprKind::BinOp { left, op, right } => format_bin_op(f, self.item, left, op, right),
ExprKind::UnaryOp { op, operand } => format_unary_op(f, self.item, op, operand),
ExprKind::Lambda { args, body } => format_lambda(f, self.item, args, body),
ExprKind::IfExp { test, body, orelse } => {
format_if_exp(f, self.item, test, body, orelse)
}
ExprKind::Dict { keys, values } => format_dict(f, self.item, keys, values),
ExprKind::Set { elts, .. } => format_set(f, self.item, elts),
ExprKind::ListComp { elt, generators } => {
format_list_comp(f, self.item, elt, generators)
}
ExprKind::SetComp { elt, generators } => format_set_comp(f, self.item, elt, generators),
ExprKind::DictComp {
key,
value,
generators,
} => format_dict_comp(f, self.item, key, value, generators),
ExprKind::GeneratorExp { elt, generators } => {
format_generator_exp(f, self.item, elt, generators)
}
ExprKind::Await { value } => format_await(f, self.item, value),
ExprKind::Yield { value } => format_yield(f, self.item, value.as_deref()),
ExprKind::YieldFrom { value } => format_yield_from(f, self.item, value),
ExprKind::Compare {
left,
ops,
comparators,
} => format_compare(f, self.item, left, ops, comparators),
ExprKind::Call {
func,
args,
keywords,
} => format_call(f, self.item, func, args, keywords),
ExprKind::JoinedStr { values } => format_joined_str(f, self.item, values),
ExprKind::Constant { value, kind } => {
format_constant(f, self.item, value, kind.as_deref())
}
ExprKind::Attribute { value, attr, .. } => format_attribute(f, self.item, value, attr),
ExprKind::Subscript { value, slice, .. } => {
format_subscript(f, self.item, value, slice)
}
ExprKind::Starred { value, .. } => format_starred(f, self.item, value),
ExprKind::Name { id, .. } => format_name(f, self.item, id),
ExprKind::List { elts, .. } => format_list(f, self.item, elts),
ExprKind::Tuple { elts, .. } => format_tuple(f, self.item, elts),
ExprKind::Slice { lower, upper, step } => {
format_slice(f, self.item, lower, upper, step.as_ref())
}
ExprKind::FormattedValue {
value,
conversion,
format_spec,
} => format_formatted_value(f, self.item, value, *conversion, format_spec.as_deref()),
}?;
// Any trailing comments come on the lines after.
for trivia in &self.item.trivia {
if trivia.relationship.is_trailing() {
if let TriviaKind::OwnLineComment(range) = trivia.kind {
write!(f, [expand_parent()])?;
write!(f, [literal(range, ContainsNewlines::No)])?;
write!(f, [hard_line_break()])?;
}
}
}
if self.item.parentheses.is_always() {
write!(f, [text(")")])?;
}
Ok(())
}
}
impl AsFormat<ASTFormatContext<'_>> for Expr {
type Format<'a> = FormatExpr<'a>;
fn format(&self) -> Self::Format<'_> {
FormatExpr { item: self }
}
}

View file

@ -1,87 +0,0 @@
use crate::cst::{Expr, ExprKind, UnaryOpKind};
pub(crate) fn is_self_closing(expr: &Expr) -> bool {
match &expr.node {
ExprKind::Tuple { .. }
| ExprKind::List { .. }
| ExprKind::Set { .. }
| ExprKind::Dict { .. }
| ExprKind::ListComp { .. }
| ExprKind::SetComp { .. }
| ExprKind::DictComp { .. }
| ExprKind::GeneratorExp { .. }
| ExprKind::Call { .. }
| ExprKind::Name { .. }
| ExprKind::Constant { .. }
| ExprKind::Subscript { .. } => true,
ExprKind::Lambda { body, .. } => is_self_closing(body),
ExprKind::BinOp { left, right, .. } => {
matches!(left.node, ExprKind::Constant { .. } | ExprKind::Name { .. })
&& matches!(
right.node,
ExprKind::Tuple { .. }
| ExprKind::List { .. }
| ExprKind::Set { .. }
| ExprKind::Dict { .. }
| ExprKind::ListComp { .. }
| ExprKind::SetComp { .. }
| ExprKind::DictComp { .. }
| ExprKind::GeneratorExp { .. }
| ExprKind::Call { .. }
| ExprKind::Subscript { .. }
)
}
ExprKind::BoolOp { values, .. } => values.last().map_or(false, |expr| {
matches!(
expr.node,
ExprKind::Tuple { .. }
| ExprKind::List { .. }
| ExprKind::Set { .. }
| ExprKind::Dict { .. }
| ExprKind::ListComp { .. }
| ExprKind::SetComp { .. }
| ExprKind::DictComp { .. }
| ExprKind::GeneratorExp { .. }
| ExprKind::Call { .. }
| ExprKind::Subscript { .. }
)
}),
ExprKind::UnaryOp { operand, .. } => is_self_closing(operand),
_ => false,
}
}
/// Return `true` if an [`Expr`] adheres to Black's definition of a non-complex
/// expression, in the context of a slice operation.
pub(crate) fn is_simple_slice(expr: &Expr) -> bool {
match &expr.node {
ExprKind::UnaryOp { op, operand } => {
if matches!(op.node, UnaryOpKind::Not) {
false
} else {
is_simple_slice(operand)
}
}
ExprKind::Constant { .. } => true,
ExprKind::Name { .. } => true,
_ => false,
}
}
/// Return `true` if an [`Expr`] adheres to Black's definition of a non-complex
/// expression, in the context of a power operation.
pub(crate) fn is_simple_power(expr: &Expr) -> bool {
match &expr.node {
ExprKind::UnaryOp { op, operand } => {
if matches!(op.node, UnaryOpKind::Not) {
false
} else {
is_simple_slice(operand)
}
}
ExprKind::Constant { .. } => true,
ExprKind::Name { .. } => true,
ExprKind::Attribute { value, .. } => is_simple_power(value),
_ => false,
}
}

View file

@ -1,37 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::Keyword;
use crate::format::comments::{end_of_line_comments, leading_comments, trailing_comments};
pub(crate) struct FormatKeyword<'a> {
item: &'a Keyword,
}
impl AsFormat<ASTFormatContext<'_>> for Keyword {
type Format<'a> = FormatKeyword<'a>;
fn format(&self) -> Self::Format<'_> {
FormatKeyword { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatKeyword<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let keyword = self.item;
write!(f, [leading_comments(keyword)])?;
if let Some(arg) = &keyword.arg {
write!(f, [dynamic_text(arg, None)])?;
write!(f, [text("=")])?;
write!(f, [keyword.value.format()])?;
} else {
write!(f, [text("**")])?;
write!(f, [keyword.value.format()])?;
}
write!(f, [end_of_line_comments(keyword)])?;
write!(f, [trailing_comments(keyword)])?;
Ok(())
}
}

View file

@ -1,42 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::MatchCase;
use crate::format::builders::block;
use crate::format::comments::{end_of_line_comments, leading_comments};
pub(crate) struct FormatMatchCase<'a> {
item: &'a MatchCase,
}
impl AsFormat<ASTFormatContext<'_>> for MatchCase {
type Format<'a> = FormatMatchCase<'a>;
fn format(&self) -> Self::Format<'_> {
FormatMatchCase { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatMatchCase<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let MatchCase {
pattern,
guard,
body,
} = self.item;
write!(f, [leading_comments(pattern)])?;
write!(f, [text("case")])?;
write!(f, [space(), pattern.format()])?;
if let Some(guard) = &guard {
write!(f, [space(), text("if"), space(), guard.format()])?;
}
write!(f, [text(":")])?;
write!(f, [end_of_line_comments(body)])?;
write!(f, [block_indent(&block(body))])?;
Ok(())
}
}

View file

@ -1,20 +0,0 @@
mod alias;
mod arg;
mod arguments;
mod bool_op;
pub(crate) mod builders;
mod cmp_op;
mod comments;
mod comprehension;
mod excepthandler;
mod expr;
mod helpers;
mod keyword;
mod match_case;
mod numbers;
mod operator;
mod pattern;
mod stmt;
mod strings;
mod unary_op;
mod withitem;

View file

@ -1,203 +0,0 @@
use std::ops::{Add, Sub};
use crate::prelude::*;
use ruff_formatter::{write, Format};
use ruff_text_size::{TextRange, TextSize};
use crate::format::builders::literal;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
struct FloatAtom {
range: TextRange,
}
impl Format<ASTFormatContext<'_>> for FloatAtom {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let contents = f.context().contents();
let content = &contents[self.range];
if let Some(dot_index) = content.find('.') {
let integer = &content[..dot_index];
let fractional = &content[dot_index + 1..];
if integer.is_empty() {
write!(f, [text("0")])?;
} else {
write!(
f,
[literal(
TextRange::new(
self.range.start(),
self.range
.start()
.add(TextSize::try_from(dot_index).unwrap())
),
ContainsNewlines::No
)]
)?;
}
write!(f, [text(".")])?;
if fractional.is_empty() {
write!(f, [text("0")])?;
} else {
write!(
f,
[literal(
TextRange::new(
self.range
.start()
.add(TextSize::try_from(dot_index + 1).unwrap()),
self.range.end()
),
ContainsNewlines::No
)]
)?;
}
} else {
write!(f, [literal(self.range, ContainsNewlines::No)])?;
}
Ok(())
}
}
#[inline]
const fn float_atom(range: TextRange) -> FloatAtom {
FloatAtom { range }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) struct FloatLiteral {
range: TextRange,
}
impl Format<ASTFormatContext<'_>> for FloatLiteral {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let contents = f.context().contents();
let content = &contents[self.range];
// Scientific notation
if let Some(exponent_index) = content.find('e').or_else(|| content.find('E')) {
// Write the base.
write!(
f,
[float_atom(TextRange::new(
self.range.start(),
self.range
.start()
.add(TextSize::try_from(exponent_index).unwrap())
))]
)?;
write!(f, [text("e")])?;
// Write the exponent, omitting the sign if it's positive.
let plus = content[exponent_index + 1..].starts_with('+');
write!(
f,
[literal(
TextRange::new(
self.range.start().add(
TextSize::try_from(exponent_index + 1 + usize::from(plus)).unwrap()
),
self.range.end()
),
ContainsNewlines::No
)]
)?;
} else {
write!(f, [float_atom(self.range)])?;
}
Ok(())
}
}
#[inline]
pub(crate) const fn float_literal(range: TextRange) -> FloatLiteral {
FloatLiteral { range }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) struct IntLiteral {
range: TextRange,
}
impl Format<ASTFormatContext<'_>> for IntLiteral {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let contents = f.context().contents();
for prefix in ["0b", "0B", "0o", "0O", "0x", "0X"] {
let content = &contents[self.range];
if content.starts_with(prefix) {
// In each case, the prefix must be lowercase, while the suffix must be uppercase.
let prefix = &content[..prefix.len()];
let suffix = &content[prefix.len()..];
if prefix.bytes().any(|b| b.is_ascii_uppercase())
|| suffix.bytes().any(|b| b.is_ascii_lowercase())
{
// Write out the fixed version.
write!(
f,
[
dynamic_text(&prefix.to_lowercase(), None),
dynamic_text(&suffix.to_uppercase(), None)
]
)?;
} else {
// Use the existing source.
write!(f, [literal(self.range, ContainsNewlines::No)])?;
}
return Ok(());
}
}
write!(f, [literal(self.range, ContainsNewlines::No)])?;
Ok(())
}
}
#[inline]
pub(crate) const fn int_literal(range: TextRange) -> IntLiteral {
IntLiteral { range }
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) struct ComplexLiteral {
range: TextRange,
}
impl Format<ASTFormatContext<'_>> for ComplexLiteral {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let contents = f.context().contents();
let content = &contents[self.range];
if content.ends_with('j') {
write!(f, [literal(self.range, ContainsNewlines::No)])?;
} else if content.ends_with('J') {
write!(
f,
[literal(
TextRange::new(self.range.start(), self.range.end().sub(TextSize::from(1))),
ContainsNewlines::No
)]
)?;
write!(f, [text("j")])?;
} else {
unreachable!("expected complex literal to end with j or J");
}
Ok(())
}
}
#[inline]
pub(crate) const fn complex_literal(range: TextRange) -> ComplexLiteral {
ComplexLiteral { range }
}

View file

@ -1,45 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::{Operator, OperatorKind};
use crate::format::comments::{end_of_line_comments, leading_comments, trailing_comments};
pub(crate) struct FormatOperator<'a> {
item: &'a Operator,
}
impl AsFormat<ASTFormatContext<'_>> for Operator {
type Format<'a> = FormatOperator<'a>;
fn format(&self) -> Self::Format<'_> {
FormatOperator { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatOperator<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let operator = self.item;
write!(f, [leading_comments(operator)])?;
write!(
f,
[text(match operator.node {
OperatorKind::Add => "+",
OperatorKind::Sub => "-",
OperatorKind::Mult => "*",
OperatorKind::MatMult => "@",
OperatorKind::Div => "/",
OperatorKind::Mod => "%",
OperatorKind::Pow => "**",
OperatorKind::LShift => "<<",
OperatorKind::RShift => ">>",
OperatorKind::BitOr => "|",
OperatorKind::BitXor => "^",
OperatorKind::BitAnd => "&",
OperatorKind::FloorDiv => "//",
})]
)?;
write!(f, [end_of_line_comments(operator)])?;
write!(f, [trailing_comments(operator)])?;
Ok(())
}
}

View file

@ -1,153 +0,0 @@
use rustpython_parser::ast::Constant;
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::{Pattern, PatternKind};
pub(crate) struct FormatPattern<'a> {
item: &'a Pattern,
}
impl AsFormat<ASTFormatContext<'_>> for Pattern {
type Format<'a> = FormatPattern<'a>;
fn format(&self) -> Self::Format<'_> {
FormatPattern { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatPattern<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let pattern = self.item;
match &pattern.node {
PatternKind::MatchValue { value } => {
write!(f, [value.format()])?;
}
PatternKind::MatchSingleton { value } => match value {
Constant::None => write!(f, [text("None")])?,
Constant::Bool(value) => {
if *value {
write!(f, [text("True")])?;
} else {
write!(f, [text("False")])?;
}
}
_ => unreachable!("singleton pattern must be None or bool"),
},
PatternKind::MatchSequence { patterns } => {
write!(f, [text("[")])?;
if let Some(pattern) = patterns.first() {
write!(f, [pattern.format()])?;
}
for pattern in patterns.iter().skip(1) {
write!(f, [text(","), space(), pattern.format()])?;
}
write!(f, [text("]")])?;
}
PatternKind::MatchMapping {
keys,
patterns,
rest,
} => {
write!(f, [text("{")])?;
if let Some(pattern) = patterns.first() {
write!(f, [keys[0].format(), text(":"), space(), pattern.format()])?;
}
for (key, pattern) in keys.iter().skip(1).zip(patterns.iter().skip(1)) {
write!(
f,
[
text(","),
space(),
key.format(),
text(":"),
space(),
pattern.format()
]
)?;
}
if let Some(rest) = &rest {
write!(
f,
[
text(","),
space(),
text("**"),
space(),
dynamic_text(rest, None)
]
)?;
}
write!(f, [text("}")])?;
}
PatternKind::MatchClass {
cls,
patterns,
kwd_attrs,
kwd_patterns,
} => {
write!(f, [cls.format()])?;
if !patterns.is_empty() {
write!(f, [text("(")])?;
if let Some(pattern) = patterns.first() {
write!(f, [pattern.format()])?;
}
for pattern in patterns.iter().skip(1) {
write!(f, [text(","), space(), pattern.format()])?;
}
write!(f, [text(")")])?;
}
if !kwd_attrs.is_empty() {
write!(f, [text("(")])?;
if let Some(attr) = kwd_attrs.first() {
write!(f, [dynamic_text(attr, None)])?;
}
for attr in kwd_attrs.iter().skip(1) {
write!(f, [text(","), space(), dynamic_text(attr, None)])?;
}
write!(f, [text(")")])?;
}
if !kwd_patterns.is_empty() {
write!(f, [text("(")])?;
if let Some(pattern) = kwd_patterns.first() {
write!(f, [pattern.format()])?;
}
for pattern in kwd_patterns.iter().skip(1) {
write!(f, [text(","), space(), pattern.format()])?;
}
write!(f, [text(")")])?;
}
}
PatternKind::MatchStar { name } => {
if let Some(name) = name {
write!(f, [text("*"), dynamic_text(name, None)])?;
} else {
write!(f, [text("*_")])?;
}
}
PatternKind::MatchAs { pattern, name } => {
if let Some(pattern) = &pattern {
write!(f, [pattern.format()])?;
write!(f, [space()])?;
write!(f, [text("as")])?;
write!(f, [space()])?;
}
if let Some(name) = name {
write!(f, [dynamic_text(name, None)])?;
} else {
write!(f, [text("_")])?;
}
}
PatternKind::MatchOr { patterns } => {
write!(f, [patterns[0].format()])?;
for pattern in patterns.iter().skip(1) {
write!(f, [space(), text("|"), space(), pattern.format()])?;
}
}
}
Ok(())
}
}

View file

@ -1,946 +0,0 @@
#![allow(unused_variables, clippy::too_many_arguments)]
use crate::prelude::*;
use ruff_formatter::{format_args, write};
use crate::cst::{
Alias, Arguments, Body, Excepthandler, Expr, ExprKind, Keyword, MatchCase, Operator, Stmt,
StmtKind, Withitem,
};
use crate::format::builders::{block, join_names};
use crate::format::comments::{end_of_line_comments, leading_comments, trailing_comments};
use crate::format::helpers::is_self_closing;
fn format_break(f: &mut Formatter<ASTFormatContext>, stmt: &Stmt) -> FormatResult<()> {
write!(f, [text("break")])?;
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_pass(f: &mut Formatter<ASTFormatContext>, stmt: &Stmt) -> FormatResult<()> {
write!(f, [text("pass")])?;
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_continue(f: &mut Formatter<ASTFormatContext>, stmt: &Stmt) -> FormatResult<()> {
write!(f, [text("continue")])?;
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_global(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
names: &[String],
) -> FormatResult<()> {
write!(f, [text("global")])?;
if !names.is_empty() {
write!(f, [space(), join_names(names)])?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_nonlocal(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
names: &[String],
) -> FormatResult<()> {
write!(f, [text("nonlocal")])?;
if !names.is_empty() {
write!(f, [space(), join_names(names)])?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_delete(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
targets: &[Expr],
) -> FormatResult<()> {
write!(f, [text("del")])?;
match targets.len() {
0 => {}
1 => write!(f, [space(), targets[0].format()])?,
_ => {
write!(
f,
[
space(),
group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_with(|f| {
for (i, target) in targets.iter().enumerate() {
write!(f, [target.format()])?;
if i < targets.len() - 1 {
write!(f, [text(","), soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
Ok(())
})),
if_group_breaks(&text(")")),
])
]
)?;
}
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_class_def(
f: &mut Formatter<ASTFormatContext>,
name: &str,
bases: &[Expr],
keywords: &[Keyword],
body: &Body,
decorator_list: &[Expr],
) -> FormatResult<()> {
for decorator in decorator_list {
write!(f, [text("@"), decorator.format(), hard_line_break()])?;
}
write!(f, [leading_comments(body)])?;
write!(f, [text("class"), space(), dynamic_text(name, None)])?;
if !bases.is_empty() || !keywords.is_empty() {
let format_bases = format_with(|f| {
for (i, expr) in bases.iter().enumerate() {
write!(f, [expr.format()])?;
if i < bases.len() - 1 || !keywords.is_empty() {
write!(f, [text(","), soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
for (i, keyword) in keywords.iter().enumerate() {
write!(f, [keyword.format()])?;
if i < keywords.len() - 1 {
write!(f, [text(","), soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
}
Ok(())
});
write!(
f,
[
text("("),
group(&soft_block_indent(&format_bases)),
text(")")
]
)?;
}
write!(f, [end_of_line_comments(body)])?;
write!(f, [text(":"), block_indent(&block(body))])
}
fn format_func_def(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
name: &str,
args: &Arguments,
returns: Option<&Expr>,
body: &Body,
decorator_list: &[Expr],
async_: bool,
) -> FormatResult<()> {
for decorator in decorator_list {
write!(f, [text("@"), decorator.format(), hard_line_break()])?;
}
write!(f, [leading_comments(body)])?;
if async_ {
write!(f, [text("async"), space()])?;
}
write!(
f,
[
text("def"),
space(),
dynamic_text(name, None),
text("("),
group(&soft_block_indent(&format_with(|f| {
if stmt.trivia.iter().any(|c| c.kind.is_magic_trailing_comma()) {
write!(f, [expand_parent()])?;
}
write!(f, [args.format()])
}))),
text(")")
]
)?;
if let Some(returns) = returns {
write!(f, [text(" -> "), returns.format()])?;
}
write!(f, [text(":")])?;
write!(f, [end_of_line_comments(body)])?;
write!(f, [block_indent(&block(body))])?;
Ok(())
}
fn format_assign(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
targets: &[Expr],
value: &Expr,
) -> FormatResult<()> {
write!(f, [targets[0].format()])?;
for target in &targets[1..] {
// TODO(charlie): This doesn't match Black's behavior. We need to parenthesize
// this expression sometimes.
write!(f, [text(" = "), target.format()])?;
}
write!(f, [text(" = ")])?;
if is_self_closing(value) {
write!(f, [group(&value.format())])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&value.format()),
if_group_breaks(&text(")")),
])]
)?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_aug_assign(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
target: &Expr,
op: &Operator,
value: &Expr,
) -> FormatResult<()> {
write!(f, [target.format()])?;
write!(f, [text(" "), op.format(), text("=")])?;
if is_self_closing(value) {
write!(f, [space(), group(&value.format())])?;
} else {
write!(
f,
[
space(),
group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&value.format()),
if_group_breaks(&text(")")),
])
]
)?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_ann_assign(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
target: &Expr,
annotation: &Expr,
value: Option<&Expr>,
simple: usize,
) -> FormatResult<()> {
let need_parens = matches!(target.node, ExprKind::Name { .. }) && simple == 0;
if need_parens {
write!(f, [text("(")])?;
}
write!(f, [target.format()])?;
if need_parens {
write!(f, [text(")")])?;
}
write!(f, [text(": "), annotation.format()])?;
if let Some(value) = value {
write!(
f,
[
space(),
text("="),
space(),
group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&value.format()),
if_group_breaks(&text(")")),
])
]
)?;
}
Ok(())
}
fn format_for(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
target: &Expr,
iter: &Expr,
body: &Body,
orelse: Option<&Body>,
_type_comment: Option<&str>,
async_: bool,
) -> FormatResult<()> {
if async_ {
write!(f, [text("async"), space()])?;
}
write!(
f,
[
text("for"),
space(),
group(&target.format()),
space(),
text("in"),
space(),
group(&iter.format()),
text(":"),
end_of_line_comments(body),
block_indent(&block(body))
]
)?;
if let Some(orelse) = orelse {
write!(
f,
[
text("else:"),
end_of_line_comments(orelse),
block_indent(&block(orelse))
]
)?;
}
Ok(())
}
fn format_while(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
test: &Expr,
body: &Body,
orelse: Option<&Body>,
) -> FormatResult<()> {
write!(f, [text("while"), space()])?;
if is_self_closing(test) {
write!(f, [test.format()])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&test.format()),
if_group_breaks(&text(")")),
])]
)?;
}
write!(
f,
[
text(":"),
end_of_line_comments(body),
block_indent(&block(body))
]
)?;
if let Some(orelse) = orelse {
write!(
f,
[
text("else:"),
end_of_line_comments(orelse),
block_indent(&block(orelse))
]
)?;
}
Ok(())
}
fn format_if(
f: &mut Formatter<ASTFormatContext>,
test: &Expr,
body: &Body,
orelse: Option<&Body>,
is_elif: bool,
) -> FormatResult<()> {
if is_elif {
write!(f, [text("elif"), space()])?;
} else {
write!(f, [text("if"), space()])?;
}
if is_self_closing(test) {
write!(f, [test.format()])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&test.format()),
if_group_breaks(&text(")")),
])]
)?;
}
write!(
f,
[
text(":"),
end_of_line_comments(body),
block_indent(&block(body))
]
)?;
if let Some(orelse) = orelse {
if orelse.node.len() == 1 {
if let StmtKind::If {
test,
body,
orelse,
is_elif: true,
} = &orelse.node[0].node
{
format_if(f, test, body, orelse.as_ref(), true)?;
} else {
write!(
f,
[
text("else:"),
end_of_line_comments(orelse),
block_indent(&block(orelse))
]
)?;
}
} else {
write!(
f,
[
text("else:"),
end_of_line_comments(orelse),
block_indent(&block(orelse))
]
)?;
}
}
Ok(())
}
fn format_match(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
subject: &Expr,
cases: &[MatchCase],
) -> FormatResult<()> {
write!(
f,
[
text("match"),
space(),
subject.format(),
text(":"),
end_of_line_comments(stmt),
]
)?;
for case in cases {
write!(f, [block_indent(&case.format())])?;
}
Ok(())
}
fn format_raise(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
exc: Option<&Expr>,
cause: Option<&Expr>,
) -> FormatResult<()> {
write!(f, [text("raise")])?;
if let Some(exc) = exc {
write!(f, [space(), exc.format()])?;
if let Some(cause) = cause {
write!(f, [space(), text("from"), space(), cause.format()])?;
}
}
Ok(())
}
fn format_return(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
value: Option<&Expr>,
) -> FormatResult<()> {
write!(f, [text("return")])?;
if let Some(value) = value {
write!(f, [space(), value.format()])?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_try(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
body: &Body,
handlers: &[Excepthandler],
orelse: Option<&Body>,
finalbody: Option<&Body>,
) -> FormatResult<()> {
write!(
f,
[
text("try:"),
end_of_line_comments(body),
block_indent(&block(body))
]
)?;
for handler in handlers {
write!(f, [handler.format()])?;
}
if let Some(orelse) = orelse {
write!(f, [text("else:")])?;
write!(f, [end_of_line_comments(orelse)])?;
write!(f, [block_indent(&block(orelse))])?;
}
if let Some(finalbody) = finalbody {
write!(f, [text("finally:")])?;
write!(f, [end_of_line_comments(finalbody)])?;
write!(f, [block_indent(&block(finalbody))])?;
}
Ok(())
}
fn format_try_star(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
body: &Body,
handlers: &[Excepthandler],
orelse: Option<&Body>,
finalbody: Option<&Body>,
) -> FormatResult<()> {
write!(
f,
[
text("try:"),
end_of_line_comments(body),
block_indent(&block(body))
]
)?;
for handler in handlers {
// TODO(charlie): Include `except*`.
write!(f, [handler.format()])?;
}
if let Some(orelse) = orelse {
write!(
f,
[
text("else:"),
end_of_line_comments(orelse),
block_indent(&block(orelse))
]
)?;
}
if let Some(finalbody) = finalbody {
write!(
f,
[
text("finally:"),
end_of_line_comments(finalbody),
block_indent(&block(finalbody))
]
)?;
}
Ok(())
}
fn format_assert(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
test: &Expr,
msg: Option<&Expr>,
) -> FormatResult<()> {
write!(f, [text("assert"), space()])?;
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&test.format()),
if_group_breaks(&text(")")),
])]
)?;
if let Some(msg) = msg {
write!(
f,
[
text(","),
space(),
group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&msg.format()),
if_group_breaks(&text(")")),
])
]
)?;
}
Ok(())
}
fn format_import(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
names: &[Alias],
) -> FormatResult<()> {
write!(
f,
[
text("import"),
space(),
group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_with(|f| {
for (i, name) in names.iter().enumerate() {
write!(f, [name.format()])?;
if i < names.len() - 1 {
write!(f, [text(","), soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
Ok(())
})),
if_group_breaks(&text(")")),
])
]
)
}
fn format_import_from(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
module: Option<&str>,
names: &[Alias],
level: Option<u32>,
) -> FormatResult<()> {
write!(f, [text("from")])?;
write!(f, [space()])?;
if let Some(level) = level {
for _ in 0..level {
write!(f, [text(".")])?;
}
}
if let Some(module) = module {
write!(f, [dynamic_text(module, None)])?;
}
write!(f, [space()])?;
write!(f, [text("import")])?;
write!(f, [space()])?;
if names.iter().any(|name| name.node.name == "*") {
write!(f, [text("*")])?;
} else {
let magic_trailing_comma = stmt.trivia.iter().any(|c| c.kind.is_magic_trailing_comma());
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_with(|f| {
if magic_trailing_comma {
write!(f, [expand_parent()])?;
}
for (i, name) in names.iter().enumerate() {
write!(f, [name.format()])?;
if i < names.len() - 1 {
write!(f, [text(",")])?;
write!(f, [soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
Ok(())
})),
if_group_breaks(&text(")")),
])]
)?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_expr(f: &mut Formatter<ASTFormatContext>, stmt: &Stmt, expr: &Expr) -> FormatResult<()> {
if stmt.parentheses.is_always() {
write!(
f,
[group(&format_args![
text("("),
soft_block_indent(&format_args![expr.format()]),
text(")"),
])]
)?;
} else if is_self_closing(expr) {
write!(f, [group(&format_args![expr.format()])])?;
} else {
write!(
f,
[group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_args![expr.format()]),
if_group_breaks(&text(")")),
])]
)?;
}
write!(f, [end_of_line_comments(stmt)])?;
Ok(())
}
fn format_with_(
f: &mut Formatter<ASTFormatContext>,
stmt: &Stmt,
items: &[Withitem],
body: &Body,
type_comment: Option<&str>,
async_: bool,
) -> FormatResult<()> {
if async_ {
write!(f, [text("async"), space()])?;
}
write!(
f,
[
text("with"),
space(),
group(&format_args![
if_group_breaks(&text("(")),
soft_block_indent(&format_with(|f| {
for (i, item) in items.iter().enumerate() {
write!(f, [item.format()])?;
if i < items.len() - 1 {
write!(f, [text(","), soft_line_break_or_space()])?;
} else {
write!(f, [if_group_breaks(&text(","))])?;
}
}
Ok(())
})),
if_group_breaks(&text(")")),
]),
text(":"),
end_of_line_comments(body),
block_indent(&block(body))
]
)?;
Ok(())
}
pub(crate) struct FormatStmt<'a> {
item: &'a Stmt,
}
impl Format<ASTFormatContext<'_>> for FormatStmt<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
write!(f, [leading_comments(self.item)])?;
match &self.item.node {
StmtKind::Pass => format_pass(f, self.item),
StmtKind::Break => format_break(f, self.item),
StmtKind::Continue => format_continue(f, self.item),
StmtKind::Global { names } => format_global(f, self.item, names),
StmtKind::Nonlocal { names } => format_nonlocal(f, self.item, names),
StmtKind::FunctionDef {
name,
args,
body,
decorator_list,
returns,
..
} => format_func_def(
f,
self.item,
name,
args,
returns.as_deref(),
body,
decorator_list,
false,
),
StmtKind::AsyncFunctionDef {
name,
args,
body,
decorator_list,
returns,
..
} => format_func_def(
f,
self.item,
name,
args,
returns.as_deref(),
body,
decorator_list,
true,
),
StmtKind::ClassDef {
name,
bases,
keywords,
body,
decorator_list,
} => format_class_def(f, name, bases, keywords, body, decorator_list),
StmtKind::Return { value } => format_return(f, self.item, value.as_ref()),
StmtKind::Delete { targets } => format_delete(f, self.item, targets),
StmtKind::Assign { targets, value, .. } => format_assign(f, self.item, targets, value),
StmtKind::AugAssign { target, op, value } => {
format_aug_assign(f, self.item, target, op, value)
}
StmtKind::AnnAssign {
target,
annotation,
value,
simple,
} => format_ann_assign(f, self.item, target, annotation, value.as_deref(), *simple),
StmtKind::For {
target,
iter,
body,
orelse,
type_comment,
} => format_for(
f,
self.item,
target,
iter,
body,
orelse.as_ref(),
type_comment.as_deref(),
false,
),
StmtKind::AsyncFor {
target,
iter,
body,
orelse,
type_comment,
} => format_for(
f,
self.item,
target,
iter,
body,
orelse.as_ref(),
type_comment.as_deref(),
true,
),
StmtKind::While { test, body, orelse } => {
format_while(f, self.item, test, body, orelse.as_ref())
}
StmtKind::If {
test,
body,
orelse,
is_elif,
} => format_if(f, test, body, orelse.as_ref(), *is_elif),
StmtKind::With {
items,
body,
type_comment,
} => format_with_(
f,
self.item,
items,
body,
type_comment.as_ref().map(String::as_str),
false,
),
StmtKind::AsyncWith {
items,
body,
type_comment,
} => format_with_(
f,
self.item,
items,
body,
type_comment.as_ref().map(String::as_str),
true,
),
StmtKind::Match { subject, cases } => format_match(f, self.item, subject, cases),
StmtKind::Raise { exc, cause } => {
format_raise(f, self.item, exc.as_deref(), cause.as_deref())
}
StmtKind::Try {
body,
handlers,
orelse,
finalbody,
} => format_try(
f,
self.item,
body,
handlers,
orelse.as_ref(),
finalbody.as_ref(),
),
StmtKind::TryStar {
body,
handlers,
orelse,
finalbody,
} => format_try_star(
f,
self.item,
body,
handlers,
orelse.as_ref(),
finalbody.as_ref(),
),
StmtKind::Assert { test, msg } => {
format_assert(f, self.item, test, msg.as_ref().map(|expr| &**expr))
}
StmtKind::Import { names } => format_import(f, self.item, names),
StmtKind::ImportFrom {
module,
names,
level,
} => format_import_from(
f,
self.item,
module.as_ref().map(String::as_str),
names,
*level,
),
StmtKind::Expr { value } => format_expr(f, self.item, value),
}?;
write!(f, [hard_line_break()])?;
write!(f, [trailing_comments(self.item)])?;
Ok(())
}
}
impl AsFormat<ASTFormatContext<'_>> for Stmt {
type Format<'a> = FormatStmt<'a>;
fn format(&self) -> Self::Format<'_> {
FormatStmt { item: self }
}
}

View file

@ -1,244 +0,0 @@
use rustpython_parser::{Mode, Tok};
use crate::prelude::*;
use ruff_formatter::{write, Format};
use ruff_python_ast::str::{leading_quote, trailing_quote};
use ruff_text_size::TextRange;
use crate::cst::Expr;
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub(crate) struct StringLiteralPart {
range: TextRange,
}
impl Format<ASTFormatContext<'_>> for StringLiteralPart {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let contents = f.context().contents();
// Extract leading and trailing quotes.
let contents = &contents[self.range];
let leading_quote = leading_quote(contents).unwrap();
let trailing_quote = trailing_quote(contents).unwrap();
let body = &contents[leading_quote.len()..contents.len() - trailing_quote.len()];
// Determine the correct quote style.
// TODO(charlie): Make this parameterizable.
let mut squotes: usize = 0;
let mut dquotes: usize = 0;
for char in body.chars() {
if char == '\'' {
squotes += 1;
} else if char == '"' {
dquotes += 1;
}
}
// Retain raw prefixes.
let mut is_raw = false;
if leading_quote.contains('r') {
is_raw = true;
f.write_element(FormatElement::StaticText { text: "r" })?;
} else if leading_quote.contains('R') {
is_raw = true;
f.write_element(FormatElement::StaticText { text: "R" })?;
}
// Normalize bytes literals to use b"...".
if leading_quote.contains('b') || leading_quote.contains('B') {
f.write_element(FormatElement::StaticText { text: "b" })?;
}
// TODO(charlie): Avoid allocating if there's nothing to escape. In other words, if we can
// use the string body directly, do so!
if trailing_quote.len() == 1 {
// Single-quoted string.
if dquotes == 0 || squotes > 0 {
// If the body doesn't contain any double quotes, or it contains both single and
// double quotes, use double quotes.
f.write_element(FormatElement::StaticText { text: "\"" })?;
f.write_element(FormatElement::DynamicText {
text: if is_raw {
body.into()
} else {
double_escape(body).into()
},
})?;
f.write_element(FormatElement::StaticText { text: "\"" })?;
Ok(())
} else {
f.write_element(FormatElement::StaticText { text: "'" })?;
f.write_element(FormatElement::DynamicText {
text: if is_raw {
body.into()
} else {
single_escape(body).into()
},
})?;
f.write_element(FormatElement::StaticText { text: "'" })?;
Ok(())
}
} else if trailing_quote.len() == 3 {
// Triple-quoted string.
if body.starts_with("\"\"\"") || body.ends_with('"') {
// We only need to use single quotes if the string body starts with three or more
// double quotes, or ends with a double quote. Converting to double quotes in those
// cases would cause a syntax error.
f.write_element(FormatElement::StaticText { text: "'''" })?;
f.write_element(FormatElement::DynamicText {
text: body.to_string().into_boxed_str(),
})?;
f.write_element(FormatElement::StaticText { text: "'''" })?;
Ok(())
} else {
f.write_element(FormatElement::StaticText { text: "\"\"\"" })?;
f.write_element(FormatElement::DynamicText {
text: body.to_string().into_boxed_str(),
})?;
f.write_element(FormatElement::StaticText { text: "\"\"\"" })?;
Ok(())
}
} else {
unreachable!("Invalid quote length: {}", trailing_quote.len());
}
}
}
#[inline]
pub(crate) const fn string_literal_part(range: TextRange) -> StringLiteralPart {
StringLiteralPart { range }
}
#[derive(Debug, Copy, Clone)]
pub(crate) struct StringLiteral<'a> {
expr: &'a Expr,
}
impl Format<ASTFormatContext<'_>> for StringLiteral<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let expr = self.expr;
// TODO(charlie): This tokenization needs to happen earlier, so that we can attach
// comments to individual string literals.
let contents = f.context().locator().slice(expr.range());
let elts = rustpython_parser::lexer::lex_starts_at(contents, Mode::Module, expr.start())
.flatten()
.filter_map(|(tok, range)| {
if matches!(tok, Tok::String { .. }) {
Some(range)
} else {
None
}
})
.collect::<Vec<_>>();
write!(
f,
[group(&format_with(|f| {
if expr.parentheses.is_if_expanded() {
write!(f, [if_group_breaks(&text("("))])?;
}
for (i, elt) in elts.iter().enumerate() {
write!(f, [string_literal_part(*elt)])?;
if i < elts.len() - 1 {
write!(f, [soft_line_break_or_space()])?;
}
}
if expr.parentheses.is_if_expanded() {
write!(f, [if_group_breaks(&text(")"))])?;
}
Ok(())
}))]
)?;
Ok(())
}
}
#[inline]
pub(crate) const fn string_literal(expr: &Expr) -> StringLiteral {
StringLiteral { expr }
}
/// Escape a string body to be used in a string literal with double quotes.
fn double_escape(text: &str) -> String {
let mut escaped = String::with_capacity(text.len());
let mut chars = text.chars().peekable();
while let Some(ch) = chars.next() {
if ch == '\\' {
let Some(next) = chars.peek() else {
break;
};
if *next == '\'' {
chars.next();
escaped.push('\'');
} else if *next == '"' {
chars.next();
escaped.push('\\');
escaped.push('"');
} else if *next == '\\' {
chars.next();
escaped.push('\\');
escaped.push(ch);
} else {
escaped.push(ch);
}
} else if ch == '"' {
escaped.push('\\');
escaped.push('"');
} else {
escaped.push(ch);
}
}
escaped
}
/// Escape a string body to be used in a string literal with single quotes.
fn single_escape(text: &str) -> String {
let mut escaped = String::with_capacity(text.len());
let mut chars = text.chars().peekable();
while let Some(ch) = chars.next() {
if ch == '\\' {
let Some(next) = chars.peek() else {
break;
};
if *next == '"' {
chars.next();
escaped.push('"');
} else if *next == '\'' {
chars.next();
escaped.push('\\');
escaped.push('\'');
} else if *next == '\\' {
chars.next();
escaped.push('\\');
escaped.push(ch);
} else {
escaped.push(ch);
}
} else if ch == '\'' {
escaped.push('\\');
escaped.push('\'');
} else {
escaped.push(ch);
}
}
escaped
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_double_escape() {
assert_eq!(double_escape(r#"It\'s mine"#), r#"It's mine"#);
assert_eq!(double_escape(r#"It\'s "mine""#), r#"It's \"mine\""#);
assert_eq!(double_escape(r#"It\\'s mine"#), r#"It\\'s mine"#);
}
#[test]
fn test_single_escape() {
assert_eq!(single_escape(r#"It's mine"#), r#"It\'s mine"#);
assert_eq!(single_escape(r#"It\'s "mine""#), r#"It\'s "mine""#);
assert_eq!(single_escape(r#"It\\'s mine"#), r#"It\\\'s mine"#);
}
}

View file

@ -1,35 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::{UnaryOp, UnaryOpKind};
pub(crate) struct FormatUnaryOp<'a> {
item: &'a UnaryOp,
}
impl AsFormat<ASTFormatContext<'_>> for UnaryOp {
type Format<'a> = FormatUnaryOp<'a>;
fn format(&self) -> Self::Format<'_> {
FormatUnaryOp { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatUnaryOp<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let unary_op = self.item;
write!(
f,
[
text(match unary_op.node {
UnaryOpKind::Invert => "~",
UnaryOpKind::Not => "not",
UnaryOpKind::UAdd => "+",
UnaryOpKind::USub => "-",
}),
matches!(unary_op.node, UnaryOpKind::Not).then_some(space())
]
)?;
Ok(())
}
}

View file

@ -1,30 +0,0 @@
use crate::prelude::*;
use ruff_formatter::write;
use crate::cst::Withitem;
pub(crate) struct FormatWithitem<'a> {
item: &'a Withitem,
}
impl AsFormat<ASTFormatContext<'_>> for Withitem {
type Format<'a> = FormatWithitem<'a>;
fn format(&self) -> Self::Format<'_> {
FormatWithitem { item: self }
}
}
impl Format<ASTFormatContext<'_>> for FormatWithitem<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext>) -> FormatResult<()> {
let withitem = self.item;
write!(f, [withitem.context_expr.format()])?;
if let Some(optional_vars) = &withitem.optional_vars {
write!(f, [space(), text("as"), space()])?;
write!(f, [optional_vars.format()])?;
}
Ok(())
}
}

View file

@ -8,24 +8,15 @@ use ruff_formatter::{
};
use ruff_python_ast::source_code::{CommentRanges, CommentRangesBuilder, Locator};
use crate::attachment::attach;
use crate::comments::Comments;
use crate::context::ASTFormatContext;
use crate::cst::Stmt;
use crate::newlines::normalize_newlines;
use crate::parentheses::normalize_parentheses;
use crate::trivia::TriviaToken;
use crate::module::FormatModule;
mod attachment;
pub mod cli;
mod comments;
pub mod context;
mod cst;
mod format;
mod newlines;
mod parentheses;
mod module;
mod prelude;
mod trivia;
include!("../../ruff_formatter/shared_traits.rs");
@ -46,12 +37,10 @@ pub fn fmt(contents: &str) -> Result<Printed> {
let comment_ranges = comment_ranges.finish();
let trivia = trivia::extract_trivia_tokens(&tokens);
// Parse the AST.
let python_ast = parse_tokens(tokens, Mode::Module, "<filename>").unwrap();
let formatted = format_node(&python_ast, &comment_ranges, contents, trivia)?;
let formatted = format_node(&python_ast, &comment_ranges, contents)?;
formatted
.print()
@ -62,27 +51,11 @@ pub(crate) fn format_node<'a>(
root: &'a Mod,
comment_ranges: &'a CommentRanges,
source: &'a str,
trivia: Vec<TriviaToken>,
) -> FormatResult<Formatted<ASTFormatContext<'a>>> {
let comments = Comments::from_ast(root, SourceCode::new(source), comment_ranges);
let module = root.as_module().unwrap();
let locator = Locator::new(source);
// Convert to a CST.
let mut python_cst: Vec<Stmt> = module
.body
.iter()
.cloned()
.map(|stmt| (stmt, &locator).into())
.collect();
// Attach trivia.
attach(&mut python_cst, trivia);
normalize_newlines(&mut python_cst);
normalize_parentheses(&mut python_cst, &locator);
format!(
ASTFormatContext::new(
SimpleFormatOptions {
@ -92,7 +65,7 @@ pub(crate) fn format_node<'a>(
locator.contents(),
comments
),
[format::builders::statements(&python_cst)]
[FormatModule::new(root)]
)
}
@ -111,15 +84,9 @@ mod tests {
use ruff_testing_macros::fixture;
use similar::TextDiff;
use crate::{fmt, format_node, trivia};
use crate::{fmt, format_node};
#[fixture(
pattern = "resources/test/fixtures/black/**/*.py",
// Excluded tests because they reach unreachable when attaching tokens
exclude = [
"*comments8.py",
])
]
#[fixture(pattern = "resources/test/fixtures/black/**/*.py")]
#[test]
fn black_test(input_path: &Path) -> Result<()> {
let content = fs::read_to_string(input_path)?;
@ -212,12 +179,10 @@ mod tests {
let comment_ranges = comment_ranges.finish();
let trivia = trivia::extract_trivia_tokens(&tokens);
// Parse the AST.
let python_ast = parse_tokens(tokens, Mode::Module, "<filename>").unwrap();
let formatted = format_node(&python_ast, &comment_ranges, src, trivia).unwrap();
let formatted = format_node(&python_ast, &comment_ranges, src).unwrap();
// Uncomment the `dbg` to print the IR.
// Use `dbg_write!(f, []) instead of `write!(f, [])` in your formatting code to print some IR

View file

@ -0,0 +1,33 @@
use crate::context::ASTFormatContext;
use ruff_formatter::format_element::tag::VerbatimKind;
use ruff_formatter::prelude::*;
use ruff_formatter::write;
use rustpython_parser::ast::{Mod, Ranged};
pub(crate) struct FormatModule<'a> {
module: &'a Mod,
}
impl<'a> FormatModule<'a> {
pub(crate) fn new(module: &'a Mod) -> Self {
Self { module }
}
}
impl Format<ASTFormatContext<'_>> for FormatModule<'_> {
fn fmt(&self, f: &mut Formatter<ASTFormatContext<'_>>) -> FormatResult<()> {
let range = self.module.range();
write!(f, [source_position(range.start())])?;
f.write_element(FormatElement::Tag(Tag::StartVerbatim(
VerbatimKind::Verbatim {
length: range.len(),
},
)))?;
write!(f, [source_text_slice(range, ContainsNewlines::Detect)])?;
f.write_element(FormatElement::Tag(Tag::EndVerbatim))?;
write!(f, [source_position(range.end())])
}
}

View file

@ -1,370 +0,0 @@
use rustpython_parser::ast::Constant;
use crate::cst::visitor;
use crate::cst::visitor::Visitor;
use crate::cst::{
Alias, Arg, BoolOp, CmpOp, Excepthandler, ExcepthandlerKind, Expr, ExprKind, Keyword, Operator,
Pattern, SliceIndex, Stmt, StmtKind, UnaryOp,
};
use crate::trivia::{Relationship, Trivia, TriviaKind};
#[derive(Debug, Copy, Clone)]
enum Depth {
TopLevel,
Nested,
}
impl Depth {
fn max_newlines(self) -> usize {
match self {
Self::TopLevel => 2,
Self::Nested => 1,
}
}
}
#[derive(Debug, Copy, Clone)]
enum Scope {
Module,
Class,
Function,
}
#[derive(Debug, Copy, Clone)]
enum Trailer {
None,
ClassDef,
FunctionDef,
Import,
Docstring,
Generic,
CompoundStatement,
}
struct StmtNormalizer {
depth: Depth,
trailer: Trailer,
scope: Scope,
}
impl<'a> Visitor<'a> for StmtNormalizer {
fn visit_stmt(&mut self, stmt: &'a mut Stmt) {
// Remove any runs of empty lines greater than two in a row.
let mut count = 0;
stmt.trivia.retain(|c| {
if c.kind.is_empty_line() && c.relationship.is_leading() {
count += 1;
count <= self.depth.max_newlines()
} else {
count = 0;
true
}
});
if matches!(self.trailer, Trailer::None)
|| (matches!(self.trailer, Trailer::CompoundStatement)
&& !matches!(
stmt.node,
StmtKind::FunctionDef { .. }
| StmtKind::AsyncFunctionDef { .. }
| StmtKind::ClassDef { .. }
))
{
// If this is the first statement in the block, remove any leading empty lines, with the
// exception being functions and classes defined within compound statements (e.g., as
// the first statement in an `if` body).
let mut seen_non_empty = false;
stmt.trivia.retain(|c| {
if seen_non_empty {
true
} else {
if c.kind.is_empty_line() && c.relationship.is_leading() {
false
} else {
seen_non_empty = true;
true
}
}
});
} else {
// If the previous statement was a function or similar, ensure we have the
// appropriate number of lines to start.
let required_newlines = match self.trailer {
Trailer::FunctionDef | Trailer::ClassDef => self.depth.max_newlines(),
Trailer::Docstring if matches!(self.scope, Scope::Class) => 1,
Trailer::Import => usize::from(!matches!(
stmt.node,
StmtKind::Import { .. } | StmtKind::ImportFrom { .. }
)),
_ => 0,
};
let present_newlines = stmt
.trivia
.iter()
.take_while(|c| c.kind.is_empty_line() && c.relationship.is_leading())
.count();
if present_newlines < required_newlines {
for _ in 0..(required_newlines - present_newlines) {
stmt.trivia.insert(
0,
Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Leading,
},
);
}
}
// If the current statement is a function or similar, Ensure we have an
// appropriate number of lines above.
if matches!(
stmt.node,
StmtKind::FunctionDef { .. }
| StmtKind::AsyncFunctionDef { .. }
| StmtKind::ClassDef { .. }
) {
let num_to_insert = self.depth.max_newlines()
- stmt
.trivia
.iter()
.take_while(|c| c.kind.is_empty_line() && c.relationship.is_leading())
.count();
for _ in 0..num_to_insert {
stmt.trivia.insert(
0,
Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Leading,
},
);
}
}
}
let prev_scope = self.scope;
let prev_depth = self.depth;
match &mut stmt.node {
StmtKind::FunctionDef { body, .. } | StmtKind::AsyncFunctionDef { body, .. } => {
self.depth = Depth::Nested;
self.scope = Scope::Function;
self.trailer = Trailer::None;
self.visit_body(body);
self.trailer = Trailer::FunctionDef;
}
StmtKind::ClassDef { body, .. } => {
self.depth = Depth::Nested;
self.scope = Scope::Class;
self.trailer = Trailer::None;
self.visit_body(body);
self.trailer = Trailer::ClassDef;
}
StmtKind::While { body, orelse, .. }
| StmtKind::For { body, orelse, .. }
| StmtKind::AsyncFor { body, orelse, .. } => {
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(body);
if let Some(orelse) = orelse {
// If the previous body ended with a function or class definition, we need to
// insert an empty line before the else block. Since the `else` itself isn't
// a statement, we need to insert it into the last statement of the body.
if matches!(self.trailer, Trailer::ClassDef | Trailer::FunctionDef) {
body.trivia.push(Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Dangling,
});
}
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(orelse);
}
}
StmtKind::If { body, orelse, .. } => {
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(body);
if let Some(orelse) = orelse {
if matches!(self.trailer, Trailer::ClassDef | Trailer::FunctionDef) {
body.trivia.push(Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Dangling,
});
}
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(orelse);
}
}
StmtKind::With { body, .. } | StmtKind::AsyncWith { body, .. } => {
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(body);
}
// StmtKind::Match { .. } => {}
StmtKind::Try {
body,
handlers,
orelse,
finalbody,
}
| StmtKind::TryStar {
body,
handlers,
orelse,
finalbody,
} => {
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(body);
let mut prev = &mut body.trivia;
for handler in handlers {
if matches!(self.trailer, Trailer::ClassDef | Trailer::FunctionDef) {
prev.push(Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Dangling,
});
}
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
let ExcepthandlerKind::ExceptHandler { body, .. } = &mut handler.node;
self.visit_body(body);
prev = &mut body.trivia;
}
if let Some(orelse) = orelse {
if matches!(self.trailer, Trailer::ClassDef | Trailer::FunctionDef) {
prev.push(Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Dangling,
});
}
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(orelse);
prev = &mut body.trivia;
}
if let Some(finalbody) = finalbody {
if matches!(self.trailer, Trailer::ClassDef | Trailer::FunctionDef) {
prev.push(Trivia {
kind: TriviaKind::EmptyLine,
relationship: Relationship::Dangling,
});
}
self.depth = Depth::Nested;
self.trailer = Trailer::CompoundStatement;
self.visit_body(finalbody);
}
}
_ => {
self.trailer = match &stmt.node {
StmtKind::Expr { value, .. }
if matches!(self.scope, Scope::Class | Scope::Function)
&& matches!(self.trailer, Trailer::None) =>
{
if let ExprKind::Constant {
value: Constant::Str(..),
..
} = &value.node
{
Trailer::Docstring
} else {
Trailer::Generic
}
}
StmtKind::Import { .. } | StmtKind::ImportFrom { .. } => Trailer::Import,
_ => Trailer::Generic,
};
visitor::walk_stmt(self, stmt);
}
}
self.depth = prev_depth;
self.scope = prev_scope;
}
}
struct ExprNormalizer;
impl<'a> Visitor<'a> for ExprNormalizer {
fn visit_expr(&mut self, expr: &'a mut Expr) {
expr.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_expr(self, expr);
}
fn visit_alias(&mut self, alias: &'a mut Alias) {
alias.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_alias(self, alias);
}
fn visit_arg(&mut self, arg: &'a mut Arg) {
arg.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_arg(self, arg);
}
fn visit_excepthandler(&mut self, excepthandler: &'a mut Excepthandler) {
excepthandler.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_excepthandler(self, excepthandler);
}
fn visit_keyword(&mut self, keyword: &'a mut Keyword) {
keyword.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_keyword(self, keyword);
}
fn visit_bool_op(&mut self, bool_op: &'a mut BoolOp) {
bool_op.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_bool_op(self, bool_op);
}
fn visit_unary_op(&mut self, unary_op: &'a mut UnaryOp) {
unary_op.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_unary_op(self, unary_op);
}
fn visit_cmp_op(&mut self, cmp_op: &'a mut CmpOp) {
cmp_op.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_cmp_op(self, cmp_op);
}
fn visit_operator(&mut self, operator: &'a mut Operator) {
operator.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_operator(self, operator);
}
fn visit_slice_index(&mut self, slice_index: &'a mut SliceIndex) {
slice_index.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_slice_index(self, slice_index);
}
fn visit_pattern(&mut self, pattern: &'a mut Pattern) {
pattern.trivia.retain(|c| !c.kind.is_empty_line());
visitor::walk_pattern(self, pattern);
}
}
pub(crate) fn normalize_newlines(python_cst: &mut [Stmt]) {
let mut normalizer = StmtNormalizer {
depth: Depth::TopLevel,
trailer: Trailer::None,
scope: Scope::Module,
};
for stmt in python_cst.iter_mut() {
normalizer.visit_stmt(stmt);
}
let mut normalizer = ExprNormalizer;
for stmt in python_cst.iter_mut() {
normalizer.visit_stmt(stmt);
}
}

View file

@ -1,199 +0,0 @@
use rustpython_parser::ast::Constant;
use ruff_python_ast::source_code::Locator;
use crate::cst::helpers::is_radix_literal;
use crate::cst::visitor;
use crate::cst::visitor::Visitor;
use crate::cst::{Expr, ExprKind, Stmt, StmtKind};
use crate::trivia::Parenthesize;
/// Modify an [`Expr`] to infer parentheses, rather than respecting any user-provided trivia.
fn use_inferred_parens(expr: &mut Expr) {
// Remove parentheses, unless it's a generator expression, in which case, keep them.
if !matches!(expr.node, ExprKind::GeneratorExp { .. }) {
expr.trivia.retain(|trivia| !trivia.kind.is_parentheses());
}
// If it's a tuple, add parentheses if it's a singleton; otherwise, we only need parentheses
// if the tuple expands.
if let ExprKind::Tuple { elts, .. } = &expr.node {
expr.parentheses = if elts.len() > 1 {
Parenthesize::IfExpanded
} else {
Parenthesize::Always
};
}
}
struct ParenthesesNormalizer<'a> {
locator: &'a Locator<'a>,
}
impl<'a> Visitor<'a> for ParenthesesNormalizer<'_> {
fn visit_stmt(&mut self, stmt: &'a mut Stmt) {
// Always remove parentheses around statements, unless it's an expression statement,
// in which case, remove parentheses around the expression.
let before = stmt.trivia.len();
stmt.trivia.retain(|trivia| !trivia.kind.is_parentheses());
let after = stmt.trivia.len();
if let StmtKind::Expr { value } = &mut stmt.node {
if before != after {
stmt.parentheses = Parenthesize::Always;
value.parentheses = Parenthesize::Never;
}
}
// In a variety of contexts, remove parentheses around sub-expressions. Right now, the
// pattern is consistent (and repeated), but it may not end up that way.
// https://black.readthedocs.io/en/stable/the_black_code_style/current_style.html#parentheses
match &mut stmt.node {
StmtKind::FunctionDef { .. } => {}
StmtKind::AsyncFunctionDef { .. } => {}
StmtKind::ClassDef { .. } => {}
StmtKind::Return { value } => {
if let Some(value) = value {
use_inferred_parens(value);
}
}
StmtKind::Delete { .. } => {}
StmtKind::Assign { targets, value, .. } => {
for target in targets {
use_inferred_parens(target);
}
use_inferred_parens(value);
}
StmtKind::AugAssign { value, .. } => {
use_inferred_parens(value);
}
StmtKind::AnnAssign { value, .. } => {
if let Some(value) = value {
use_inferred_parens(value);
}
}
StmtKind::For { target, iter, .. } | StmtKind::AsyncFor { target, iter, .. } => {
use_inferred_parens(target);
if !matches!(iter.node, ExprKind::Tuple { .. }) {
use_inferred_parens(iter);
}
}
StmtKind::While { test, .. } => {
use_inferred_parens(test);
}
StmtKind::If { test, .. } => {
use_inferred_parens(test);
}
StmtKind::With { .. } => {}
StmtKind::AsyncWith { .. } => {}
StmtKind::Match { .. } => {}
StmtKind::Raise { .. } => {}
StmtKind::Try { .. } => {}
StmtKind::TryStar { .. } => {}
StmtKind::Assert { test, msg } => {
use_inferred_parens(test);
if let Some(msg) = msg {
use_inferred_parens(msg);
}
}
StmtKind::Import { .. } => {}
StmtKind::ImportFrom { .. } => {}
StmtKind::Global { .. } => {}
StmtKind::Nonlocal { .. } => {}
StmtKind::Expr { .. } => {}
StmtKind::Pass => {}
StmtKind::Break => {}
StmtKind::Continue => {}
}
visitor::walk_stmt(self, stmt);
}
fn visit_expr(&mut self, expr: &'a mut Expr) {
// Always retain parentheses around expressions.
let before = expr.trivia.len();
expr.trivia.retain(|trivia| !trivia.kind.is_parentheses());
let after = expr.trivia.len();
if before != after {
expr.parentheses = Parenthesize::Always;
}
match &mut expr.node {
ExprKind::BoolOp { .. } => {}
ExprKind::NamedExpr { .. } => {}
ExprKind::BinOp { .. } => {}
ExprKind::UnaryOp { .. } => {}
ExprKind::Lambda { .. } => {}
ExprKind::IfExp { .. } => {}
ExprKind::Dict { .. } => {}
ExprKind::Set { .. } => {}
ExprKind::ListComp { .. } => {}
ExprKind::SetComp { .. } => {}
ExprKind::DictComp { .. } => {}
ExprKind::GeneratorExp { .. } => {}
ExprKind::Await { .. } => {}
ExprKind::Yield { .. } => {}
ExprKind::YieldFrom { .. } => {}
ExprKind::Compare { .. } => {}
ExprKind::Call { .. } => {}
ExprKind::FormattedValue { .. } => {}
ExprKind::JoinedStr { .. } => {}
ExprKind::Constant { .. } => {}
ExprKind::Attribute { value, .. } => {
if matches!(
value.node,
ExprKind::Constant {
value: Constant::Float(..),
..
},
) {
value.parentheses = Parenthesize::Always;
} else if matches!(
value.node,
ExprKind::Constant {
value: Constant::Int(..),
..
},
) {
// TODO(charlie): Encode this in the AST via separate node types.
if !is_radix_literal(self.locator.slice(value.range())) {
value.parentheses = Parenthesize::Always;
}
}
}
ExprKind::Subscript { value, slice, .. } => {
// If the slice isn't manually parenthesized, ensure that we _never_ parenthesize
// the value.
if !slice
.trivia
.iter()
.any(|trivia| trivia.kind.is_parentheses())
{
value.parentheses = Parenthesize::Never;
}
}
ExprKind::Starred { .. } => {}
ExprKind::Name { .. } => {}
ExprKind::List { .. } => {}
ExprKind::Tuple { .. } => {}
ExprKind::Slice { .. } => {}
}
visitor::walk_expr(self, expr);
}
}
/// Normalize parentheses in a Python CST.
///
/// It's not always possible to determine the correct parentheses to use during formatting
/// from the node (and trivia) alone; sometimes, we need to know the parent node. This
/// visitor normalizes parentheses via a top-down traversal, which simplifies the formatting
/// code later on.
///
/// TODO(charlie): It's weird that we have both `TriviaKind::Parentheses` (which aren't used
/// during formatting) and `Parenthesize` (which are used during formatting).
pub(crate) fn normalize_parentheses(python_cst: &mut [Stmt], locator: &Locator) {
let mut normalizer = ParenthesesNormalizer { locator };
for stmt in python_cst {
normalizer.visit_stmt(stmt);
}
}

View file

@ -1,3 +1,4 @@
#[allow(unused_imports)]
pub(crate) use crate::{ASTFormatContext, AsFormat, FormattedIterExt as _, IntoFormat};
#[allow(unused_imports)]
pub(crate) use ruff_formatter::prelude::*;

View file

@ -0,0 +1,132 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/attribute_access_on_number_literals.py
---
## Input
```py
x = 123456789 .bit_count()
x = (123456).__abs__()
x = .1.is_integer()
x = 1. .imag
x = 1E+1.imag
x = 1E-1.real
x = 123456789.123456789.hex()
x = 123456789.123456789E123456789 .real
x = 123456789E123456789 .conjugate()
x = 123456789J.real
x = 123456789.123456789J.__add__(0b1011.bit_length())
x = 0XB1ACC.conjugate()
x = 0B1011 .conjugate()
x = 0O777 .real
x = 0.000000006 .hex()
x = -100.0000J
if 10 .real:
...
y = 100[no]
y = 100(no)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,21 +1,21 @@
-x = (123456789).bit_count()
+x = 123456789 .bit_count()
x = (123456).__abs__()
-x = (0.1).is_integer()
-x = (1.0).imag
-x = (1e1).imag
-x = (1e-1).real
-x = (123456789.123456789).hex()
-x = (123456789.123456789e123456789).real
-x = (123456789e123456789).conjugate()
-x = 123456789j.real
-x = 123456789.123456789j.__add__(0b1011.bit_length())
-x = 0xB1ACC.conjugate()
-x = 0b1011.conjugate()
-x = 0o777.real
-x = (0.000000006).hex()
-x = -100.0000j
+x = .1.is_integer()
+x = 1. .imag
+x = 1E+1.imag
+x = 1E-1.real
+x = 123456789.123456789.hex()
+x = 123456789.123456789E123456789 .real
+x = 123456789E123456789 .conjugate()
+x = 123456789J.real
+x = 123456789.123456789J.__add__(0b1011.bit_length())
+x = 0XB1ACC.conjugate()
+x = 0B1011 .conjugate()
+x = 0O777 .real
+x = 0.000000006 .hex()
+x = -100.0000J
-if (10).real:
+if 10 .real:
...
y = 100[no]
```
## Ruff Output
```py
x = 123456789 .bit_count()
x = (123456).__abs__()
x = .1.is_integer()
x = 1. .imag
x = 1E+1.imag
x = 1E-1.real
x = 123456789.123456789.hex()
x = 123456789.123456789E123456789 .real
x = 123456789E123456789 .conjugate()
x = 123456789J.real
x = 123456789.123456789J.__add__(0b1011.bit_length())
x = 0XB1ACC.conjugate()
x = 0B1011 .conjugate()
x = 0O777 .real
x = 0.000000006 .hex()
x = -100.0000J
if 10 .real:
...
y = 100[no]
y = 100(no)
```
## Black Output
```py
x = (123456789).bit_count()
x = (123456).__abs__()
x = (0.1).is_integer()
x = (1.0).imag
x = (1e1).imag
x = (1e-1).real
x = (123456789.123456789).hex()
x = (123456789.123456789e123456789).real
x = (123456789e123456789).conjugate()
x = 123456789j.real
x = 123456789.123456789j.__add__(0b1011.bit_length())
x = 0xB1ACC.conjugate()
x = 0b1011.conjugate()
x = 0o777.real
x = (0.000000006).hex()
x = -100.0000j
if (10).real:
...
y = 100[no]
y = 100(no)
```

View file

@ -1,14 +1,18 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip.py
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/beginning_backslash.py
---
## Input
```py
a, b = 1, 2
c = 6 # fmt: skip
d = 5
\
print("hello, world")
```
## Black Differences
@ -16,27 +20,32 @@ d = 5
```diff
--- Black
+++ Ruff
@@ -1,3 +1,3 @@
a, b = 1, 2
-c = 6 # fmt: skip
+c = 6 # fmt: skip
d = 5
@@ -1 +1,7 @@
+\
+
+
+
+
+
print("hello, world")
```
## Ruff Output
```py
a, b = 1, 2
c = 6 # fmt: skip
d = 5
\
print("hello, world")
```
## Black Output
```py
a, b = 1, 2
c = 6 # fmt: skip
d = 5
print("hello, world")
```

View file

@ -0,0 +1,54 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/bracketmatch.py
---
## Input
```py
for ((x in {}) or {})['a'] in x:
pass
pem_spam = lambda l, spam = {
"x": 3
}: not spam.get(l.strip())
lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,4 +1,6 @@
-for ((x in {}) or {})["a"] in x:
+for ((x in {}) or {})['a'] in x:
pass
-pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip())
-lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x
+pem_spam = lambda l, spam = {
+ "x": 3
+}: not spam.get(l.strip())
+lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x
```
## Ruff Output
```py
for ((x in {}) or {})['a'] in x:
pass
pem_spam = lambda l, spam = {
"x": 3
}: not spam.get(l.strip())
lambda x=lambda y={1: 3}: y['x':lambda y: {1: 2}]: x
```
## Black Output
```py
for ((x in {}) or {})["a"] in x:
pass
pem_spam = lambda l, spam={"x": 3}: not spam.get(l.strip())
lambda x=lambda y={1: 3}: y["x" : lambda y: {1: 2}]: x
```

View file

@ -0,0 +1,141 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_blank_parentheses.py
---
## Input
```py
class SimpleClassWithBlankParentheses():
pass
class ClassWithSpaceParentheses ( ):
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc():
pass
class NormalClass (
):
def func_for_testing(self, first, second):
sum = first + second
return sum
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,30 +1,23 @@
-class SimpleClassWithBlankParentheses:
+class SimpleClassWithBlankParentheses():
pass
-
-
-class ClassWithSpaceParentheses:
+class ClassWithSpaceParentheses ( ):
first_test_data = 90
second_test_data = 100
-
def test_func(self):
return None
-
+class ClassWithEmptyFunc(object):
-class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
-
-
def class_under_the_func_with_blank_parentheses():
- class InsideFunc:
+ class InsideFunc():
pass
-
-
-class NormalClass:
+class NormalClass (
+):
def func_for_testing(self, first, second):
sum = first + second
return sum
```
## Ruff Output
```py
class SimpleClassWithBlankParentheses():
pass
class ClassWithSpaceParentheses ( ):
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc():
pass
class NormalClass (
):
def func_for_testing(self, first, second):
sum = first + second
return sum
```
## Black Output
```py
class SimpleClassWithBlankParentheses:
pass
class ClassWithSpaceParentheses:
first_test_data = 90
second_test_data = 100
def test_func(self):
return None
class ClassWithEmptyFunc(object):
def func_with_blank_parentheses():
return 5
def public_func_with_blank_parentheses():
return None
def class_under_the_func_with_blank_parentheses():
class InsideFunc:
pass
class NormalClass:
def func_for_testing(self, first, second):
sum = first + second
return sum
```

View file

@ -0,0 +1,559 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/class_methods_new_line.py
---
## Input
```py
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,165 +1,100 @@
class ClassSimplest:
pass
-
-
class ClassWithSingleField:
a = 1
-
-
class ClassWithJustTheDocstring:
"""Just a docstring."""
-
-
class ClassWithInit:
def __init__(self):
pass
-
-
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
-
def __init__(self):
pass
-
-
class ClassWithInitAndVars:
cls_var = 100
-
def __init__(self):
pass
-
-
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
-
cls_var = 100
-
def __init__(self):
pass
-
-
class ClassWithDecoInit:
@deco
def __init__(self):
pass
-
-
class ClassWithDecoInitAndVars:
cls_var = 100
-
@deco
def __init__(self):
pass
-
-
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
-
cls_var = 100
-
@deco
def __init__(self):
pass
-
-
class ClassSimplestWithInner:
class Inner:
pass
-
-
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
-
def __init__(self):
pass
-
-
class ClassWithSingleFieldWithInner:
a = 1
-
class Inner:
pass
-
-
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
-
class Inner:
pass
-
-
class ClassWithInitWithInner:
class Inner:
pass
-
def __init__(self):
pass
-
-
class ClassWithInitAndVarsWithInner:
cls_var = 100
-
class Inner:
pass
-
def __init__(self):
pass
-
-
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
-
cls_var = 100
-
class Inner:
pass
-
def __init__(self):
pass
-
-
class ClassWithDecoInitWithInner:
class Inner:
pass
-
@deco
def __init__(self):
pass
-
-
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
-
class Inner:
pass
-
@deco
def __init__(self):
pass
-
-
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
-
cls_var = 100
-
class Inner:
pass
-
@deco
def __init__(self):
pass
-
-
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
-
class Inner:
pass
-
cls_var = 100
-
@deco
def __init__(self):
pass
```
## Ruff Output
```py
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
```
## Black Output
```py
class ClassSimplest:
pass
class ClassWithSingleField:
a = 1
class ClassWithJustTheDocstring:
"""Just a docstring."""
class ClassWithInit:
def __init__(self):
pass
class ClassWithTheDocstringAndInit:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithInitAndVars:
cls_var = 100
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
def __init__(self):
pass
class ClassWithDecoInit:
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVars:
cls_var = 100
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstring:
"""Test class"""
cls_var = 100
@deco
def __init__(self):
pass
class ClassSimplestWithInner:
class Inner:
pass
class ClassSimplestWithInnerWithDocstring:
class Inner:
"""Just a docstring."""
def __init__(self):
pass
class ClassWithSingleFieldWithInner:
a = 1
class Inner:
pass
class ClassWithJustTheDocstringWithInner:
"""Just a docstring."""
class Inner:
pass
class ClassWithInitWithInner:
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
def __init__(self):
pass
class ClassWithDecoInitWithInner:
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsWithInner:
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner:
"""Test class"""
cls_var = 100
class Inner:
pass
@deco
def __init__(self):
pass
class ClassWithDecoInitAndVarsAndDocstringWithInner2:
"""Test class"""
class Inner:
pass
cls_var = 100
@deco
def __init__(self):
pass
```

View file

@ -0,0 +1,370 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/collections.py
---
## Input
```py
import core, time, a
from . import A, B, C
# keeps existing trailing comma
from foo import (
bar,
)
# also keeps existing structure
from foo import (
baz,
qux,
)
# `as` works as well
from foo import (
xyzzy as magic,
)
a = {1,2,3,}
b = {
1,2,
3}
c = {
1,
2,
3,
}
x = 1,
y = narf(),
nested = {(1,2,3),(4,5,6),}
nested_no_trailing_comma = {(1,2,3),(4,5,6)}
nested_long_lines = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "cccccccccccccccccccccccccccccccccccccccc", (1, 2, 3), "dddddddddddddddddddddddddddddddddddddddd"]
{"oneple": (1,),}
{"oneple": (1,)}
['ls', 'lsoneple/%s' % (foo,)]
x = {"oneple": (1,)}
y = {"oneple": (1,),}
assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
# looping over a 1-tuple should also not get wrapped
for x in (1,):
pass
for (x,) in (1,), (2,), (3,):
pass
[1, 2, 3,]
division_result_tuple = (6/2,)
print("foo %r", (foo.bar,))
if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
)
if True:
ec2client.get_waiter('instance_stopped').wait(
InstanceIds=[instance.id],
WaiterConfig={
'Delay': 5,
})
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={"Delay": 5,},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id], WaiterConfig={"Delay": 5,},
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -18,44 +18,26 @@
xyzzy as magic,
)
-a = {
- 1,
- 2,
- 3,
-}
-b = {1, 2, 3}
+a = {1,2,3,}
+b = {
+1,2,
+ 3}
c = {
1,
2,
3,
}
-x = (1,)
-y = (narf(),)
-nested = {
- (1, 2, 3),
- (4, 5, 6),
-}
-nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
-nested_long_lines = [
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
- "cccccccccccccccccccccccccccccccccccccccc",
- (1, 2, 3),
- "dddddddddddddddddddddddddddddddddddddddd",
-]
-{
- "oneple": (1,),
-}
+x = 1,
+y = narf(),
+nested = {(1,2,3),(4,5,6),}
+nested_no_trailing_comma = {(1,2,3),(4,5,6)}
+nested_long_lines = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "cccccccccccccccccccccccccccccccccccccccc", (1, 2, 3), "dddddddddddddddddddddddddddddddddddddddd"]
+{"oneple": (1,),}
{"oneple": (1,)}
-["ls", "lsoneple/%s" % (foo,)]
+['ls', 'lsoneple/%s' % (foo,)]
x = {"oneple": (1,)}
-y = {
- "oneple": (1,),
-}
-assert False, (
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s"
- % bar
-)
+y = {"oneple": (1,),}
+assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
# looping over a 1-tuple should also not get wrapped
for x in (1,):
@@ -63,13 +45,9 @@
for (x,) in (1,), (2,), (3,):
pass
-[
- 1,
- 2,
- 3,
-]
+[1, 2, 3,]
-division_result_tuple = (6 / 2,)
+division_result_tuple = (6/2,)
print("foo %r", (foo.bar,))
if True:
@@ -79,21 +57,15 @@
)
if True:
- ec2client.get_waiter("instance_stopped").wait(
+ ec2client.get_waiter('instance_stopped').wait(
InstanceIds=[instance.id],
WaiterConfig={
- "Delay": 5,
- },
- )
+ 'Delay': 5,
+ })
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
- WaiterConfig={
- "Delay": 5,
- },
+ WaiterConfig={"Delay": 5,},
)
ec2client.get_waiter("instance_stopped").wait(
- InstanceIds=[instance.id],
- WaiterConfig={
- "Delay": 5,
- },
+ InstanceIds=[instance.id], WaiterConfig={"Delay": 5,},
)
```
## Ruff Output
```py
import core, time, a
from . import A, B, C
# keeps existing trailing comma
from foo import (
bar,
)
# also keeps existing structure
from foo import (
baz,
qux,
)
# `as` works as well
from foo import (
xyzzy as magic,
)
a = {1,2,3,}
b = {
1,2,
3}
c = {
1,
2,
3,
}
x = 1,
y = narf(),
nested = {(1,2,3),(4,5,6),}
nested_no_trailing_comma = {(1,2,3),(4,5,6)}
nested_long_lines = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", "cccccccccccccccccccccccccccccccccccccccc", (1, 2, 3), "dddddddddddddddddddddddddddddddddddddddd"]
{"oneple": (1,),}
{"oneple": (1,)}
['ls', 'lsoneple/%s' % (foo,)]
x = {"oneple": (1,)}
y = {"oneple": (1,),}
assert False, ("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s" % bar)
# looping over a 1-tuple should also not get wrapped
for x in (1,):
pass
for (x,) in (1,), (2,), (3,):
pass
[1, 2, 3,]
division_result_tuple = (6/2,)
print("foo %r", (foo.bar,))
if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
)
if True:
ec2client.get_waiter('instance_stopped').wait(
InstanceIds=[instance.id],
WaiterConfig={
'Delay': 5,
})
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={"Delay": 5,},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id], WaiterConfig={"Delay": 5,},
)
```
## Black Output
```py
import core, time, a
from . import A, B, C
# keeps existing trailing comma
from foo import (
bar,
)
# also keeps existing structure
from foo import (
baz,
qux,
)
# `as` works as well
from foo import (
xyzzy as magic,
)
a = {
1,
2,
3,
}
b = {1, 2, 3}
c = {
1,
2,
3,
}
x = (1,)
y = (narf(),)
nested = {
(1, 2, 3),
(4, 5, 6),
}
nested_no_trailing_comma = {(1, 2, 3), (4, 5, 6)}
nested_long_lines = [
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"cccccccccccccccccccccccccccccccccccccccc",
(1, 2, 3),
"dddddddddddddddddddddddddddddddddddddddd",
]
{
"oneple": (1,),
}
{"oneple": (1,)}
["ls", "lsoneple/%s" % (foo,)]
x = {"oneple": (1,)}
y = {
"oneple": (1,),
}
assert False, (
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa wraps %s"
% bar
)
# looping over a 1-tuple should also not get wrapped
for x in (1,):
pass
for (x,) in (1,), (2,), (3,):
pass
[
1,
2,
3,
]
division_result_tuple = (6 / 2,)
print("foo %r", (foo.bar,))
if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
)
if True:
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={
"Delay": 5,
},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={
"Delay": 5,
},
)
ec2client.get_waiter("instance_stopped").wait(
InstanceIds=[instance.id],
WaiterConfig={
"Delay": 5,
},
)
```

View file

@ -0,0 +1,64 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comment_after_escaped_newline.py
---
## Input
```py
def bob(): \
# pylint: disable=W9016
pass
def bobtwo(): \
\
# some comment here
pass
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,6 +1,9 @@
-def bob(): # pylint: disable=W9016
+def bob(): \
+ # pylint: disable=W9016
pass
-def bobtwo(): # some comment here
+def bobtwo(): \
+ \
+ # some comment here
pass
```
## Ruff Output
```py
def bob(): \
# pylint: disable=W9016
pass
def bobtwo(): \
\
# some comment here
pass
```
## Black Output
```py
def bob(): # pylint: disable=W9016
pass
def bobtwo(): # some comment here
pass
```

View file

@ -178,119 +178,262 @@ instruction()#comment with bad spacing
```diff
--- Black
+++ Ruff
@@ -72,7 +72,11 @@
@@ -1,39 +1,40 @@
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent, # NOT DRY
+ MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
- MyLovelyCompanyTeamProjectComponent as component, # DRY
+ MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.
__all__ = [
# Super-special typing primitives.
- "Any",
- "Callable",
- "ClassVar",
+ 'Any',
+ 'Callable',
+ 'ClassVar',
+
# ABCs (from collections.abc).
- "AbstractSet", # collections.abc.Set.
- "ByteString",
- "Container",
+ 'AbstractSet', # collections.abc.Set.
+ 'ByteString',
+ 'Container',
+
# Concrete collection types.
- "Counter",
- "Deque",
- "Dict",
- "DefaultDict",
- "List",
- "Set",
- "FrozenSet",
- "NamedTuple", # Not really a type.
- "Generator",
+ 'Counter',
+ 'Deque',
+ 'Dict',
+ 'DefaultDict',
+ 'List',
+ 'Set',
+ 'FrozenSet',
+ 'NamedTuple', # Not really a type.
+ 'Generator',
]
not_shareables = [
# singletons
True,
False,
- NotImplemented,
- ...,
+ NotImplemented, ...,
# builtin types and objects
type,
object,
@@ -48,20 +49,23 @@
SubBytes(b"spam"),
]
-if "PYTHON" in os.environ:
+if 'PYTHON' in os.environ:
add_compiler(compiler_from_env())
else:
# for compiler in compilers.values():
- # add_compiler(compiler)
+ # add_compiler(compiler)
add_compiler(compilers[(7.0, 32)])
# add_compiler(compilers[(7.1, 64)])
-
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
- parameters.children = [children[0], body, children[-1]] # (1 # )1
parameters.children = [
+ children[0], # (1
+ body,
+ children[-1] # )1
+ ]
+ parameters.children = [
children[0],
body,
children[-1], # type: ignore
@@ -73,49 +77,42 @@
parameters.children[-1], # )2
]
- parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore
+ parameters.children = [
+ parameters.what_if_this_was_actually_long.children[0],
+ body,
+ parameters.children[-1],
+ ] # type: ignore
if (
self._proc is not None
# has the child process finished?
@@ -103,35 +107,35 @@
parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore
- if (
- self._proc is not None
- # has the child process finished?
- and self._returncode is None
- # the child process has finished, but the
- # transport hasn't been notified yet?
- and self._proc.poll() is None
- ):
+ if (self._proc is not None
+ # has the child process finished?
+ and self._returncode is None
+ # the child process has finished, but the
+ # transport hasn't been notified yet?
+ and self._proc.poll() is None):
pass
# no newline before or after
short = [
- # one
- 1,
- # two
- 2,
- ]
+ # one
+ 1,
+ # two
+ 2]
# no newline after
- call(
- arg1,
- arg2,
- """
+ call(arg1, arg2, """
short
-""",
- arg3=True,
- )
+""", arg3=True)
############################################################################
call2(
- # short
+ #short
arg1,
- arg1,
- # but
+ #but
arg2,
- arg2,
- # multiline
+ #multiline
"""
- """
+ #short
+ arg1,
+ #but
+ arg2,
+ #multiline
+ """
short
""",
# yup
arg3=True,
)
- lcomp = [
- # yup
- arg3=True,
- )
+ # yup
+ arg3=True)
lcomp = [
- element for element in collection if element is not None # yup # yup # right
- ]
+ lcomp = [element for element in collection if element is not None] # yup # yup # right
+ element # yup
+ for element in collection # yup
+ if element is not None # right
]
lcomp2 = [
# hello
element
- # yup
- for element in collection
- # right
- if element is not None
+ for # yup
+ element in collection
+ if # right
+ element
+ is not None
@@ -127,7 +124,7 @@
]
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
- # yup
- for element in collection.select_elements()
- # right
- if element is not None
+ for # yup
+ element in collection.select_elements()
+ if # right
+ element
+ is not None
]
while True:
if False:
@@ -167,7 +171,7 @@
- element.split("\n", 1)[0]
+ element.split('\n', 1)[0]
# yup
for element in collection.select_elements()
# right
@@ -140,34 +137,26 @@
# and round and round we go
# and round and round we go
- # let's return
+ # let's return
return Node(
syms.simple_stmt,
- [Node(statement, result), Leaf(token.NEWLINE, "\n")], # FIXME: \r\n?
+ [
+ Node(statement, result),
+ Leaf(token.NEWLINE, '\n') # FIXME: \r\n?
+ ],
)
-
-CONFIG_FILES = (
- [
- CONFIG_FILE,
- ]
- + SHARED_CONFIG_FILES
- + USER_CONFIG_FILES
-) # type: Final
+CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
-
class Test:
def _init_host(self, parsed) -> None:
- if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore
+ if (parsed.hostname is None or # type: ignore
+ not parsed.hostname.strip()):
pass
-
#######################
### SECTION COMMENT ###
#######################
-instruction() # comment with bad spacing
+instruction() #comment with bad spacing
# END COMMENTS
# MORE END COMMENTS
-
-# END COMMENTS
-# MORE END COMMENTS
+instruction()#comment with bad spacing
```
## Ruff Output
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
MyLovelyCompanyTeamProjectComponent # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
MyLovelyCompanyTeamProjectComponent as component # DRY
)
# Please keep __all__ alphabetized within each category.
__all__ = [
# Super-special typing primitives.
"Any",
"Callable",
"ClassVar",
'Any',
'Callable',
'ClassVar',
# ABCs (from collections.abc).
"AbstractSet", # collections.abc.Set.
"ByteString",
"Container",
'AbstractSet', # collections.abc.Set.
'ByteString',
'Container',
# Concrete collection types.
"Counter",
"Deque",
"Dict",
"DefaultDict",
"List",
"Set",
"FrozenSet",
"NamedTuple", # Not really a type.
"Generator",
'Counter',
'Deque',
'Dict',
'DefaultDict',
'List',
'Set',
'FrozenSet',
'NamedTuple', # Not really a type.
'Generator',
]
not_shareables = [
# singletons
True,
False,
NotImplemented,
...,
NotImplemented, ...,
# builtin types and objects
type,
object,
@ -305,19 +448,22 @@ not_shareables = [
SubBytes(b"spam"),
]
if "PYTHON" in os.environ:
if 'PYTHON' in os.environ:
add_compiler(compiler_from_env())
else:
# for compiler in compilers.values():
# add_compiler(compiler)
# add_compiler(compiler)
add_compiler(compilers[(7.0, 32)])
# add_compiler(compilers[(7.1, 64)])
# Comment before function.
def inline_comments_in_brackets_ruin_everything():
if typedargslist:
parameters.children = [children[0], body, children[-1]] # (1 # )1
parameters.children = [
children[0], # (1
body,
children[-1] # )1
]
parameters.children = [
children[0],
body,
@ -329,70 +475,59 @@ def inline_comments_in_brackets_ruin_everything():
body,
parameters.children[-1], # )2
]
parameters.children = [
parameters.what_if_this_was_actually_long.children[0],
body,
parameters.children[-1],
] # type: ignore
if (
self._proc is not None
# has the child process finished?
and self._returncode is None
# the child process has finished, but the
# transport hasn't been notified yet?
and self._proc.poll() is None
):
parameters.children = [parameters.what_if_this_was_actually_long.children[0], body, parameters.children[-1]] # type: ignore
if (self._proc is not None
# has the child process finished?
and self._returncode is None
# the child process has finished, but the
# transport hasn't been notified yet?
and self._proc.poll() is None):
pass
# no newline before or after
short = [
# one
1,
# two
2,
]
# one
1,
# two
2]
# no newline after
call(
arg1,
arg2,
"""
call(arg1, arg2, """
short
""",
arg3=True,
)
""", arg3=True)
############################################################################
call2(
#short
arg1,
#but
arg2,
#multiline
"""
#short
arg1,
#but
arg2,
#multiline
"""
short
""",
# yup
arg3=True,
)
lcomp = [element for element in collection if element is not None] # yup # yup # right
# yup
arg3=True)
lcomp = [
element # yup
for element in collection # yup
if element is not None # right
]
lcomp2 = [
# hello
element
for # yup
element in collection
if # right
element
is not None
# yup
for element in collection
# right
if element is not None
]
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
for # yup
element in collection.select_elements()
if # right
element
is not None
element.split('\n', 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
while True:
if False:
@ -401,37 +536,29 @@ short
# and round and round we go
# and round and round we go
# let's return
# let's return
return Node(
syms.simple_stmt,
[Node(statement, result), Leaf(token.NEWLINE, "\n")], # FIXME: \r\n?
[
Node(statement, result),
Leaf(token.NEWLINE, '\n') # FIXME: \r\n?
],
)
CONFIG_FILES = (
[
CONFIG_FILE,
]
+ SHARED_CONFIG_FILES
+ USER_CONFIG_FILES
) # type: Final
CONFIG_FILES = [CONFIG_FILE, ] + SHARED_CONFIG_FILES + USER_CONFIG_FILES # type: Final
class Test:
def _init_host(self, parsed) -> None:
if parsed.hostname is None or not parsed.hostname.strip(): # type: ignore
if (parsed.hostname is None or # type: ignore
not parsed.hostname.strip()):
pass
#######################
### SECTION COMMENT ###
#######################
instruction() #comment with bad spacing
# END COMMENTS
# MORE END COMMENTS
instruction()#comment with bad spacing
```
## Black Output

View file

@ -1,189 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments3.py
---
## Input
```py
# The percent-percent comments are Spyder IDE cells.
# %%
def func():
x = """
a really long string
"""
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
embedded = []
for exc in exc_value.exceptions:
if exc not in _seen:
embedded.append(
# This should be left alone (before)
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# This should be left alone (after)
)
# everything is fine if the expression isn't nested
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# %%
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -9,10 +9,11 @@
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
- # yup
- for element in collection.select_elements()
- # right
- if element is not None
+ for # yup
+ element in collection.select_elements()
+ if # right
+ element
+ is not None
]
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
```
## Ruff Output
```py
# The percent-percent comments are Spyder IDE cells.
# %%
def func():
x = """
a really long string
"""
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
for # yup
element in collection.select_elements()
if # right
element
is not None
]
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
embedded = []
for exc in exc_value.exceptions:
if exc not in _seen:
embedded.append(
# This should be left alone (before)
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# This should be left alone (after)
)
# everything is fine if the expression isn't nested
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# %%
```
## Black Output
```py
# The percent-percent comments are Spyder IDE cells.
# %%
def func():
x = """
a really long string
"""
lcomp3 = [
# This one is actually too long to fit in a single line.
element.split("\n", 1)[0]
# yup
for element in collection.select_elements()
# right
if element is not None
]
# Capture each of the exceptions in the MultiError along with each of their causes and contexts
if isinstance(exc_value, MultiError):
embedded = []
for exc in exc_value.exceptions:
if exc not in _seen:
embedded.append(
# This should be left alone (before)
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# This should be left alone (after)
)
# everything is fine if the expression isn't nested
traceback.TracebackException.from_exception(
exc,
limit=limit,
lookup_lines=lookup_lines,
capture_locals=capture_locals,
# copy the set of _seen exceptions so that duplicates
# shared between sub-exceptions are not omitted
_seen=set(_seen),
)
# %%
```

View file

@ -1,435 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments4.py
---
## Input
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -10,39 +10,50 @@
@pytest.mark.parametrize(
("post_data", "message"),
[
- # metadata_version errors.
- (
+ (# metadata_version errors.
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
- {"metadata_version": "-1"},
+ {
+ "metadata_version": "-1",
+ },
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
- # name errors.
- (
- {"metadata_version": "1.2"},
+ (# name errors.
+ {
+ "metadata_version": "1.2",
+ },
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
- {"metadata_version": "1.2", "name": "foo-"},
+ {
+ "metadata_version": "1.2",
+ "name": "foo-",
+ },
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
- # version errors.
- (
- {"metadata_version": "1.2", "name": "example"},
+ (# version errors.
+ {
+ "metadata_version": "1.2",
+ "name": "example",
+ },
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
- {"metadata_version": "1.2", "name": "example", "version": "dog"},
+ {
+ "metadata_version": "1.2",
+ "name": "example",
+ "version": "dog",
+ },
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
@@ -50,45 +61,34 @@
],
)
def test_fails_invalid_post_data(
- self, pyramid_config, db_request, post_data, message
+ self,
+ pyramid_config,
+ db_request,
+ post_data,
+ message,
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
- results = (
- User.query.filter(User.foo == "bar")
- .filter( # Because foo.
- db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
- )
- .filter(User.xyz.is_(None))
- # Another comment about the filtering on is_quux goes here.
- .filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
- .order_by(User.created_at.desc())
- .with_for_update(key_share=True)
- .all()
- )
+ results = User.query.filter(User.foo == "bar").filter( # Because foo.
+ db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
+ ).filter(User.xyz.is_(None)).filter(
+ db.not_(User.is_pending.astext.cast(db.Boolean).is_(True))
+ ).order_by(User.created_at.desc()).with_for_update(key_share=True).all()
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
- return (
- User.query.filter(User.foo == "bar")
- .filter(
- db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
- )
- .filter(User.xyz.is_(None))
- )
+ return User.query.filter(User.foo == "bar").filter(
+ db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
+ ).filter(User.xyz.is_(None))
def foo3(list_a, list_b):
- return (
- # Standalone comment but weirdly placed.
- User.query.filter(User.foo == "bar")
- .filter(
- db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
- )
- .filter(User.xyz.is_(None))
- )
+ return # Standalone comment but weirdly placed.
+ User.query.filter(User.foo == "bar").filter(
+ db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
+ ).filter(User.xyz.is_(None))
```
## Ruff Output
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
(# metadata_version errors.
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{
"metadata_version": "-1",
},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
(# name errors.
{
"metadata_version": "1.2",
},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{
"metadata_version": "1.2",
"name": "foo-",
},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
(# version errors.
{
"metadata_version": "1.2",
"name": "example",
},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{
"metadata_version": "1.2",
"name": "example",
"version": "dog",
},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self,
pyramid_config,
db_request,
post_data,
message,
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = User.query.filter(User.foo == "bar").filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
).filter(User.xyz.is_(None)).filter(
db.not_(User.is_pending.astext.cast(db.Boolean).is_(True))
).order_by(User.created_at.desc()).with_for_update(key_share=True).all()
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return User.query.filter(User.foo == "bar").filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
).filter(User.xyz.is_(None))
def foo3(list_a, list_b):
return # Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar").filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
).filter(User.xyz.is_(None))
```
## Black Output
```py
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent, # NOT DRY
)
from com.my_lovely_company.my_lovely_team.my_lovely_project.my_lovely_component import (
MyLovelyCompanyTeamProjectComponent as component, # DRY
)
class C:
@pytest.mark.parametrize(
("post_data", "message"),
[
# metadata_version errors.
(
{},
"None is an invalid value for Metadata-Version. Error: This field is"
" required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "-1"},
"'-1' is an invalid value for Metadata-Version. Error: Unknown Metadata"
" Version see"
" https://packaging.python.org/specifications/core-metadata",
),
# name errors.
(
{"metadata_version": "1.2"},
"'' is an invalid value for Name. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "foo-"},
"'foo-' is an invalid value for Name. Error: Must start and end with a"
" letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
# version errors.
(
{"metadata_version": "1.2", "name": "example"},
"'' is an invalid value for Version. Error: This field is required. see"
" https://packaging.python.org/specifications/core-metadata",
),
(
{"metadata_version": "1.2", "name": "example", "version": "dog"},
"'dog' is an invalid value for Version. Error: Must start and end with"
" a letter or numeral and contain only ascii numeric and '.', '_' and"
" '-'. see https://packaging.python.org/specifications/core-metadata",
),
],
)
def test_fails_invalid_post_data(
self, pyramid_config, db_request, post_data, message
):
pyramid_config.testing_securitypolicy(userid=1)
db_request.POST = MultiDict(post_data)
def foo(list_a, list_b):
results = (
User.query.filter(User.foo == "bar")
.filter( # Because foo.
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
# Another comment about the filtering on is_quux goes here.
.filter(db.not_(User.is_pending.astext.cast(db.Boolean).is_(True)))
.order_by(User.created_at.desc())
.with_for_update(key_share=True)
.all()
)
return results
def foo2(list_a, list_b):
# Standalone comment reasonably placed.
return (
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
def foo3(list_a, list_b):
return (
# Standalone comment but weirdly placed.
User.query.filter(User.foo == "bar")
.filter(
db.or_(User.field_a.astext.in_(list_a), User.field_b.astext.in_(list_b))
)
.filter(User.xyz.is_(None))
)
```

View file

@ -1,279 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments5.py
---
## Input
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -23,7 +23,6 @@
try:
with open(some_other_file) as w:
w.write(data)
-
except OSError:
print("problems")
@@ -41,18 +40,18 @@
# leading 1
@deco1
-# leading 2
-@deco2(with_args=True)
-# leading 3
-@deco3
+@# leading 2
+deco2(with_args=True)
+@# leading 3
+deco3
def decorated1():
...
# leading 1
@deco1
-# leading 2
-@deco2(with_args=True)
+@# leading 2
+deco2(with_args=True)
# leading function comment
def decorated1():
...
```
## Ruff Output
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
@# leading 2
deco2(with_args=True)
@# leading 3
deco3
def decorated1():
...
# leading 1
@deco1
@# leading 2
deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```
## Black Output
```py
while True:
if something.changed:
do.stuff() # trailing comment
# Comment belongs to the `if` block.
# This one belongs to the `while` block.
# Should this one, too? I guess so.
# This one is properly standalone now.
for i in range(100):
# first we do this
if i % 33 == 0:
break
# then we do this
print(i)
# and finally we loop around
with open(some_temp_file) as f:
data = f.read()
try:
with open(some_other_file) as w:
w.write(data)
except OSError:
print("problems")
import sys
# leading function comment
def wat():
...
# trailing function comment
# SECTION COMMENT
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
def decorated1():
...
# leading 1
@deco1
# leading 2
@deco2(with_args=True)
# leading function comment
def decorated1():
...
# Note: this is fixed in
# Preview.empty_lines_before_class_or_def_with_leading_comments.
# In the current style, the user will have to split those lines by hand.
some_instruction
# This comment should be split from `some_instruction` by two lines but isn't.
def g():
...
if __name__ == "__main__":
main()
```

View file

@ -1,456 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments6.py
---
## Input
```py
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -31,8 +31,8 @@
def f(
arg, # type: int
*args, # type: *Any
- default=False, # type: bool
- **kwargs, # type: **Any
+ default=False, # type: bool # type: **Any
+ **kwargs,
):
# type: (...) -> None
pass
@@ -49,9 +49,7 @@
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
- another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
- 3
- ) # type: int
+ another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = 3 # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
@@ -100,19 +98,33 @@
)
c = call(
- "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
+ "aaaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaa",
+ "aaaaaaaa", # type: ignore
)
-result = ( # aaa
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-)
+result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa
-AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
+AAAAAAAAAAAAA = (
+ [AAAAAAAAAAAAA]
+ + SHARED_AAAAAAAAAAAAA
+ + USER_AAAAAAAAAAAAA
+ + AAAAAAAAAAAAA
+) # type: ignore
call_to_some_function_asdf(
foo,
- [AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
+ [
+ AAAAAAAAAAAAAAAAAAAAAAA,
+ AAAAAAAAAAAAAAAAAAAAAAA,
+ AAAAAAAAAAAAAAAAAAAAAAA,
+ BBBBBBBBBBBB,
+ ], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
```
## Ruff Output
```py
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool # type: **Any
**kwargs,
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = 3 # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa",
"aaaaaaaa",
"aaaaaaaa",
"aaaaaaaa",
"aaaaaaaa",
"aaaaaaaa",
"aaaaaaaa", # type: ignore
)
result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa
AAAAAAAAAAAAA = (
[AAAAAAAAAAAAA]
+ SHARED_AAAAAAAAAAAAA
+ USER_AAAAAAAAAAAAA
+ AAAAAAAAAAAAA
) # type: ignore
call_to_some_function_asdf(
foo,
[
AAAAAAAAAAAAAAAAAAAAAAA,
AAAAAAAAAAAAAAAAAAAAAAA,
AAAAAAAAAAAAAAAAAAAAAAA,
BBBBBBBBBBBB,
], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
```
## Black Output
```py
from typing import Any, Tuple
def f(
a, # type: int
):
pass
# test type comments
def f(a, b, c, d, e, f, g, h, i):
# type: (int, int, int, int, int, int, int, int, int) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
e, # type: int
f, # type: int
g, # type: int
h, # type: int
i, # type: int
):
# type: (...) -> None
pass
def f(
arg, # type: int
*args, # type: *Any
default=False, # type: bool
**kwargs, # type: **Any
):
# type: (...) -> None
pass
def f(
a, # type: int
b, # type: int
c, # type: int
d, # type: int
):
# type: (...) -> None
element = 0 # type: int
another_element = 1 # type: float
another_element_with_long_name = 2 # type: int
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style = (
3
) # type: int
an_element_with_a_long_value = calls() or more_calls() and more() # type: bool
tup = (
another_element,
another_really_really_long_element_with_a_unnecessarily_long_name_to_describe_what_it_does_enterprise_style,
) # type: Tuple[int, int]
a = (
element
+ another_element
+ another_element_with_long_name
+ element
+ another_element
+ another_element_with_long_name
) # type: int
def f(
x, # not a type comment
y, # type: int
):
# type: (...) -> None
pass
def f(
x, # not a type comment
): # type: (int) -> None
pass
def func(
a=some_list[0], # type: int
): # type: () -> int
c = call(
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
0.0123,
0.0456,
0.0789,
a[-1], # type: ignore
)
c = call(
"aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore
)
result = ( # aaa
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
AAAAAAAAAAAAA = [AAAAAAAAAAAAA] + SHARED_AAAAAAAAAAAAA + USER_AAAAAAAAAAAAA + AAAAAAAAAAAAA # type: ignore
call_to_some_function_asdf(
foo,
[AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, AAAAAAAAAAAAAAAAAAAAAAA, BBBBBBBBBBBB], # type: ignore
)
aaaaaaaaaaaaa, bbbbbbbbb = map(list, map(itertools.chain.from_iterable, zip(*items))) # type: ignore[arg-type]
```

View file

@ -0,0 +1,47 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/comments8.py
---
## Input
```py
# The percent-percent comments are Spyder IDE cells.
# Both `#%%`` and `# %%` are accepted, so `black` standardises
# to the latter.
#%%
# %%
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,6 +0,0 @@
-# The percent-percent comments are Spyder IDE cells.
-# Both `#%%`` and `# %%` are accepted, so `black` standardises
-# to the latter.
-
-# %%
-# %%
```
## Ruff Output
```py
```
## Black Output
```py
# The percent-percent comments are Spyder IDE cells.
# Both `#%%`` and `# %%` are accepted, so `black` standardises
# to the latter.
# %%
# %%
```

View file

@ -152,96 +152,115 @@ def bar():
```diff
--- Black
+++ Ruff
@@ -35,9 +35,10 @@
@@ -1,16 +1,12 @@
# Test for https://github.com/psf/black/issues/246.
some = statement
-
-
# This comment should be split from the statement above by two lines.
def function():
pass
some = statement
+
+
# This should be stick to the statement above
-
-
# This multiline comments section
# should be split from the statement
# above by two lines.
@@ -19,16 +15,12 @@
some = statement
-
-
# This comment should be split from the statement above by two lines.
async def async_function():
pass
some = statement
-
-
# This comment should be split from the statement above by two lines.
class MyClass:
pass
@@ -36,7 +28,6 @@
some = statement
# This should be stick to the statement above
-
# This should be split from the above by two lines
class MyClassWithComplexLeadingComments:
pass
@@ -57,11 +58,11 @@
@@ -45,16 +36,12 @@
# leading 1
@deco1
-# leading 2
+@# leading 2
# leading 2 extra
-@deco2(with_args=True)
-# leading 3
-@deco3
+deco2(with_args=True)
+@# leading 3
+deco3
# leading 4
def decorated():
pass
@@ -72,11 +73,10 @@
# leading 1
@deco1
-# leading 2
-@deco2(with_args=True)
class ClassWithDocstring:
"""A docstring."""
-
-# leading 3 that already has an empty line
-@deco3
+@# leading 2
+deco2(with_args=True)
+@# leading 3 that already has an empty line
+deco3
# leading 4
def decorated_with_split_leading_comments():
-
# Leading comment after a class with just a docstring
class MyClassAfterAnotherClassWithDocstring:
pass
@@ -87,10 +87,10 @@
some = statement
-
-
# leading 1
@deco1
-# leading 2
-@deco2(with_args=True)
-# leading 3
-@deco3
+@# leading 2
+deco2(with_args=True)
+@# leading 3
+deco3
# leading 2
@@ -68,8 +55,6 @@
# leading 4 that already has an empty line
def decorated_with_split_leading_comments():
@@ -99,6 +99,7 @@
def main():
if a:
+
some = statement
-
-
# leading 1
@deco1
# leading 2
@@ -83,8 +68,6 @@
some = statement
-
-
# leading 1
@deco1
# leading 2
@@ -102,11 +85,9 @@
# Leading comment before inline function
def inline():
pass
@@ -108,12 +109,14 @@
-
# Another leading comment
def another_inline():
pass
-
else:
+
# More leading comments
def inline_after_else():
pass
if a:
+
@@ -117,11 +98,9 @@
# Leading comment before "top-level inline" function
def top_level_quote_inline():
pass
@@ -123,6 +126,7 @@
-
# Another leading comment
def another_top_level_quote_inline_inline():
pass
-
else:
+
# More leading comments
def top_level_quote_inline_after_else():
pass
@@ -153,7 +132,6 @@
# Trailing comment that belongs to this function.
# NOTE this comment only has one empty line below, and the formatter
# should enforce two blank lines.
-
@decorator1
# A standalone comment
```
## Ruff Output
@ -250,16 +269,12 @@ def bar():
# Test for https://github.com/psf/black/issues/246.
some = statement
# This comment should be split from the statement above by two lines.
def function():
pass
some = statement
# This multiline comments section
# should be split from the statement
# above by two lines.
@ -268,24 +283,18 @@ def function():
some = statement
# This comment should be split from the statement above by two lines.
async def async_function():
pass
some = statement
# This comment should be split from the statement above by two lines.
class MyClass:
pass
some = statement
# This should be stick to the statement above
# This should be split from the above by two lines
@ -295,51 +304,44 @@ class MyClassWithComplexLeadingComments:
class ClassWithDocstring:
"""A docstring."""
# Leading comment after a class with just a docstring
class MyClassAfterAnotherClassWithDocstring:
pass
some = statement
# leading 1
@deco1
@# leading 2
# leading 2
# leading 2 extra
deco2(with_args=True)
@# leading 3
deco3
@deco2(with_args=True)
# leading 3
@deco3
# leading 4
def decorated():
pass
some = statement
# leading 1
@deco1
@# leading 2
deco2(with_args=True)
@# leading 3 that already has an empty line
deco3
# leading 2
@deco2(with_args=True)
# leading 3 that already has an empty line
@deco3
# leading 4
def decorated_with_split_leading_comments():
pass
some = statement
# leading 1
@deco1
@# leading 2
deco2(with_args=True)
@# leading 3
deco3
# leading 2
@deco2(with_args=True)
# leading 3
@deco3
# leading 4 that already has an empty line
def decorated_with_split_leading_comments():
@ -348,34 +350,26 @@ def decorated_with_split_leading_comments():
def main():
if a:
# Leading comment before inline function
def inline():
pass
# Another leading comment
def another_inline():
pass
else:
# More leading comments
def inline_after_else():
pass
if a:
# Leading comment before "top-level inline" function
def top_level_quote_inline():
pass
# Another leading comment
def another_top_level_quote_inline_inline():
pass
else:
# More leading comments
def top_level_quote_inline_after_else():
pass
@ -407,7 +401,6 @@ def foo():
# NOTE this comment only has one empty line below, and the formatter
# should enforce two blank lines.
@decorator1
# A standalone comment
def bar():

View file

@ -32,32 +32,34 @@ def function(a:int=42):
```diff
--- Black
+++ Ruff
@@ -1,23 +1,22 @@
from .config import (
ConfigTypeAttributes,
Int,
@@ -1,23 +1,19 @@
-from .config import (
- ConfigTypeAttributes,
- Int,
- Path, # String,
- # DEFAULT_TYPE_ATTRIBUTES,
+ Path, # String,
+from .config import ( ConfigTypeAttributes, Int, Path, # String,
+ # DEFAULT_TYPE_ATTRIBUTES,
)
-result = 1 # A simple comment
-result = (1,) # Another one
+result = 1 # A simple comment
+result = (1,) # Another one
+result = ( 1, ) # Another one
-result = 1 #  type: ignore
-result = 1 # This comment is talking about type: ignore
-square = Square(4) #  type: Optional[Square]
+result = 1 # type: ignore
+result = 1 # This comment is talking about type: ignore
+square = Square(4) # type: Optional[Square]
+result = 1 # type: ignore
+result = 1# This comment is talking about type: ignore
+square = Square(4) # type: Optional[Square]
def function(a: int = 42):
-
-def function(a: int = 42):
- """This docstring is already formatted
- a
- b
+def function(a:int=42):
+ """ This docstring is already formatted
+ a
+ b
@ -71,21 +73,18 @@ def function(a:int=42):
## Ruff Output
```py
from .config import (
ConfigTypeAttributes,
Int,
Path, # String,
from .config import ( ConfigTypeAttributes, Int, Path, # String,
# DEFAULT_TYPE_ATTRIBUTES,
)
result = 1 # A simple comment
result = (1,) # Another one
result = ( 1, ) # Another one
result = 1 # type: ignore
result = 1 # This comment is talking about type: ignore
square = Square(4) # type: Optional[Square]
result = 1 # type: ignore
result = 1# This comment is talking about type: ignore
square = Square(4) # type: Optional[Square]
def function(a: int = 42):
def function(a:int=42):
""" This docstring is already formatted
a
b

View file

@ -194,274 +194,86 @@ class C:
```diff
--- Black
+++ Ruff
@@ -2,7 +2,8 @@
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
- unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
+ unstyle(str(report)),
+ "1 file reformatted, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
@@ -25,11 +26,8 @@
# Rule 2
and i % 3 == 0
):
- while (
- # Just a comment
- call()
- # Another
- ):
+ while # Just a comment
+ call():
print(i)
@@ -34,7 +34,7 @@
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
@@ -39,116 +37,140 @@
max_items_to_push=num_items,
- batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
+ batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE
).push(
# Only send the first n items.
items=items[:num_items]
)
- return (
- 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
- % (test.name, test.filename, lineno, lname, err)
- )
+ return 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
+ % (test.name, test.filename, lineno, lname, err)
def omitting_trailers(self) -> None:
get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
+ hey_this_is_a_very_long_call,
+ it_has_funny_attributes,
+ really=True,
)[OneLevelIndex]
get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
+ hey_this_is_a_very_long_call,
+ it_has_funny_attributes,
+ really=True,
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
- assignment = (
- some.rather.elaborate.rule() and another.rule.ending_with.index[123]
- )
+ assignment = some.rather.elaborate.rule()
+ and another.rule.ending_with.index[123]
def easy_asserts(self) -> None:
- assert {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
@@ -68,7 +68,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- } == expected, "Not what we expected"
+ assert (
+ {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ == expected
+ ), "Not what we expected"
+ key9: value9
} == expected, "Not what we expected"
- assert expected == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
assert expected == {
@@ -80,7 +80,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- }, "Not what we expected"
+ assert (
+ expected
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ ), "Not what we expected"
+ key9: value9
}, "Not what we expected"
- assert expected == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
assert expected == {
@@ -92,7 +92,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- }
+ assert (
+ expected
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ )
+ key9: value9
}
def tricky_asserts(self) -> None:
- assert {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
@@ -105,7 +105,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- } == expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True
+ assert (
+ {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ == expected(
+ value,
+ is_going_to_be="too long to fit in a single line",
+ srsly=True,
+ )
+ key9: value9
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
- assert {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
@@ -119,7 +119,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- } == expected, (
- "Not what we expected and the message is too long to fit in one line"
- )
+ assert (
+ {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ == expected
+ ), "Not what we expected and the message is too long to fit in one line"
- assert expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True
- ) == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
+ key9: value9
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
@@ -135,7 +135,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- }, "Not what we expected"
+ assert (
+ expected(
+ value,
+ is_going_to_be="too long to fit in a single line",
+ srsly=True,
+ )
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ ), "Not what we expected"
+ key9: value9
}, "Not what we expected"
- assert expected == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
assert expected == {
@@ -147,7 +147,7 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
- }, (
+ assert (
+ expected
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ ), (
+ key9: value9
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
@@ -176,6 +176,6 @@
key6: value6,
key7: value7,
key8: value8,
- key9: value9,
+ key9: value9
}
)
@@ -161,9 +183,8 @@
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
- """ % (
- _C.__init__.__code__.co_firstlineno + 1,
- )
+ """
+ % (_C.__init__.__code__.co_firstlineno + 1,)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
```
## Ruff Output
@ -471,8 +283,7 @@ class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file failed to reformat.",
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
@ -495,151 +306,130 @@ class C:
# Rule 2
and i % 3 == 0
):
while # Just a comment
call():
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE
).push(
# Only send the first n items.
items=items[:num_items]
)
return 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call,
it_has_funny_attributes,
really=True,
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call,
it_has_funny_attributes,
really=True,
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = some.rather.elaborate.rule()
and another.rule.ending_with.index[123]
def easy_asserts(self) -> None:
assert (
{
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
== expected
), "Not what we expected"
assert (
expected
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
), "Not what we expected"
assert (
expected
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}
def tricky_asserts(self) -> None:
assert (
{
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
== expected(
value,
is_going_to_be="too long to fit in a single line",
srsly=True,
)
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert (
{
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
== expected
), "Not what we expected and the message is too long to fit in one line"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert (
expected(
value,
is_going_to_be="too long to fit in a single line",
srsly=True,
)
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
), "Not what we expected"
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}, "Not what we expected"
assert (
expected
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
), (
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
@ -652,8 +442,9 @@ class C:
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
"""
% (_C.__init__.__code__.co_firstlineno + 1,)
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
@ -666,7 +457,7 @@ class C:
key6: value6,
key7: value7,
key8: value8,
key9: value9,
key9: value9
}
)
```

View file

@ -1,860 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/composition.py
---
## Input
```py
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
def tricky_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -2,7 +2,8 @@
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
- unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
+ unstyle(str(report)),
+ "1 file reformatted, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
@@ -25,11 +26,8 @@
# Rule 2
and i % 3 == 0
):
- while (
- # Just a comment
- call()
- # Another
- ):
+ while # Just a comment
+ call():
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
@@ -39,116 +37,140 @@
# Only send the first n items.
items=items[:num_items]
)
- return (
- 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
- % (test.name, test.filename, lineno, lname, err)
- )
+ return 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
+ % (test.name, test.filename, lineno, lname, err)
def omitting_trailers(self) -> None:
get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
+ hey_this_is_a_very_long_call,
+ it_has_funny_attributes,
+ really=True,
)[OneLevelIndex]
get_collection(
- hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
+ hey_this_is_a_very_long_call,
+ it_has_funny_attributes,
+ really=True,
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
- assignment = (
- some.rather.elaborate.rule() and another.rule.ending_with.index[123]
- )
+ assignment = some.rather.elaborate.rule()
+ and another.rule.ending_with.index[123]
def easy_asserts(self) -> None:
- assert {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- } == expected, "Not what we expected"
+ assert (
+ {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ == expected
+ ), "Not what we expected"
- assert expected == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- }, "Not what we expected"
+ assert (
+ expected
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ ), "Not what we expected"
- assert expected == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- }
+ assert (
+ expected
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ )
def tricky_asserts(self) -> None:
- assert {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- } == expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True
+ assert (
+ {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ == expected(
+ value,
+ is_going_to_be="too long to fit in a single line",
+ srsly=True,
+ )
), "Not what we expected"
- assert {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- } == expected, (
- "Not what we expected and the message is too long to fit in one line"
- )
+ assert (
+ {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ == expected
+ ), "Not what we expected and the message is too long to fit in one line"
- assert expected(
- value, is_going_to_be="too long to fit in a single line", srsly=True
- ) == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- }, "Not what we expected"
+ assert (
+ expected(
+ value,
+ is_going_to_be="too long to fit in a single line",
+ srsly=True,
+ )
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ ), "Not what we expected"
- assert expected == {
- key1: value1,
- key2: value2,
- key3: value3,
- key4: value4,
- key5: value5,
- key6: value6,
- key7: value7,
- key8: value8,
- key9: value9,
- }, (
+ assert (
+ expected
+ == {
+ key1: value1,
+ key2: value2,
+ key3: value3,
+ key4: value4,
+ key5: value5,
+ key6: value6,
+ key7: value7,
+ key8: value8,
+ key9: value9,
+ }
+ ), (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
@@ -161,9 +183,8 @@
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
- """ % (
- _C.__init__.__code__.co_firstlineno + 1,
- )
+ """
+ % (_C.__init__.__code__.co_firstlineno + 1,)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
```
## Ruff Output
```py
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while # Just a comment
call():
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items]
)
return 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call,
it_has_funny_attributes,
really=True,
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call,
it_has_funny_attributes,
really=True,
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = some.rather.elaborate.rule()
and another.rule.ending_with.index[123]
def easy_asserts(self) -> None:
assert (
{
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
== expected
), "Not what we expected"
assert (
expected
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
), "Not what we expected"
assert (
expected
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)
def tricky_asserts(self) -> None:
assert (
{
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
== expected(
value,
is_going_to_be="too long to fit in a single line",
srsly=True,
)
), "Not what we expected"
assert (
{
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
== expected
), "Not what we expected and the message is too long to fit in one line"
assert (
expected(
value,
is_going_to_be="too long to fit in a single line",
srsly=True,
)
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
), "Not what we expected"
assert (
expected
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
), (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
"""
% (_C.__init__.__code__.co_firstlineno + 1,)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)
```
## Black Output
```py
class C:
def test(self) -> None:
with patch("black.out", print):
self.assertEqual(
unstyle(str(report)), "1 file reformatted, 1 file failed to reformat."
)
self.assertEqual(
unstyle(str(report)),
"1 file reformatted, 1 file left unchanged, 1 file failed to reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 1 file left unchanged, 1 file failed to"
" reformat.",
)
self.assertEqual(
unstyle(str(report)),
"2 files reformatted, 2 files left unchanged, 2 files failed to"
" reformat.",
)
for i in (a,):
if (
# Rule 1
i % 2 == 0
# Rule 2
and i % 3 == 0
):
while (
# Just a comment
call()
# Another
):
print(i)
xxxxxxxxxxxxxxxx = Yyyy2YyyyyYyyyyy(
push_manager=context.request.resource_manager,
max_items_to_push=num_items,
batch_size=Yyyy2YyyyYyyyyYyyy.FULL_SIZE,
).push(
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
)
def omitting_trailers(self) -> None:
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex]
get_collection(
hey_this_is_a_very_long_call, it_has_funny_attributes, really=True
)[OneLevelIndex][TwoLevelIndex][ThreeLevelIndex][FourLevelIndex]
d[0][1][2][3][4][5][6][7][8][9][10][11][12][13][14][15][16][17][18][19][20][21][
22
]
assignment = (
some.rather.elaborate.rule() and another.rule.ending_with.index[123]
)
def easy_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
def tricky_asserts(self) -> None:
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
), "Not what we expected"
assert {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
} == expected, (
"Not what we expected and the message is too long to fit in one line"
)
assert expected(
value, is_going_to_be="too long to fit in a single line", srsly=True
) == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, "Not what we expected"
assert expected == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}, (
"Not what we expected and the message is too long to fit in one line"
" because it's too long"
)
dis_c_instance_method = """\
%3d 0 LOAD_FAST 1 (x)
2 LOAD_CONST 1 (1)
4 COMPARE_OP 2 (==)
6 LOAD_FAST 0 (self)
8 STORE_ATTR 0 (x)
10 LOAD_CONST 0 (None)
12 RETURN_VALUE
""" % (
_C.__init__.__code__.co_firstlineno + 1,
)
assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)
```

View file

@ -63,7 +63,7 @@ def single_quote_docstring_over_line_limit2():
```diff
--- Black
+++ Ruff
@@ -1,9 +1,13 @@
@@ -1,9 +1,11 @@
def docstring_almost_at_line_limit():
- """long docstring................................................................."""
+ """long docstring.................................................................
@ -72,40 +72,17 @@ def single_quote_docstring_over_line_limit2():
def docstring_almost_at_line_limit_with_prefix():
- f"""long docstring................................................................"""
+ (
+ f"""long docstring................................................................
+ f"""long docstring................................................................
+ """
+ )
def mulitline_docstring_almost_at_line_limit():
@@ -14,10 +18,12 @@
@@ -45,4 +47,4 @@
def mulitline_docstring_almost_at_line_limit_with_prefix():
- f"""long docstring................................................................
+ (
+ f"""long docstring................................................................
..................................................................................
"""
+ )
def docstring_at_line_limit():
@@ -35,9 +41,11 @@
def multiline_docstring_at_line_limit_with_prefix():
- f"""first line----------------------------------------------------------------------
+ (
+ f"""first line----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
+ )
def single_quote_docstring_over_line_limit():
def single_quote_docstring_over_line_limit2():
- "We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
+ 'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).'
```
## Ruff Output
@ -117,10 +94,8 @@ def docstring_almost_at_line_limit():
def docstring_almost_at_line_limit_with_prefix():
(
f"""long docstring................................................................
f"""long docstring................................................................
"""
)
def mulitline_docstring_almost_at_line_limit():
@ -131,12 +106,10 @@ def mulitline_docstring_almost_at_line_limit():
def mulitline_docstring_almost_at_line_limit_with_prefix():
(
f"""long docstring................................................................
f"""long docstring................................................................
..................................................................................
"""
)
def docstring_at_line_limit():
@ -154,11 +127,9 @@ def multiline_docstring_at_line_limit():
def multiline_docstring_at_line_limit_with_prefix():
(
f"""first line----------------------------------------------------------------------
f"""first line----------------------------------------------------------------------
second line----------------------------------------------------------------------"""
)
def single_quote_docstring_over_line_limit():
@ -166,7 +137,7 @@ def single_quote_docstring_over_line_limit():
def single_quote_docstring_over_line_limit2():
"We do not want to put the closing quote on a new line as that is invalid (see GH-3141)."
'We do not want to put the closing quote on a new line as that is invalid (see GH-3141).'
```
## Black Output

View file

@ -234,73 +234,85 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
```diff
--- Black
+++ Ruff
@@ -1,83 +1,85 @@
@@ -1,83 +1,84 @@
class MyClass:
- """Multiline
- class docstring
- """
+ """ Multiline
+ """ Multiline
+ class docstring
+ """
def method(self):
"""Multiline
+
+ def method(self):
"""Multiline
- class docstring
+ method docstring
"""
-
- def method(self):
- """Multiline
- method docstring
- """
+ method docstring
+ """
pass
- pass
+ pass
def foo():
- """This is a docstring with
- some lines of text here
- """
+ """This is a docstring with
- return
+ """This is a docstring with
+ some lines of text here
+ """
return
+ return
def bar():
"""This is another docstring
- """This is another docstring
- with more lines of text
- """
- return
+ '''This is another docstring
+ with more lines of text
+ """
return
+ '''
+ return
def baz():
'''"This" is a string with some
- '''"This" is a string with some
- embedded "quotes"'''
- return
+ '''"This" is a string with some
+ embedded "quotes"'''
return
+ return
def troz():
"""Indentation with tabs
- """Indentation with tabs
- is just as OK
- """
- return
+ '''Indentation with tabs
+ is just as OK
+ """
return
+ '''
+ return
def zort():
"""Another
- """Another
- multiline
- docstring
- """
- pass
-
+ """Another
+ multiline
+ docstring
+ """
pass
+ pass
def poit():
"""
- """
- Lorem ipsum dolor sit amet.
+ """
+ Lorem ipsum dolor sit amet.
- Consectetur adipiscing elit:
@ -310,6 +322,7 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
- - quis nostrud exercitation ullamco laboris nisi
- - aliquip ex ea commodo consequat
- """
- pass
+ Consectetur adipiscing elit:
+ - sed do eiusmod tempor incididunt ut labore
+ - dolore magna aliqua
@ -317,30 +330,34 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
+ - quis nostrud exercitation ullamco laboris nisi
+ - aliquip ex ea commodo consequat
+ """
pass
+ pass
def under_indent():
"""
- """
- These lines are indented in a way that does not
- make sense.
- """
- pass
+ """
+ These lines are indented in a way that does not
+make sense.
+ """
pass
+ pass
def over_indent():
"""
- This has a shallow indent
- - But some lines are deeper
- - And the closing quote is too deep
+ """
+ This has a shallow indent
+ - But some lines are deeper
+ - And the closing quote is too deep
"""
pass
- This has a shallow indent
- - But some lines are deeper
- - And the closing quote is too deep
- """
- pass
+ pass
def single_line():
@ -351,56 +368,70 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
pass
@@ -93,20 +95,25 @@
@@ -88,25 +89,30 @@
def that():
- """ "hey yah" """
+ """ "hey yah" """
def and_that():
"""
- """
- "hey yah" """
+ """
+ "hey yah" """
def and_this():
- '''
- "hey yah"'''
+ '''
+ '''
+ "hey yah"'''
def multiline_whitespace():
- """ """
+ """
+ '''
+
+
+
+
+ """
+ '''
def oneline_whitespace():
- """ """
+ """ """
+ ''' '''
def empty():
@@ -118,8 +125,8 @@
@@ -114,46 +120,43 @@
def believe_it_or_not_this_is_in_the_py_stdlib():
def single_quotes():
- "testing"
+ 'testing'
-def believe_it_or_not_this_is_in_the_py_stdlib():
- '''
- "hey yah"'''
+ '''
+def believe_it_or_not_this_is_in_the_py_stdlib(): '''
+"hey yah"'''
def ignored_docstring():
@@ -128,31 +135,31 @@
"""a => \
-b"""
-
+b"""
def single_line_docstring_with_whitespace():
- """This should be stripped"""
-
+ """ This should be stripped """
def docstring_with_inline_tabs_and_space_indentation():
"""hey
@ -419,7 +450,8 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
def docstring_with_inline_tabs_and_tab_indentation():
"""hey
- """hey
+ """hey
- tab separated value
- tab at start of line and then a tab separated value
@ -428,6 +460,7 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
-
- line ends with some tabs
- """
- pass
+ tab separated value
+ tab at start of line and then a tab separated value
+ multiple tabs at the beginning and inline
@ -435,28 +468,43 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
+
+ line ends with some tabs
+ """
pass
+ pass
@@ -168,7 +175,7 @@
def backslash_space():
@@ -161,16 +164,15 @@
def multiline_backslash_1():
- """
+ '''
hey\there\
- \ """
+ \ '''
def multiline_backslash_2():
"""
- """
- hey there \ """
+ hey there \ """
+ '''
+ hey there \ '''
-
# Regression test for #3425
@@ -179,7 +186,7 @@
def multiline_backslash_really_long_dont_crash():
"""
@@ -178,8 +180,8 @@
def multiline_backslash_3():
"""
- """
- already escaped \\"""
+ already escaped \\ """
+ '''
+ already escaped \\ '''
def my_god_its_full_of_stars_1():
@@ -188,7 +195,7 @@
@@ -188,7 +190,7 @@
# the space below is actually a \u2001, removed in output
def my_god_its_full_of_stars_2():
@ -465,60 +513,69 @@ def stable_quote_normalization_with_immediate_inner_single_quote(self):
def docstring_almost_at_line_limit():
@@ -213,7 +215,7 @@
def stable_quote_normalization_with_immediate_inner_single_quote(self):
- """'<text here>
+ ''''<text here>
<text here, since without another non-empty line black is stable>
- """
+ '''
```
## Ruff Output
```py
class MyClass:
""" Multiline
""" Multiline
class docstring
"""
def method(self):
"""Multiline
def method(self):
"""Multiline
method docstring
"""
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def bar():
"""This is another docstring
with more lines of text
"""
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def troz():
"""Indentation with tabs
is just as OK
"""
return
def zort():
"""Another
multiline
docstring
"""
pass
def foo():
"""This is a docstring with
some lines of text here
"""
return
def bar():
'''This is another docstring
with more lines of text
'''
return
def baz():
'''"This" is a string with some
embedded "quotes"'''
return
def troz():
'''Indentation with tabs
is just as OK
'''
return
def zort():
"""Another
multiline
docstring
"""
pass
def poit():
"""
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
@ -528,24 +585,24 @@ def poit():
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass
pass
def under_indent():
"""
"""
These lines are indented in a way that does not
make sense.
"""
pass
pass
def over_indent():
"""
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass
pass
def single_line():
@ -562,30 +619,30 @@ def this():
def that():
""" "hey yah" """
""" "hey yah" """
def and_that():
"""
"""
"hey yah" """
def and_this():
'''
'''
"hey yah"'''
def multiline_whitespace():
"""
'''
"""
'''
def oneline_whitespace():
""" """
''' '''
def empty():
@ -593,23 +650,20 @@ def empty():
def single_quotes():
"testing"
'testing'
def believe_it_or_not_this_is_in_the_py_stdlib():
'''
def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''
def ignored_docstring():
"""a => \
b"""
b"""
def single_line_docstring_with_whitespace():
""" This should be stripped """
def docstring_with_inline_tabs_and_space_indentation():
"""hey
@ -623,7 +677,7 @@ def docstring_with_inline_tabs_and_space_indentation():
def docstring_with_inline_tabs_and_tab_indentation():
"""hey
"""hey
tab separated value
tab at start of line and then a tab separated value
@ -632,7 +686,7 @@ def docstring_with_inline_tabs_and_tab_indentation():
line ends with some tabs
"""
pass
pass
def backslash_space():
@ -640,15 +694,14 @@ def backslash_space():
def multiline_backslash_1():
"""
'''
hey\there\
\ """
\ '''
def multiline_backslash_2():
"""
hey there \ """
'''
hey there \ '''
# Regression test for #3425
def multiline_backslash_really_long_dont_crash():
@ -657,8 +710,8 @@ def multiline_backslash_really_long_dont_crash():
def multiline_backslash_3():
"""
already escaped \\ """
'''
already escaped \\ '''
def my_god_its_full_of_stars_1():
@ -692,10 +745,10 @@ def multiline_docstring_at_line_limit():
def stable_quote_normalization_with_immediate_inner_single_quote(self):
"""'<text here>
''''<text here>
<text here, since without another non-empty line black is stable>
"""
'''
```
## Black Output

View file

@ -105,61 +105,60 @@ def g():
```diff
--- Black
+++ Ruff
@@ -25,23 +25,30 @@
@@ -3,9 +3,9 @@
# leading comment
def f():
- NO = ""
- SPACE = " "
- DOUBLESPACE = " "
+ NO = ''
+ SPACE = ' '
+ DOUBLESPACE = ' '
t = leaf.type
p = leaf.parent # trailing comment
@@ -16,14 +16,19 @@
if t == token.COMMENT: # another trailing comment
return DOUBLESPACE
+
assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
+
prev = leaf.prev_sibling
if not prev:
prevp = preceding_leaf(p)
if not prevp or prevp.type in OPENING_BRACKETS:
+
+
return NO
+
if prevp.type == token.EQUAL:
- if prevp.parent and prevp.parent.type in {
- syms.typedargslist,
- syms.varargslist,
- syms.parameters,
- syms.arglist,
- syms.argument,
- }:
+ if (
+ prevp.parent
+ and prevp.parent.type
+ in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.argument,
+ }
+ ):
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
@@ -44,16 +49,14 @@
}:
return NO
-
elif prevp.type == token.DOUBLESTAR:
- if prevp.parent and prevp.parent.type in {
- syms.typedargslist,
- syms.varargslist,
- syms.parameters,
- syms.arglist,
- syms.dictsetmaker,
- }:
+ if (
+ prevp.parent
+ and prevp.parent.type
+ in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.dictsetmaker,
+ }
+ ):
return NO
@@ -49,7 +56,6 @@
###############################################################################
# SECTION BECAUSE SECTIONS
###############################################################################
-
def g():
NO = ""
SPACE = " "
@@ -67,7 +73,7 @@
- NO = ""
- SPACE = " "
- DOUBLESPACE = " "
+ NO = ''
+ SPACE = ' '
+ DOUBLESPACE = ' '
t = leaf.type
p = leaf.parent
@@ -67,7 +70,7 @@
return DOUBLESPACE
# Another comment because more comments
@ -168,29 +167,6 @@ def g():
prev = leaf.prev_sibling
if not prev:
@@ -79,11 +85,15 @@
return NO
if prevp.type == token.EQUAL:
- if prevp.parent and prevp.parent.type in {
- syms.typedargslist,
- syms.varargslist,
- syms.parameters,
- syms.arglist,
- syms.argument,
- }:
+ if (
+ prevp.parent
+ and prevp.parent.type
+ in {
+ syms.typedargslist,
+ syms.varargslist,
+ syms.parameters,
+ syms.arglist,
+ syms.argument,
+ }
+ ):
return NO
```
## Ruff Output
@ -201,9 +177,9 @@ def g():
# leading comment
def f():
NO = ""
SPACE = " "
DOUBLESPACE = " "
NO = ''
SPACE = ' '
DOUBLESPACE = ' '
t = leaf.type
p = leaf.parent # trailing comment
@ -214,50 +190,47 @@ def f():
if t == token.COMMENT: # another trailing comment
return DOUBLESPACE
assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}"
prev = leaf.prev_sibling
if not prev:
prevp = preceding_leaf(p)
if not prevp or prevp.type in OPENING_BRACKETS:
return NO
if prevp.type == token.EQUAL:
if (
prevp.parent
and prevp.parent.type
in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}
):
return NO
elif prevp.type == token.DOUBLESTAR:
if (
prevp.parent
and prevp.parent.type
in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.dictsetmaker,
}
):
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}:
return NO
elif prevp.type == token.DOUBLESTAR:
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.dictsetmaker,
}:
return NO
###############################################################################
# SECTION BECAUSE SECTIONS
###############################################################################
def g():
NO = ""
SPACE = " "
DOUBLESPACE = " "
NO = ''
SPACE = ' '
DOUBLESPACE = ' '
t = leaf.type
p = leaf.parent
@ -283,17 +256,13 @@ def g():
return NO
if prevp.type == token.EQUAL:
if (
prevp.parent
and prevp.parent.type
in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}
):
if prevp.parent and prevp.parent.type in {
syms.typedargslist,
syms.varargslist,
syms.parameters,
syms.arglist,
syms.argument,
}:
return NO
```

View file

@ -267,55 +267,215 @@ last_call()
```diff
--- Black
+++ Ruff
@@ -1,3 +1,4 @@
@@ -1,5 +1,6 @@
-"some_string"
-b"\\xa3"
+...
"some_string"
b"\\xa3"
+'some_string'
+b'\\xa3'
Name
@@ -38,7 +39,8 @@
lambda a, b, c=True, *, d=(1 << v2), e="str": a
lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
None
True
@@ -22,119 +23,83 @@
v1 << 2
1 >> v2
1 % finished
-1 + v2 - v3 * 4 ^ 5**v6 / 7 // 8
-((1 + v2) - (v3 * 4)) ^ (((5**v6) / 7) // 8)
+1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8
+((1 + v2) - (v3 * 4)) ^ (((5 ** v6) / 7) // 8)
not great
~great
+value
-1
~int and not v1 ^ 123 + v2 | True
(~int) and (not ((v1 ^ (123 + v2)) | True))
-+(really ** -(confusing ** ~(operator**-precedence)))
-flags & ~select.EPOLLIN and waiters.write_task is not None
++really ** -confusing ** ~operator ** -precedence
+flags & ~ select.EPOLLIN and waiters.write_task is not None
lambda arg: None
lambda a=True: a
lambda a, b, c=True: a
-lambda a, b, c=True, *, d=(1 << v2), e="str": a
-lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
+lambda a, b, c=True, *, d=(1 << v2), e='str': a
+lambda a, b, c=True, *vararg, d=(v1 << 2), e='str', **kwargs: a + b
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
-foo = lambda port_id, ignore_missing: {
+foo = lambda port_id,
+ignore_missing,: {
"port1": port1_resource,
"port2": port2_resource,
}[port_id]
@@ -100,7 +102,8 @@
- "port1": port1_resource,
- "port2": port2_resource,
-}[port_id]
+foo = (lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[port_id])
1 if True else 2
str or None if True else str or bytes or None
(str or None) if True else (str or bytes or None)
str or None if (1 if True else 2) else str or bytes or None
(str or None) if (1 if True else 2) else (str or bytes or None)
-(
- (super_long_variable_name or None)
- if (1 if super_long_test_name else 2)
- 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), **{"3.6": verygood}}
+((super_long_variable_name or None) if (1 if super_long_test_name else 2) 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), **{'3.6': verygood}}
{**a, **b, **c}
-{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
-({"a": "b"}, (True or False), (+value), "string", b"bytes") or None
+{'2.7', '3.6', '3.7', '3.8', '3.9', ('4.0' if gilectomy else '3.10')}
+({'a': 'b'}, (True or False), (+value), 'string', b'bytes') or None
()
(1,)
(1, 2)
(1, 2, 3)
[]
[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)]
-[
- 1,
- 2,
- 3,
-]
+[1, 2, 3,]
[*a]
[*range(10)]
-[
- *a,
- 4,
- 5,
-]
-[
- 4,
- *a,
- 5,
-]
-[
- this_is_a_very_long_variable_which_will_force_a_delimiter_split,
- element,
- another,
- *more,
-]
+[*a, 4, 5,]
+[4, *a, 5,]
+[this_is_a_very_long_variable_which_will_force_a_delimiter_split, element, another, *more]
{i for i in (1, 2, 3)}
-{(i**2) for i in (1, 2, 3)}
-{(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))}
-{((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
+{(i ** 2) for i in (1, 2, 3)}
+{(i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}
+{((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
[i for i in (1, 2, 3)]
-[(i**2) for i in (1, 2, 3)]
-[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))]
-[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
+[(i ** 2) for i in (1, 2, 3)]
+[(i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]
+[((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
{i: 0 for i in (1, 2, 3)}
-{i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
+{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}
{a: b * 2 for a, b in dictionary.items()}
{a: b * -2 for a, b in dictionary.items()}
{
k: v
-{
- k: v
- for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
+ for k,
+ v, in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
}
-}
+{k: v for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension}
Python3 > Python2 > COBOL
Life is Life
@@ -138,15 +141,15 @@
call()
call(arg)
-call(kwarg="hey")
-call(arg, kwarg="hey")
-call(arg, another, kwarg="hey", **kwargs)
-call(
- this_is_a_very_long_variable_which_will_force_a_delimiter_split,
- arg,
- another,
- kwarg="hey",
- **kwargs,
-) # note: no trailing comma pre-3.6
+call(kwarg='hey')
+call(arg, kwarg='hey')
+call(arg, another, kwarg='hey', **kwargs)
+call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs) # note: no trailing comma pre-3.6
call(*gidgets[:2])
call(a, *gidgets[:2])
call(**self.screen_kwargs)
call(b, **self.screen_kwargs)
lukasz.langa.pl
call.me(maybe)
-(1).real
-(1.0).real
+1 .real
+1.0 .real
....__class__
list[str]
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]
]
+tuple[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_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore
)
-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
+)
+xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
+ classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__))
@@ -144,9 +109,9 @@
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
+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]
@@ -201,30 +204,26 @@
@@ -174,57 +139,29 @@
numpy[:, ::-1]
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}
-{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
+{'2.7': dead, '3.7': long_live or die_hard}
+{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
(SomeName)
SomeName
(Good, Bad, Ugly)
(i for i in (1, 2, 3))
-((i**2) for i in (1, 2, 3))
-((i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c")))
-(((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
+((i ** 2) for i in (1, 2, 3))
+((i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))
+(((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
(*starred,)
-{
- "id": "1",
- "type": "type",
- "started_at": now(),
- "ended_at": now() + timedelta(days=10),
- "priority": 1,
- "import_session_id": 1,
- **kwargs,
-}
+{"id": "1","type": "type","started_at": now(),"ended_at": now() + timedelta(days=10),"priority": 1,"import_session_id": 1,**kwargs}
a = (1,)
-b = (1,)
+b = 1,
c = 1
d = (1,) + a + (2,)
e = (1,).count(1)
f = 1, *range(10)
g = 1, *"ten"
@ -332,11 +492,7 @@ last_call()
- )
- .order_by(models.Customer.id.asc())
- .all()
+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(
@ -346,77 +502,195 @@ last_call()
- models.Customer.id.asc(),
- )
- .all()
+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(
+ models.Customer.account_id == account_id,
+ models.Customer.email == email_address,
+).order_by(models.Customer.id.asc()).all()
+result = session.query(models.Customer.id).filter(
+ models.Customer.account_id == account_id,
+ models.Customer.email == email_address,
+).order_by(
+ models.Customer.id.asc(),
+).all()
-)
+what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(vars_to_remove)
+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(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc()).all()
+result = session.query(models.Customer.id).filter(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc(),).all()
Ø = set()
authors.łukasz.say_thanks()
mapping = {
@@ -250,9 +249,9 @@
@@ -233,138 +170,84 @@
C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12),
}
-
def gen():
yield from outside_of_generator
- a = yield
- b = yield
- c = yield
-
+ a = (yield)
+ b = ((yield))
+ c = (((yield)))
async def f():
await some.complicated[0].call(with_args=(True or (1 is not 1)))
-
-
-print(*[] or [1])
+print(* [] or [1])
print(**{1: 3} if False else {x: x for x in range(3)})
print(*lambda x: x)
assert not Test, "Short message"
-print(*lambda x: x)
-assert not Test, "Short message"
-assert this is ComplexTest and not requirements.fit_in_a_single_line(
- force=False
-), "Short message"
+assert this is ComplexTest and not requirements.fit_in_a_single_line(force=False), (
+ "Short message"
+)
assert parens is TooMany
for (x,) in (1,), (2,), (3,):
...
@@ -327,13 +326,18 @@
-assert parens is TooMany
-for (x,) in (1,), (2,), (3,):
- ...
-for y in ():
- ...
-for z in (i for i in (1, 2, 3)):
- ...
-for i in call():
- ...
-for j in 1 + (2 + 3):
- ...
-while this and that:
- ...
-for (
- addr_family,
- addr_type,
- addr_proto,
- addr_canonname,
- addr_sockaddr,
-) in socket.getaddrinfo("google.com", "http"):
+print(* lambda x: x)
+assert(not Test),("Short message")
+assert this is ComplexTest and not requirements.fit_in_a_single_line(force=False), "Short message"
+assert(((parens is TooMany)))
+for x, in (1,), (2,), (3,): ...
+for y in (): ...
+for z in (i for i in (1, 2, 3)): ...
+for i in (call()): ...
+for j in (1 + (2 + 3)): ...
+while(this and that): ...
+for addr_family, addr_type, addr_proto, addr_canonname, addr_sockaddr in socket.getaddrinfo('google.com', 'http'):
pass
-a = (
- aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
- in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
-)
-a = (
- aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
- not in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
-)
-a = (
- aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
- is qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
-)
-a = (
- aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
- is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
-)
+a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
+a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp not in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
+a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp is qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
+a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
if (
- threading.current_thread() != threading.main_thread()
- and threading.current_thread() != threading.main_thread()
- or signal.getsignal(signal.SIGINT) != signal.default_int_handler
+ threading.current_thread() != threading.main_thread() and
+ threading.current_thread() != threading.main_thread() or
+ signal.getsignal(signal.SIGINT) != signal.default_int_handler
):
return True
if (
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- * aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- / aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
- ~aaaa.a + aaaa.b - aaaa.c * aaaa.d / aaaa.e
+ ~aaaa.a
+ + aaaa.b
+ - aaaa.c * aaaa.d / aaaa.e
| aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l**aaaa.m // aaaa.n
- | aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l**aaaa.m // aaaa.n
+ ~ aaaa.a + aaaa.b - aaaa.c * aaaa.d / aaaa.e | aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l ** aaaa.m // aaaa.n
):
return True
if (
- ~aaaaaaaa.a + aaaaaaaa.b - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e
- | aaaaaaaa.f & aaaaaaaa.g % aaaaaaaa.h
+ ~aaaaaaaa.a
+ + aaaaaaaa.b
+ - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e
+ | aaaaaaaa.f
+ & aaaaaaaa.g % aaaaaaaa.h
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
- ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
+ ~ aaaaaaaa.a + aaaaaaaa.b - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e | aaaaaaaa.f & aaaaaaaa.g % aaaaaaaa.h ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l ** aaaaaaaa.m // aaaaaaaa.n
):
return True
@@ -341,7 +345,8 @@
~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
if (
- ~aaaaaaaaaaaaaaaa.a
- + aaaaaaaaaaaaaaaa.b
- - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
- | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h
+ | aaaaaaaaaaaaaaaa.f
+ & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h
^ aaaaaaaaaaaaaaaa.i
<< aaaaaaaaaaaaaaaa.k
>> aaaaaaaaaaaaaaaa.l**aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
- ^ aaaaaaaaaaaaaaaa.i
- << aaaaaaaaaaaaaaaa.k
- >> aaaaaaaaaaaaaaaa.l**aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
+ ~ aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h ^ aaaaaaaaaaaaaaaa.i << aaaaaaaaaaaaaaaa.k >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
):
return True
-(
- aaaaaaaaaaaaaaaa
- + aaaaaaaaaaaaaaaa
- - aaaaaaaaaaaaaaaa
- * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
- / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
-)
+aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa - aaaaaaaaaaaaaaaa * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa
-(
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-)
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbb >> bbbb * bbbb
-(
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- ^ bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- ^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
-)
+aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ^bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
last_call()
-# standalone comment at ENDMARKER
```
## Ruff Output
```py
...
"some_string"
b"\\xa3"
'some_string'
b'\\xa3'
Name
None
True
@ -439,133 +713,95 @@ Name1 or Name2 and Name3 or Name4
v1 << 2
1 >> v2
1 % finished
1 + v2 - v3 * 4 ^ 5**v6 / 7 // 8
((1 + v2) - (v3 * 4)) ^ (((5**v6) / 7) // 8)
1 + v2 - v3 * 4 ^ 5 ** v6 / 7 // 8
((1 + v2) - (v3 * 4)) ^ (((5 ** v6) / 7) // 8)
not great
~great
+value
-1
~int and not v1 ^ 123 + v2 | True
(~int) and (not ((v1 ^ (123 + v2)) | True))
+(really ** -(confusing ** ~(operator**-precedence)))
flags & ~select.EPOLLIN and waiters.write_task is not None
+really ** -confusing ** ~operator ** -precedence
flags & ~ select.EPOLLIN and waiters.write_task is not None
lambda arg: None
lambda a=True: a
lambda a, b, c=True: a
lambda a, b, c=True, *, d=(1 << v2), e="str": a
lambda a, b, c=True, *vararg, d=(v1 << 2), e="str", **kwargs: a + b
lambda a, b, c=True, *, d=(1 << v2), e='str': a
lambda a, b, c=True, *vararg, d=(v1 << 2), e='str', **kwargs: a + b
manylambdas = lambda x=lambda y=lambda z=1: z: y(): x()
foo = lambda port_id,
ignore_missing,: {
"port1": port1_resource,
"port2": port2_resource,
}[port_id]
foo = (lambda port_id, ignore_missing: {"port1": port1_resource, "port2": port2_resource}[port_id])
1 if True else 2
str or None if True else str or bytes or None
(str or None) if True else (str or bytes or None)
str or None if (1 if True else 2) else str or bytes or None
(str or None) if (1 if True else 2) else (str or bytes or None)
(
(super_long_variable_name or None)
if (1 if super_long_test_name else 2)
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), **{"3.6": verygood}}
((super_long_variable_name or None) if (1 if super_long_test_name else 2) 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), **{'3.6': verygood}}
{**a, **b, **c}
{"2.7", "3.6", "3.7", "3.8", "3.9", ("4.0" if gilectomy else "3.10")}
({"a": "b"}, (True or False), (+value), "string", b"bytes") or None
{'2.7', '3.6', '3.7', '3.8', '3.9', ('4.0' if gilectomy else '3.10')}
({'a': 'b'}, (True or False), (+value), 'string', b'bytes') or None
()
(1,)
(1, 2)
(1, 2, 3)
[]
[1, 2, 3, 4, 5, 6, 7, 8, 9, (10 or A), (11 or B), (12 or C)]
[
1,
2,
3,
]
[1, 2, 3,]
[*a]
[*range(10)]
[
*a,
4,
5,
]
[
4,
*a,
5,
]
[
this_is_a_very_long_variable_which_will_force_a_delimiter_split,
element,
another,
*more,
]
[*a, 4, 5,]
[4, *a, 5,]
[this_is_a_very_long_variable_which_will_force_a_delimiter_split, element, another, *more]
{i for i in (1, 2, 3)}
{(i**2) for i in (1, 2, 3)}
{(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))}
{((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
{(i ** 2) for i in (1, 2, 3)}
{(i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))}
{((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3)}
[i for i in (1, 2, 3)]
[(i**2) for i in (1, 2, 3)]
[(i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c"))]
[((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
[(i ** 2) for i in (1, 2, 3)]
[(i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c'))]
[((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3)]
{i: 0 for i in (1, 2, 3)}
{i: j for i, j in ((1, "a"), (2, "b"), (3, "c"))}
{i: j for i, j in ((1, 'a'), (2, 'b'), (3, 'c'))}
{a: b * 2 for a, b in dictionary.items()}
{a: b * -2 for a, b in dictionary.items()}
{
k: v
for k,
v, in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension
}
{k: v for k, v in this_is_a_very_long_variable_which_will_cause_a_trailing_comma_which_breaks_the_comprehension}
Python3 > Python2 > COBOL
Life is Life
call()
call(arg)
call(kwarg="hey")
call(arg, kwarg="hey")
call(arg, another, kwarg="hey", **kwargs)
call(
this_is_a_very_long_variable_which_will_force_a_delimiter_split,
arg,
another,
kwarg="hey",
**kwargs,
) # note: no trailing comma pre-3.6
call(kwarg='hey')
call(arg, kwarg='hey')
call(arg, another, kwarg='hey', **kwargs)
call(this_is_a_very_long_variable_which_will_force_a_delimiter_split, arg, another, kwarg='hey', **kwargs) # note: no trailing comma pre-3.6
call(*gidgets[:2])
call(a, *gidgets[:2])
call(**self.screen_kwargs)
call(b, **self.screen_kwargs)
lukasz.langa.pl
call.me(maybe)
(1).real
(1.0).real
1 .real
1.0 .real
....__class__
list[str]
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]
]
tuple[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(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # 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(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore
)
xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = (
classmethod(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]
@ -593,53 +829,29 @@ numpy[:, l[-2]]
numpy[:, ::-1]
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}
{"2.7", "3.6", "3.7", "3.8", "3.9", "4.0" if gilectomy else "3.10"}
{'2.7': dead, '3.7': long_live or die_hard}
{'2.7', '3.6', '3.7', '3.8', '3.9', '4.0' if gilectomy else '3.10'}
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10 or A, 11 or B, 12 or C]
(SomeName)
SomeName
(Good, Bad, Ugly)
(i for i in (1, 2, 3))
((i**2) for i in (1, 2, 3))
((i**2) for i, _ in ((1, "a"), (2, "b"), (3, "c")))
(((i**2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
((i ** 2) for i in (1, 2, 3))
((i ** 2) for i, _ in ((1, 'a'), (2, 'b'), (3, 'c')))
(((i ** 2) + j) for i in (1, 2, 3) for j in (1, 2, 3))
(*starred,)
{
"id": "1",
"type": "type",
"started_at": now(),
"ended_at": now() + timedelta(days=10),
"priority": 1,
"import_session_id": 1,
**kwargs,
}
{"id": "1","type": "type","started_at": now(),"ended_at": now() + timedelta(days=10),"priority": 1,"import_session_id": 1,**kwargs}
a = (1,)
b = (1,)
b = 1,
c = 1
d = (1,) + a + (2,)
e = (1,).count(1)
f = 1, *range(10)
g = 1, *"ten"
what_is_up_with_those_new_coord_names = (
(coord_names
+ set(vars_to_create))
+ set(vars_to_remove)
)
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(
models.Customer.account_id == account_id,
models.Customer.email == email_address,
).order_by(models.Customer.id.asc()).all()
result = session.query(models.Customer.id).filter(
models.Customer.account_id == account_id,
models.Customer.email == email_address,
).order_by(
models.Customer.id.asc(),
).all()
what_is_up_with_those_new_coord_names = (coord_names + set(vars_to_create)) + set(vars_to_remove)
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(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc()).all()
result = session.query(models.Customer.id).filter(models.Customer.account_id == account_id, models.Customer.email == email_address).order_by(models.Customer.id.asc(),).all()
Ø = set()
authors.łukasz.say_thanks()
mapping = {
@ -649,146 +861,86 @@ mapping = {
D: 0.1 * (10.0 / 12),
}
def gen():
yield from outside_of_generator
a = yield
b = yield
c = yield
a = (yield)
b = ((yield))
c = (((yield)))
async def f():
await some.complicated[0].call(with_args=(True or (1 is not 1)))
print(*[] or [1])
print(* [] or [1])
print(**{1: 3} if False else {x: x for x in range(3)})
print(*lambda x: x)
assert not Test, "Short message"
assert this is ComplexTest and not requirements.fit_in_a_single_line(force=False), (
"Short message"
)
assert parens is TooMany
for (x,) in (1,), (2,), (3,):
...
for y in ():
...
for z in (i for i in (1, 2, 3)):
...
for i in call():
...
for j in 1 + (2 + 3):
...
while this and that:
...
for (
addr_family,
addr_type,
addr_proto,
addr_canonname,
addr_sockaddr,
) in socket.getaddrinfo("google.com", "http"):
print(* lambda x: x)
assert(not Test),("Short message")
assert this is ComplexTest and not requirements.fit_in_a_single_line(force=False), "Short message"
assert(((parens is TooMany)))
for x, in (1,), (2,), (3,): ...
for y in (): ...
for z in (i for i in (1, 2, 3)): ...
for i in (call()): ...
for j in (1 + (2 + 3)): ...
while(this and that): ...
for addr_family, addr_type, addr_proto, addr_canonname, addr_sockaddr in socket.getaddrinfo('google.com', 'http'):
pass
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
not in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
is qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = (
aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp
is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
)
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp not in qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp is qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
a = aaaa.bbbb.cccc.dddd.eeee.ffff.gggg.hhhh.iiii.jjjj.kkkk.llll.mmmm.nnnn.oooo.pppp is not qqqq.rrrr.ssss.tttt.uuuu.vvvv.xxxx.yyyy.zzzz
if (
threading.current_thread() != threading.main_thread()
and threading.current_thread() != threading.main_thread()
or signal.getsignal(signal.SIGINT) != signal.default_int_handler
threading.current_thread() != threading.main_thread() and
threading.current_thread() != threading.main_thread() or
signal.getsignal(signal.SIGINT) != signal.default_int_handler
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
| aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
& aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa -
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
- aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa *
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
* aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa /
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
/ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
):
return True
if (
~aaaa.a
+ aaaa.b
- aaaa.c * aaaa.d / aaaa.e
| aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l**aaaa.m // aaaa.n
~ aaaa.a + aaaa.b - aaaa.c * aaaa.d / aaaa.e | aaaa.f & aaaa.g % aaaa.h ^ aaaa.i << aaaa.k >> aaaa.l ** aaaa.m // aaaa.n
):
return True
if (
~aaaaaaaa.a
+ aaaaaaaa.b
- aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e
| aaaaaaaa.f
& aaaaaaaa.g % aaaaaaaa.h
^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l**aaaaaaaa.m // aaaaaaaa.n
~ aaaaaaaa.a + aaaaaaaa.b - aaaaaaaa.c @ aaaaaaaa.d / aaaaaaaa.e | aaaaaaaa.f & aaaaaaaa.g % aaaaaaaa.h ^ aaaaaaaa.i << aaaaaaaa.k >> aaaaaaaa.l ** aaaaaaaa.m // aaaaaaaa.n
):
return True
if (
~aaaaaaaaaaaaaaaa.a
+ aaaaaaaaaaaaaaaa.b
- aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e
| aaaaaaaaaaaaaaaa.f
& aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h
^ aaaaaaaaaaaaaaaa.i
<< aaaaaaaaaaaaaaaa.k
>> aaaaaaaaaaaaaaaa.l**aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
~ aaaaaaaaaaaaaaaa.a + aaaaaaaaaaaaaaaa.b - aaaaaaaaaaaaaaaa.c * aaaaaaaaaaaaaaaa.d @ aaaaaaaaaaaaaaaa.e | aaaaaaaaaaaaaaaa.f & aaaaaaaaaaaaaaaa.g % aaaaaaaaaaaaaaaa.h ^ aaaaaaaaaaaaaaaa.i << aaaaaaaaaaaaaaaa.k >> aaaaaaaaaaaaaaaa.l ** aaaaaaaaaaaaaaaa.m // aaaaaaaaaaaaaaaa.n
):
return True
(
aaaaaaaaaaaaaaaa
+ aaaaaaaaaaaaaaaa
- aaaaaaaaaaaaaaaa
* (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
/ (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
)
aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa - aaaaaaaaaaaaaaaa * (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa) / (aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa)
aaaaaaaaaaaaaaaa + aaaaaaaaaaaaaaaa
(
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
>> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
<< aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa >> aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa << aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbb >> bbbb * bbbb
(
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
^ bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
^ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
)
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ^bbbb.a & aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa^aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
last_call()
# standalone comment at ENDMARKER
```
## Black Output

View file

@ -1,205 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtonoff2.py
---
## Input
```py
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -3,38 +3,42 @@
TmSt = 1
TmEx = 2
+
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
-@pytest.mark.parametrize('test', [
-
- # Test don't manage the volume
+@pytest.mark.parametrize(
+ "test",
[
- ('stuff', 'in')
+ # Test don't manage the volume
+ [("stuff", "in")],
],
-])
+)
def test_fader(test):
pass
+
def check_fader(test):
+ pass
- pass
def verify_fader(test):
- # misaligned comment
+ # misaligned comment
pass
+
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
+
def test_calculate_fades():
calcs = [
- # one is zero/none
- (0, 4, 0, 0, 10, 0, 0, 6, 10),
- (None, 4, 0, 0, 10, 0, 0, 6, 10),
+ (# one is zero/none
+ 0, 4, 0, 0, 10, 0, 0, 6, 10),
+ (None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on
```
## Ruff Output
```py
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize(
"test",
[
# Test don't manage the volume
[("stuff", "in")],
],
)
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
(# one is zero/none
0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on
```
## Black Output
```py
import pytest
TmSt = 1
TmEx = 2
# fmt: off
# Test data:
# Position, Volume, State, TmSt/TmEx/None, [call, [arg1...]]
@pytest.mark.parametrize('test', [
# Test don't manage the volume
[
('stuff', 'in')
],
])
def test_fader(test):
pass
def check_fader(test):
pass
def verify_fader(test):
# misaligned comment
pass
def verify_fader(test):
"""Hey, ho."""
assert test.passed()
def test_calculate_fades():
calcs = [
# one is zero/none
(0, 4, 0, 0, 10, 0, 0, 6, 10),
(None, 4, 0, 0, 10, 0, 0, 6, 10),
]
# fmt: on
```

View file

@ -30,29 +30,14 @@ x = [
```diff
--- Black
+++ Ruff
@@ -1,14 +1,18 @@
# fmt: off
x = [
- 1, 2,
- 3, 4,
+ 1,
+ 2,
+ 3,
+ 4,
]
# fmt: on
# fmt: off
x = [
- 1, 2,
- 3, 4,
+ 1,
+ 2,
+ 3,
+ 4,
@@ -12,4 +12,6 @@
]
# fmt: on
-x = [1, 2, 3, 4]
+x = [
+ 1, 2, 3, 4
+]
```
## Ruff Output
@ -60,23 +45,21 @@ x = [
```py
# fmt: off
x = [
1,
2,
3,
4,
1, 2,
3, 4,
]
# fmt: on
# fmt: off
x = [
1,
2,
3,
4,
1, 2,
3, 4,
]
# fmt: on
x = [1, 2, 3, 4]
x = [
1, 2, 3, 4
]
```
## Black Output

View file

@ -26,52 +26,48 @@ def f(): pass
```diff
--- Black
+++ Ruff
@@ -1,8 +1,12 @@
# fmt: off
-@test([
- 1, 2,
- 3, 4,
-])
+@test(
+ [
+ 1,
+ 2,
+ 3,
+ 4,
+ ]
+)
@@ -4,17 +4,10 @@
3, 4,
])
# fmt: on
def f():
pass
-def f():
- pass
-
+def f(): pass
-@test(
- [
- 1,
- 2,
- 3,
- 4,
- ]
-)
-def f():
- pass
+@test([
+ 1, 2,
+ 3, 4,
+])
+def f(): pass
```
## Ruff Output
```py
# fmt: off
@test(
[
1,
2,
3,
4,
]
)
@test([
1, 2,
3, 4,
])
# fmt: on
def f():
pass
def f(): pass
@test(
[
1,
2,
3,
4,
]
)
def f():
pass
@test([
1, 2,
3, 4,
])
def f(): pass
```
## Black Output

View file

@ -97,87 +97,45 @@ elif unformatted:
```diff
--- Black
+++ Ruff
@@ -3,10 +3,8 @@
entry_points={
# fmt: off
"console_scripts": [
- "foo-bar"
- "=foo.bar.:main",
- # fmt: on
- ] # Includes an formatted indentation.
+ "foo-bar" "=foo.bar.:main",
+ ], # Includes an formatted indentation.
},
)
@@ -27,9 +25,8 @@
# Regression test for https://github.com/psf/black/issues/3026.
def test_func():
# yapf: disable
- if unformatted( args ):
+ if unformatted(args):
return True
- # yapf: enable
elif b:
return True
@@ -39,10 +36,10 @@
# Regression test for https://github.com/psf/black/issues/2567.
if True:
# fmt: off
- for _ in range( 1 ):
- # fmt: on
- print ( "This won't be formatted" )
- print ( "This won't be formatted either" )
+ for _ in range(1):
+ # fmt: on
+ print("This won't be formatted")
+ print("This won't be formatted either")
@@ -44,7 +44,7 @@
print ( "This won't be formatted" )
print ( "This won't be formatted either" )
else:
print("This will be formatted")
- print("This will be formatted")
+ print ( "This will be formatted" )
@@ -52,14 +49,11 @@
async def call(param):
if param:
# fmt: off
- if param[0:4] in (
- "ABCD", "EFGH"
- ) :
+ if param[0:4] in ("ABCD", "EFGH"):
# fmt: on
- print ( "This won't be formatted" )
-
+ print("This won't be formatted")
# Regression test for https://github.com/psf/black/issues/3184.
@@ -61,7 +61,7 @@
elif param[0:4] in ("ZZZZ",):
- print ( "This won't be formatted either" )
+ print("This won't be formatted either")
print ( "This won't be formatted either" )
print("This will be formatted")
- print("This will be formatted")
+ print ( "This will be formatted" )
@@ -68,20 +62,19 @@
class Named(t.Protocol):
# fmt: off
# Regression test for https://github.com/psf/black/issues/2985.
@@ -70,11 +70,8 @@
@property
- def this_wont_be_formatted ( self ) -> str: ...
+ def this_wont_be_formatted(self) -> str:
+ ...
def this_wont_be_formatted ( self ) -> str: ...
class Factory(t.Protocol):
def this_will_be_formatted(self, **kwargs) -> Named:
...
-
class Factory(t.Protocol):
- def this_will_be_formatted(self, **kwargs) -> Named:
- ...
-
+ def this_will_be_formatted ( self, **kwargs ) -> Named: ...
# fmt: on
# Regression test for https://github.com/psf/black/issues/3436.
if x:
@@ -83,5 +80,5 @@
return x
-# fmt: off
-elif unformatted:
+elif unformatted:
# fmt: on
will_be_formatted()
# fmt: off
elif unformatted:
- # fmt: on
- will_be_formatted()
+# fmt: on
+ will_be_formatted ()
```
## Ruff Output
@ -188,8 +146,10 @@ setup(
entry_points={
# fmt: off
"console_scripts": [
"foo-bar" "=foo.bar.:main",
], # Includes an formatted indentation.
"foo-bar"
"=foo.bar.:main",
# fmt: on
] # Includes an formatted indentation.
},
)
@ -210,8 +170,9 @@ run(
# Regression test for https://github.com/psf/black/issues/3026.
def test_func():
# yapf: disable
if unformatted(args):
if unformatted( args ):
return True
# yapf: enable
elif b:
return True
@ -221,12 +182,12 @@ def test_func():
# Regression test for https://github.com/psf/black/issues/2567.
if True:
# fmt: off
for _ in range(1):
# fmt: on
print("This won't be formatted")
print("This won't be formatted either")
for _ in range( 1 ):
# fmt: on
print ( "This won't be formatted" )
print ( "This won't be formatted either" )
else:
print("This will be formatted")
print ( "This will be formatted" )
# Regression test for https://github.com/psf/black/issues/3184.
@ -234,35 +195,36 @@ class A:
async def call(param):
if param:
# fmt: off
if param[0:4] in ("ABCD", "EFGH"):
if param[0:4] in (
"ABCD", "EFGH"
) :
# fmt: on
print("This won't be formatted")
elif param[0:4] in ("ZZZZ",):
print("This won't be formatted either")
print ( "This won't be formatted" )
print("This will be formatted")
elif param[0:4] in ("ZZZZ",):
print ( "This won't be formatted either" )
print ( "This will be formatted" )
# Regression test for https://github.com/psf/black/issues/2985.
class Named(t.Protocol):
# fmt: off
@property
def this_wont_be_formatted(self) -> str:
...
def this_wont_be_formatted ( self ) -> str: ...
class Factory(t.Protocol):
def this_will_be_formatted(self, **kwargs) -> Named:
...
def this_will_be_formatted ( self, **kwargs ) -> Named: ...
# fmt: on
# Regression test for https://github.com/psf/black/issues/3436.
if x:
return x
elif unformatted:
# fmt: on
will_be_formatted()
# fmt: off
elif unformatted:
# fmt: on
will_be_formatted ()
```
## Black Output

View file

@ -199,213 +199,199 @@ d={'a':1,
```diff
--- Black
+++ Ruff
@@ -5,39 +5,53 @@
@@ -4,18 +4,17 @@
from third_party import X, Y, Z
from library import some_connection, some_decorator
+# fmt: off
+from third_party import X, Y, Z
-# fmt: off
-from third_party import (X,
- Y, Z)
-from library import some_connection, some_decorator
-
+from library import some_connection, \
+ some_decorator
# fmt: off
from third_party import (X,
Y, Z)
# fmt: on
-f"trigger 3.6 mode"
+f'trigger 3.6 mode'
+
+
# Comment 1
# Comment 2
-
-
# fmt: off
def func_no_args():
- a; b; c
- if True: raise RuntimeError
- if False: ...
- for i in range(10):
- print(i)
- continue
- exec('new-style exec', {}, {})
- return None
+ a
+ b
+ c
+ if True:
+ raise RuntimeError
+ if False:
+ ...
+ for i in range(10):
+ print(i)
+ continue
+ exec("new-style exec", {}, {})
+ return None
+
+
async def coroutine(arg, exec=False):
- 'Single-line docstring. Multiline is harder to reformat.'
- async with some_connection() as conn:
- await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
- await asyncio.sleep(1)
+ "Single-line docstring. Multiline is harder to reformat."
+ async with some_connection() as conn:
+ await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
+ await asyncio.sleep(1)
+
+
@asyncio.coroutine
-@some_decorator(
-with_args=True,
-many_args=[1,2,3]
-)
-def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
- return text[number:-1]
+@some_decorator(with_args=True, many_args=[1, 2, 3])
+def function_signature_stress_test(
+ number: int,
+ no_annotation=None,
+ text: str = "default",
+ *,
+ debug: bool = False,
+ **kwargs,
+) -> str:
+ return text[number:-1]
+
+
a; b; c
@@ -39,34 +38,16 @@
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
return text[number:-1]
# fmt: on
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
@@ -64,55 +78,55 @@
-def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
- offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
- assert task._cancel_stack[: len(old_stack)] == old_stack
-
-
-def spaces_types(
- a: int = 1,
- b: tuple = (),
- c: list = [],
- d: dict = {},
- e: bool = True,
- f: int = -1,
- g: int = 1 if False else 2,
- h: str = "",
- i: str = r"",
-):
- ...
-
-
-def spaces2(result=_core.Value(None)):
- ...
-
-
+def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
+ offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2)))
+ assert task._cancel_stack[:len(old_stack)] == old_stack
+def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
+def spaces2(result= _core.Value(None)):
+ ...
something = {
# fmt: off
- key: 'value',
+ key: "value",
key: 'value',
}
-
def subscriptlist():
atom[
# fmt: off
- 'some big and',
- 'complex subscript',
+ "some big and",
+ "complex subscript",
@@ -74,17 +55,14 @@
'some big and',
'complex subscript',
# fmt: on
- goes + here,
+ goes
+ + here,
andhere,
]
- andhere,
- ]
-
+ goes + here, andhere,
+ ]
def import_as_names():
# fmt: off
- from hello import a, b
- 'unformatted'
+ from hello import a, b
+
+ "unformatted"
from hello import a, b
'unformatted'
# fmt: on
-
def testlist_star_expr():
# fmt: off
- a , b = *hello
- 'unformatted'
+ a, b = *hello
+ "unformatted"
@@ -92,18 +70,16 @@
'unformatted'
# fmt: on
-
def yield_expr():
# fmt: off
yield hello
- 'unformatted'
+ "unformatted"
'unformatted'
# fmt: on
"formatted"
- "formatted"
+ 'formatted'
# fmt: off
- ( yield hello )
- 'unformatted'
+ (yield hello)
+ "unformatted"
( yield hello )
'unformatted'
# fmt: on
-
def example(session):
# fmt: off
- result = session\
- .query(models.Customer.id)\
- .filter(models.Customer.account_id == account_id,
- models.Customer.email == email_address)\
- .order_by(models.Customer.id.asc())\
- .all()
+ result = session.query(models.Customer.id).filter(
+ models.Customer.account_id == account_id,
+ models.Customer.email == email_address,
+ ).order_by(models.Customer.id.asc()).all()
@@ -114,8 +90,6 @@
.order_by(models.Customer.id.asc())\
.all()
# fmt: on
-
-
def off_and_on_without_data():
"""All comments here are technically on the same prefix.
@@ -123,7 +137,7 @@
@@ -123,12 +97,12 @@
"""
# fmt: off
- # hey, that won't work
+ #hey, that won't work
+ #hey, that won't work
+
+
# fmt: on
pass
@@ -133,10 +147,10 @@
-
-
def on_and_off_broken():
"""Another known limitation."""
# fmt: on
# fmt: off
- this=should.not_be.formatted()
- and_=indeed . it is not formatted
- because . the . handling . inside . generate_ignored_nodes()
- now . considers . multiple . fmt . directives . within . one . prefix
+ this = should.not_be.formatted()
+ and_ = indeed.it is not formatted
+ because.the.handling.inside.generate_ignored_nodes()
+ now.considers.multiple.fmt.directives.within.one.prefix
@@ -139,19 +113,12 @@
now . considers . multiple . fmt . directives . within . one . prefix
# fmt: on
# fmt: off
# ...but comments still get reformatted even though they should not be
@@ -154,9 +168,7 @@
)
- # ...but comments still get reformatted even though they should not be
+ # ...but comments still get reformatted even though they should not be
# fmt: on
-
-
def long_lines():
if True:
typedargslist.extend(
- gen_annotated_params(
- ast_args.kwonlyargs,
- ast_args.kw_defaults,
- parameters,
- implicit_default=True,
- )
+ gen_annotated_params(ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True)
)
# fmt: off
- a = (
- unnecessary_bracket()
- )
+ a = unnecessary_bracket()
# fmt: on
_type_comment_re = re.compile(
r"""
@@ -179,7 +191,8 @@
$
""",
# fmt: off
- re.MULTILINE|re.VERBOSE
+ re.MULTILINE
+ | re.VERBOSE,
a = (
@@ -182,24 +149,19 @@
re.MULTILINE|re.VERBOSE
# fmt: on
)
@@ -217,8 +230,7 @@
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
-
-
def single_literal_yapf_disable():
"""Black does not support this."""
- BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable
-
-
+ BAZ = {
+ (1, 2, 3, 4),
+ (5, 6, 7, 8),
+ (9, 10, 11, 12)
+ } # yapf: disable
cfg.rule(
- "Default",
- "address",
+ "Default", "address",
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
- xxxxxx="xx_xxxxx",
- xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
- xxxxxxxxx_xxxx=True,
- xxxxxxxx_xxxxxxxxxx=False,
- xxxxxx_xxxxxx=2,
- xxxxxx_xxxxx_xxxxxxxx=70,
- xxxxxx_xxxxxx_xxxxx=True,
+ xxxxxx="xx_xxxxx", xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
+ xxxxxxxxx_xxxx=True, xxxxxxxx_xxxxxxxxxx=False,
+ xxxxxx_xxxxxx=2, xxxxxx_xxxxx_xxxxxxxx=70, xxxxxx_xxxxxx_xxxxx=True,
# fmt: off
xxxxxxx_xxxxxxxxxxxx={
"xxxxxxxx": {
@@ -214,7 +176,7 @@
},
},
# fmt: on
- xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
+ xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
)
# fmt: off
-yield 'hello'
+yield "hello"
# No formatting to the end of the file
-l=[1,2,3]
-d={'a':1,
- 'b':2}
+l = [1, 2, 3]
+d = {"a": 1, "b": 2}
yield 'hello'
```
## Ruff Output
@ -417,132 +403,92 @@ import sys
from third_party import X, Y, Z
from library import some_connection, some_decorator
from library import some_connection, \
some_decorator
# fmt: off
from third_party import X, Y, Z
from third_party import (X,
Y, Z)
# fmt: on
f'trigger 3.6 mode'
# Comment 1
# Comment 2
# fmt: off
def func_no_args():
a
b
c
if True:
raise RuntimeError
if False:
...
for i in range(10):
print(i)
continue
exec("new-style exec", {}, {})
return None
a; b; c
if True: raise RuntimeError
if False: ...
for i in range(10):
print(i)
continue
exec('new-style exec', {}, {})
return None
async def coroutine(arg, exec=False):
"Single-line docstring. Multiline is harder to reformat."
async with some_connection() as conn:
await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
await asyncio.sleep(1)
'Single-line docstring. Multiline is harder to reformat.'
async with some_connection() as conn:
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
await asyncio.sleep(1)
@asyncio.coroutine
@some_decorator(with_args=True, many_args=[1, 2, 3])
def function_signature_stress_test(
number: int,
no_annotation=None,
text: str = "default",
*,
debug: bool = False,
**kwargs,
) -> str:
return text[number:-1]
@some_decorator(
with_args=True,
many_args=[1,2,3]
)
def function_signature_stress_test(number:int,no_annotation=None,text:str='default',* ,debug:bool=False,**kwargs) -> str:
return text[number:-1]
# fmt: on
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(1, 2)))
assert task._cancel_stack[: len(old_stack)] == old_stack
def spaces_types(
a: int = 1,
b: tuple = (),
c: list = [],
d: dict = {},
e: bool = True,
f: int = -1,
g: int = 1 if False else 2,
h: str = "",
i: str = r"",
):
...
def spaces2(result=_core.Value(None)):
...
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
offset = attr.ib(default=attr.Factory( lambda: _r.uniform(1, 2)))
assert task._cancel_stack[:len(old_stack)] == old_stack
def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
def spaces2(result= _core.Value(None)):
...
something = {
# fmt: off
key: "value",
key: 'value',
}
def subscriptlist():
atom[
# fmt: off
"some big and",
"complex subscript",
'some big and',
'complex subscript',
# fmt: on
goes
+ here,
andhere,
]
goes + here, andhere,
]
def import_as_names():
# fmt: off
from hello import a, b
"unformatted"
from hello import a, b
'unformatted'
# fmt: on
def testlist_star_expr():
# fmt: off
a, b = *hello
"unformatted"
a , b = *hello
'unformatted'
# fmt: on
def yield_expr():
# fmt: off
yield hello
"unformatted"
'unformatted'
# fmt: on
"formatted"
'formatted'
# fmt: off
(yield hello)
"unformatted"
( yield hello )
'unformatted'
# fmt: on
def example(session):
# fmt: off
result = session.query(models.Customer.id).filter(
models.Customer.account_id == account_id,
models.Customer.email == email_address,
).order_by(models.Customer.id.asc()).all()
result = session\
.query(models.Customer.id)\
.filter(models.Customer.account_id == account_id,
models.Customer.email == email_address)\
.order_by(models.Customer.id.asc())\
.all()
# fmt: on
def off_and_on_without_data():
"""All comments here are technically on the same prefix.
@ -550,38 +496,33 @@ def off_and_on_without_data():
"""
# fmt: off
#hey, that won't work
#hey, that won't work
# fmt: on
pass
def on_and_off_broken():
"""Another known limitation."""
# fmt: on
# fmt: off
this = should.not_be.formatted()
and_ = indeed.it is not formatted
because.the.handling.inside.generate_ignored_nodes()
now.considers.multiple.fmt.directives.within.one.prefix
this=should.not_be.formatted()
and_=indeed . it is not formatted
because . the . handling . inside . generate_ignored_nodes()
now . considers . multiple . fmt . directives . within . one . prefix
# fmt: on
# fmt: off
# ...but comments still get reformatted even though they should not be
# ...but comments still get reformatted even though they should not be
# fmt: on
def long_lines():
if True:
typedargslist.extend(
gen_annotated_params(
ast_args.kwonlyargs,
ast_args.kw_defaults,
parameters,
implicit_default=True,
)
gen_annotated_params(ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True)
)
# fmt: off
a = unnecessary_bracket()
a = (
unnecessary_bracket()
)
# fmt: on
_type_comment_re = re.compile(
r"""
@ -604,28 +545,22 @@ def long_lines():
$
""",
# fmt: off
re.MULTILINE
| re.VERBOSE,
re.MULTILINE|re.VERBOSE
# fmt: on
)
def single_literal_yapf_disable():
"""Black does not support this."""
BAZ = {(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12)} # yapf: disable
BAZ = {
(1, 2, 3, 4),
(5, 6, 7, 8),
(9, 10, 11, 12)
} # yapf: disable
cfg.rule(
"Default",
"address",
"Default", "address",
xxxx_xxxx=["xxx-xxxxxx-xxxxxxxxxx"],
xxxxxx="xx_xxxxx",
xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
xxxxxxxxx_xxxx=True,
xxxxxxxx_xxxxxxxxxx=False,
xxxxxx_xxxxxx=2,
xxxxxx_xxxxx_xxxxxxxx=70,
xxxxxx_xxxxxx_xxxxx=True,
xxxxxx="xx_xxxxx", xxxxxxx="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
xxxxxxxxx_xxxx=True, xxxxxxxx_xxxxxxxxxx=False,
xxxxxx_xxxxxx=2, xxxxxx_xxxxx_xxxxxxxx=70, xxxxxx_xxxxxx_xxxxx=True,
# fmt: off
xxxxxxx_xxxxxxxxxxxx={
"xxxxxxxx": {
@ -640,13 +575,14 @@ cfg.rule(
},
},
# fmt: on
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5,
xxxxxxxxxx_xxxxxxxxxxx_xxxxxxx_xxxxxxxxx=5
)
# fmt: off
yield "hello"
yield 'hello'
# No formatting to the end of the file
l = [1, 2, 3]
d = {"a": 1, "b": 2}
l=[1,2,3]
d={'a':1,
'b':2}
```
## Black Output

View file

@ -16,39 +16,28 @@ l3 = ["I have", "trailing comma", "so I should be braked",]
```diff
--- Black
+++ Ruff
@@ -3,7 +3,11 @@
"into multiple lines",
"because it is way too long",
]
-l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip
+l2 = [
+ "But this list shouldn't",
+ "even though it also has",
+ "way too many characters in it",
+] # fmt: skip
l3 = [
"I have",
"trailing comma",
@@ -1,11 +1,3 @@
-l1 = [
- "This list should be broken up",
- "into multiple lines",
- "because it is way too long",
-]
+l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"]
l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip
-l3 = [
- "I have",
- "trailing comma",
- "so I should be braked",
-]
+l3 = ["I have", "trailing comma", "so I should be braked",]
```
## Ruff Output
```py
l1 = [
"This list should be broken up",
"into multiple lines",
"because it is way too long",
]
l2 = [
"But this list shouldn't",
"even though it also has",
"way too many characters in it",
] # fmt: skip
l3 = [
"I have",
"trailing comma",
"so I should be braked",
]
l1 = ["This list should be broken up", "into multiple lines", "because it is way too long"]
l2 = ["But this list shouldn't", "even though it also has", "way too many characters in it"] # fmt: skip
l3 = ["I have", "trailing comma", "so I should be braked",]
```
## Black Output

View file

@ -20,31 +20,31 @@ f = ["This is a very long line that should be formatted into a clearer line ", "
```diff
--- Black
+++ Ruff
@@ -1,7 +1,7 @@
a = 3
@@ -1,10 +1,7 @@
-a = 3
+a = 3
# fmt: off
-b, c = 1, 2
-d = 6 # fmt: skip
+b, c = 1, 2
+d = 6 # fmt: skip
b, c = 1, 2
d = 6 # fmt: skip
e = 5
# fmt: on
f = [
-f = [
- "This is a very long line that should be formatted into a clearer line ",
- "by rearranging.",
-]
+f = ["This is a very long line that should be formatted into a clearer line ", "by rearranging."]
```
## Ruff Output
```py
a = 3
a = 3
# fmt: off
b, c = 1, 2
d = 6 # fmt: skip
b, c = 1, 2
d = 6 # fmt: skip
e = 5
# fmt: on
f = [
"This is a very long line that should be formatted into a clearer line ",
"by rearranging.",
]
f = ["This is a very long line that should be formatted into a clearer line ", "by rearranging."]
```
## Black Output

View file

@ -0,0 +1,51 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip4.py
---
## Input
```py
a = 2
# fmt: skip
l = [1, 2, 3,]
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,7 +1,3 @@
-a = 2
+a = 2
# fmt: skip
-l = [
- 1,
- 2,
- 3,
-]
+l = [1, 2, 3,]
```
## Ruff Output
```py
a = 2
# fmt: skip
l = [1, 2, 3,]
```
## Black Output
```py
a = 2
# fmt: skip
l = [
1,
2,
3,
]
```

View file

@ -22,24 +22,26 @@ else:
```diff
--- Black
+++ Ruff
@@ -1,9 +1,5 @@
a, b, c = 3, 4, 5
-if (
@@ -1,6 +1,6 @@
-a, b, c = 3, 4, 5
+a, b, c = 3, 4, 5
if (
- a == 3
- and b != 9 # fmt: skip
- and c is not None
-):
+if a == 3 and b != 9 and c is not None: # fmt: skip
print("I'm good!")
else:
print("I'm bad")
+ a == 3
and b != 9 # fmt: skip
and c is not None
):
```
## Ruff Output
```py
a, b, c = 3, 4, 5
if a == 3 and b != 9 and c is not None: # fmt: skip
a, b, c = 3, 4, 5
if (
a == 3
and b != 9 # fmt: skip
and c is not None
):
print("I'm good!")
else:
print("I'm bad")

View file

@ -18,11 +18,12 @@ d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasu
--- Black
+++ Ruff
@@ -1,4 +1,4 @@
a = "this is some code"
-a = "this is some code"
-b = 5 # fmt:skip
-c = 9 # fmt: skip
-d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" # fmt:skip
+b = 5 #fmt:skip
+a = "this is some code"
+b = 5 #fmt:skip
+c = 9 #fmt: skip
+d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" #fmt:skip
```
@ -30,8 +31,8 @@ d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasu
## Ruff Output
```py
a = "this is some code"
b = 5 #fmt:skip
a = "this is some code"
b = 5 #fmt:skip
c = 9 #fmt: skip
d = "thisisasuperlongstringthisisasuperlongstringthisisasuperlongstringthisisasuperlongstring" #fmt:skip
```

View file

@ -1,293 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/fmtskip8.py
---
## Input
```py
# Make sure a leading comment is not removed.
def some_func( unformatted, args ): # fmt: skip
print("I am some_func")
return 0
# Make sure this comment is not removed.
# Make sure a leading comment is not removed.
async def some_async_func( unformatted, args): # fmt: skip
print("I am some_async_func")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
class SomeClass( Unformatted, SuperClasses ): # fmt: skip
def some_method( self, unformatted, args ): # fmt: skip
print("I am some_method")
return 0
async def some_async_method( self, unformatted, args ): # fmt: skip
print("I am some_async_method")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
if unformatted_call( args ): # fmt: skip
print("First branch")
# Make sure this is not removed.
elif another_unformatted_call( args ): # fmt: skip
print("Second branch")
else : # fmt: skip
print("Last branch")
while some_condition( unformatted, args ): # fmt: skip
print("Do something")
for i in some_iter( unformatted, args ): # fmt: skip
print("Do something")
async def test_async_for():
async for i in some_async_iter( unformatted, args ): # fmt: skip
print("Do something")
try : # fmt: skip
some_call()
except UnformattedError as ex: # fmt: skip
handle_exception()
finally : # fmt: skip
finally_call()
with give_me_context( unformatted, args ): # fmt: skip
print("Do something")
async def test_async_with():
async with give_me_async_context( unformatted, args ): # fmt: skip
print("Do something")
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,62 +1,62 @@
# Make sure a leading comment is not removed.
-def some_func( unformatted, args ): # fmt: skip
+def some_func(unformatted, args): # fmt: skip
print("I am some_func")
return 0
# Make sure this comment is not removed.
# Make sure a leading comment is not removed.
-async def some_async_func( unformatted, args): # fmt: skip
+async def some_async_func(unformatted, args): # fmt: skip
print("I am some_async_func")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
-class SomeClass( Unformatted, SuperClasses ): # fmt: skip
- def some_method( self, unformatted, args ): # fmt: skip
+class SomeClass(Unformatted, SuperClasses): # fmt: skip
+ def some_method(self, unformatted, args): # fmt: skip
print("I am some_method")
return 0
- async def some_async_method( self, unformatted, args ): # fmt: skip
+ async def some_async_method(self, unformatted, args): # fmt: skip
print("I am some_async_method")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
-if unformatted_call( args ): # fmt: skip
+if unformatted_call(args): # fmt: skip
print("First branch")
# Make sure this is not removed.
-elif another_unformatted_call( args ): # fmt: skip
+elif another_unformatted_call(args): # fmt: skip
print("Second branch")
-else : # fmt: skip
+else: # fmt: skip
print("Last branch")
-while some_condition( unformatted, args ): # fmt: skip
+while some_condition(unformatted, args): # fmt: skip
print("Do something")
-for i in some_iter( unformatted, args ): # fmt: skip
+for i in some_iter(unformatted, args): # fmt: skip
print("Do something")
async def test_async_for():
- async for i in some_async_iter( unformatted, args ): # fmt: skip
+ async for i in some_async_iter(unformatted, args): # fmt: skip
print("Do something")
-try : # fmt: skip
+try: # fmt: skip
some_call()
-except UnformattedError as ex: # fmt: skip
+except UnformattedError as ex:
handle_exception()
-finally : # fmt: skip
+finally: # fmt: skip
finally_call()
-with give_me_context( unformatted, args ): # fmt: skip
+with give_me_context(unformatted, args): # fmt: skip
print("Do something")
async def test_async_with():
- async with give_me_async_context( unformatted, args ): # fmt: skip
+ async with give_me_async_context(unformatted, args): # fmt: skip
print("Do something")
```
## Ruff Output
```py
# Make sure a leading comment is not removed.
def some_func(unformatted, args): # fmt: skip
print("I am some_func")
return 0
# Make sure this comment is not removed.
# Make sure a leading comment is not removed.
async def some_async_func(unformatted, args): # fmt: skip
print("I am some_async_func")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
class SomeClass(Unformatted, SuperClasses): # fmt: skip
def some_method(self, unformatted, args): # fmt: skip
print("I am some_method")
return 0
async def some_async_method(self, unformatted, args): # fmt: skip
print("I am some_async_method")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
if unformatted_call(args): # fmt: skip
print("First branch")
# Make sure this is not removed.
elif another_unformatted_call(args): # fmt: skip
print("Second branch")
else: # fmt: skip
print("Last branch")
while some_condition(unformatted, args): # fmt: skip
print("Do something")
for i in some_iter(unformatted, args): # fmt: skip
print("Do something")
async def test_async_for():
async for i in some_async_iter(unformatted, args): # fmt: skip
print("Do something")
try: # fmt: skip
some_call()
except UnformattedError as ex:
handle_exception()
finally: # fmt: skip
finally_call()
with give_me_context(unformatted, args): # fmt: skip
print("Do something")
async def test_async_with():
async with give_me_async_context(unformatted, args): # fmt: skip
print("Do something")
```
## Black Output
```py
# Make sure a leading comment is not removed.
def some_func( unformatted, args ): # fmt: skip
print("I am some_func")
return 0
# Make sure this comment is not removed.
# Make sure a leading comment is not removed.
async def some_async_func( unformatted, args): # fmt: skip
print("I am some_async_func")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
class SomeClass( Unformatted, SuperClasses ): # fmt: skip
def some_method( self, unformatted, args ): # fmt: skip
print("I am some_method")
return 0
async def some_async_method( self, unformatted, args ): # fmt: skip
print("I am some_async_method")
await asyncio.sleep(1)
# Make sure a leading comment is not removed.
if unformatted_call( args ): # fmt: skip
print("First branch")
# Make sure this is not removed.
elif another_unformatted_call( args ): # fmt: skip
print("Second branch")
else : # fmt: skip
print("Last branch")
while some_condition( unformatted, args ): # fmt: skip
print("Do something")
for i in some_iter( unformatted, args ): # fmt: skip
print("Do something")
async def test_async_for():
async for i in some_async_iter( unformatted, args ): # fmt: skip
print("Do something")
try : # fmt: skip
some_call()
except UnformattedError as ex: # fmt: skip
handle_exception()
finally : # fmt: skip
finally_call()
with give_me_context( unformatted, args ): # fmt: skip
print("Do something")
async def test_async_with():
async with give_me_async_context( unformatted, args ): # fmt: skip
print("Do something")
```

View file

@ -66,30 +66,83 @@ with hmm_but_this_should_get_two_preceding_newlines():
```diff
--- Black
+++ Ruff
@@ -5,7 +5,8 @@
@@ -1,11 +1,11 @@
def f(
- a,
- **kwargs,
+ a,
+ **kwargs,
) -> A:
with cache_dir():
if something:
result = CliRunner().invoke(
- result = CliRunner().invoke(
- black.main, [str(src1), str(src2), "--diff", "--check"]
+ black.main,
+ [str(src1), str(src2), "--diff", "--check"],
+ result = (
+ CliRunner().invoke(black.main, [str(src1), str(src2), "--diff", "--check"])
)
limited.append(-limited.pop()) # negate top
return A(
@@ -13,34 +13,24 @@
very_long_argument_name2=-very.long.value.for_the_argument,
**kwargs,
)
-
-
def g():
"Docstring."
-
def inner():
pass
-
print("Inner defs should breathe a little.")
-
-
def h():
def inner():
pass
-
print("Inner defs should breathe a little.")
if os.name == "posix":
import termios
-
def i_should_be_followed_by_only_one_newline():
pass
-
elif os.name == "nt":
try:
import msvcrt
-
def i_should_be_followed_by_only_one_newline():
pass
@@ -54,12 +44,10 @@
class IHopeYouAreHavingALovelyDay:
def __call__(self):
print("i_should_be_followed_by_only_one_newline")
-
else:
def foo():
pass
-
with hmm_but_this_should_get_two_preceding_newlines():
pass
```
## Ruff Output
```py
def f(
a,
**kwargs,
a,
**kwargs,
) -> A:
with cache_dir():
if something:
result = CliRunner().invoke(
black.main,
[str(src1), str(src2), "--diff", "--check"],
result = (
CliRunner().invoke(black.main, [str(src1), str(src2), "--diff", "--check"])
)
limited.append(-limited.pop()) # negate top
return A(
@ -97,34 +150,24 @@ def f(
very_long_argument_name2=-very.long.value.for_the_argument,
**kwargs,
)
def g():
"Docstring."
def inner():
pass
print("Inner defs should breathe a little.")
def h():
def inner():
pass
print("Inner defs should breathe a little.")
if os.name == "posix":
import termios
def i_should_be_followed_by_only_one_newline():
pass
elif os.name == "nt":
try:
import msvcrt
def i_should_be_followed_by_only_one_newline():
pass
@ -138,13 +181,11 @@ elif False:
class IHopeYouAreHavingALovelyDay:
def __call__(self):
print("i_should_be_followed_by_only_one_newline")
else:
def foo():
pass
with hmm_but_this_should_get_two_preceding_newlines():
pass
```

View file

@ -108,24 +108,101 @@ def __await__(): return (yield)
```diff
--- Black
+++ Ruff
@@ -6,7 +6,7 @@
@@ -4,97 +4,52 @@
from library import some_connection, some_decorator
from third_party import X, Y, Z
-from library import some_connection, some_decorator
-
-f"trigger 3.6 mode"
-
-
+from library import some_connection, \
+ some_decorator
+f'trigger 3.6 mode'
def func_no_args():
@@ -64,19 +64,15 @@
def spaces2(result=_core.Value(None)):
- a
- b
- c
- if True:
- raise RuntimeError
- if False:
- ...
- for i in range(10):
- print(i)
- continue
- exec("new-style exec", {}, {})
- return None
-
-
+ a; b; c
+ if True: raise RuntimeError
+ if False: ...
+ for i in range(10):
+ print(i)
+ continue
+ exec("new-style exec", {}, {})
+ return None
async def coroutine(arg, exec=False):
- "Single-line docstring. Multiline is harder to reformat."
- async with some_connection() as conn:
- await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
- await asyncio.sleep(1)
-
-
+ "Single-line docstring. Multiline is harder to reformat."
+ async with some_connection() as conn:
+ await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
+ await asyncio.sleep(1)
@asyncio.coroutine
-@some_decorator(with_args=True, many_args=[1, 2, 3])
-def function_signature_stress_test(
- number: int,
- no_annotation=None,
- text: str = "default",
- *,
- debug: bool = False,
- **kwargs,
-) -> str:
- return text[number:-1]
-
-
-def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
- offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000)))
- assert task._cancel_stack[: len(old_stack)] == old_stack
-
-
-def spaces_types(
- a: int = 1,
- b: tuple = (),
- c: list = [],
- d: dict = {},
- e: bool = True,
- f: int = -1,
- g: int = 1 if False else 2,
- h: str = "",
- i: str = r"",
-):
- ...
-
-
-def spaces2(result=_core.Value(None)):
- assert fut is self._read_fut, (fut, self._read_fut)
+ assert fut is self._read_fut, fut, self._read_fut
+
-
-
+@some_decorator(
+with_args=True,
+many_args=[1,2,3]
+)
+def function_signature_stress_test(number:int,no_annotation=None,text:str="default",* ,debug:bool=False,**kwargs) -> str:
+ return text[number:-1]
+def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
+ offset = attr.ib(default=attr.Factory( lambda: _r.uniform(10000, 200000)))
+ assert task._cancel_stack[:len(old_stack)] == old_stack
+def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
+def spaces2(result= _core.Value(None)):
+ assert fut is self._read_fut, (fut, self._read_fut)
+
def example(session):
- result = (
- session.query(models.Customer.id)
@ -136,30 +213,76 @@ def __await__(): return (yield)
- .order_by(models.Customer.id.asc())
- .all()
- )
-
-
+ result = session.query(models.Customer.id).filter(
+ models.Customer.account_id == account_id,
+ models.Customer.email == email_address,
+ ).order_by(models.Customer.id.asc()).all()
+ ).order_by(
+ models.Customer.id.asc()
+ ).all()
def long_lines():
@@ -135,14 +131,13 @@
a,
**kwargs,
if True:
typedargslist.extend(
- gen_annotated_params(
- ast_args.kwonlyargs,
- ast_args.kw_defaults,
- parameters,
- implicit_default=True,
- )
+ gen_annotated_params(ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True)
)
typedargslist.extend(
gen_annotated_params(
- ast_args.kwonlyargs,
- ast_args.kw_defaults,
- parameters,
- implicit_default=True,
+ ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True,
# trailing standalone comment
)
)
@@ -117,23 +72,18 @@
\n?
)
$
- """,
- re.MULTILINE | re.VERBOSE,
+ """, re.MULTILINE | re.VERBOSE
)
-
-
def trailing_comma():
mapping = {
- A: 0.25 * (10.0 / 12),
- B: 0.1 * (10.0 / 12),
- C: 0.1 * (10.0 / 12),
- D: 0.1 * (10.0 / 12),
- }
-
-
+ A: 0.25 * (10.0 / 12),
+ B: 0.1 * (10.0 / 12),
+ C: 0.1 * (10.0 / 12),
+ D: 0.1 * (10.0 / 12),
+}
def f(
- a,
- **kwargs,
+ a,
+ **kwargs,
) -> A:
- return (
+ return
return (
yield from A(
very_long_argument_name1=very_long_value_for_the_argument,
very_long_argument_name2=very_long_value_for_the_argument,
@@ -142,7 +92,4 @@
**kwargs,
)
- )
def __await__():
)
-
-
-def __await__():
- return (yield)
+ return yield
+def __await__(): return (yield)
```
## Ruff Output
@ -171,93 +294,52 @@ import sys
from third_party import X, Y, Z
from library import some_connection, some_decorator
from library import some_connection, \
some_decorator
f'trigger 3.6 mode'
def func_no_args():
a
b
c
if True:
raise RuntimeError
if False:
...
for i in range(10):
print(i)
continue
exec("new-style exec", {}, {})
return None
a; b; c
if True: raise RuntimeError
if False: ...
for i in range(10):
print(i)
continue
exec("new-style exec", {}, {})
return None
async def coroutine(arg, exec=False):
"Single-line docstring. Multiline is harder to reformat."
async with some_connection() as conn:
await conn.do_what_i_mean("SELECT bobby, tables FROM xkcd", timeout=2)
await asyncio.sleep(1)
"Single-line docstring. Multiline is harder to reformat."
async with some_connection() as conn:
await conn.do_what_i_mean('SELECT bobby, tables FROM xkcd', timeout=2)
await asyncio.sleep(1)
@asyncio.coroutine
@some_decorator(with_args=True, many_args=[1, 2, 3])
def function_signature_stress_test(
number: int,
no_annotation=None,
text: str = "default",
*,
debug: bool = False,
**kwargs,
) -> str:
return text[number:-1]
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r""):
offset = attr.ib(default=attr.Factory(lambda: _r.uniform(10000, 200000)))
assert task._cancel_stack[: len(old_stack)] == old_stack
def spaces_types(
a: int = 1,
b: tuple = (),
c: list = [],
d: dict = {},
e: bool = True,
f: int = -1,
g: int = 1 if False else 2,
h: str = "",
i: str = r"",
):
...
def spaces2(result=_core.Value(None)):
assert fut is self._read_fut, fut, self._read_fut
@some_decorator(
with_args=True,
many_args=[1,2,3]
)
def function_signature_stress_test(number:int,no_annotation=None,text:str="default",* ,debug:bool=False,**kwargs) -> str:
return text[number:-1]
def spaces(a=1, b=(), c=[], d={}, e=True, f=-1, g=1 if False else 2, h="", i=r''):
offset = attr.ib(default=attr.Factory( lambda: _r.uniform(10000, 200000)))
assert task._cancel_stack[:len(old_stack)] == old_stack
def spaces_types(a: int = 1, b: tuple = (), c: list = [], d: dict = {}, e: bool = True, f: int = -1, g: int = 1 if False else 2, h: str = "", i: str = r''): ...
def spaces2(result= _core.Value(None)):
assert fut is self._read_fut, (fut, self._read_fut)
def example(session):
result = session.query(models.Customer.id).filter(
models.Customer.account_id == account_id,
models.Customer.email == email_address,
).order_by(models.Customer.id.asc()).all()
).order_by(
models.Customer.id.asc()
).all()
def long_lines():
if True:
typedargslist.extend(
gen_annotated_params(
ast_args.kwonlyargs,
ast_args.kw_defaults,
parameters,
implicit_default=True,
)
gen_annotated_params(ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True)
)
typedargslist.extend(
gen_annotated_params(
ast_args.kwonlyargs,
ast_args.kw_defaults,
parameters,
implicit_default=True,
ast_args.kwonlyargs, ast_args.kw_defaults, parameters, implicit_default=True,
# trailing standalone comment
)
)
@ -280,34 +362,27 @@ def long_lines():
\n?
)
$
""",
re.MULTILINE | re.VERBOSE,
""", re.MULTILINE | re.VERBOSE
)
def trailing_comma():
mapping = {
A: 0.25 * (10.0 / 12),
B: 0.1 * (10.0 / 12),
C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12),
}
A: 0.25 * (10.0 / 12),
B: 0.1 * (10.0 / 12),
C: 0.1 * (10.0 / 12),
D: 0.1 * (10.0 / 12),
}
def f(
a,
**kwargs,
a,
**kwargs,
) -> A:
return
return (
yield from A(
very_long_argument_name1=very_long_value_for_the_argument,
very_long_argument_name2=very_long_value_for_the_argument,
**kwargs,
)
def __await__():
return yield
)
def __await__(): return (yield)
```
## Black Output

View file

@ -74,195 +74,199 @@ some_module.some_function(
```diff
--- Black
+++ Ruff
@@ -52,53 +52,52 @@
@@ -1,69 +1,26 @@
-def f(
- a,
-):
- d = {
- "key": "value",
- }
+def f(a,):
+ d = {'key': 'value',}
tup = (1,)
-
-def f2(
- a,
- b,
-):
- d = {
- "key": "value",
- "key2": "value2",
- }
- tup = (
- 1,
- 2,
- )
-
+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],
- )
+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"]
- ):
+ 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,]}}}
-def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> (
- Set["xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]
-):
+def xxxxxxxxxxxxxxxxxxxxxxxxxxxx() -> Set[
+ "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+]:
json = {
"k": {
"k2": {
"k3": [
1,
- 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
-):
+def some_function_with_a_really_long_name() -> returning_a_deeply_nested_import_of_a_type_i_suppose:
@@ -74,24 +31,21 @@
pass
def some_method_with_a_really_long_name(
-def some_method_with_a_really_long_name(
- very_long_parameter_so_yeah: str, another_long_parameter: int
+ 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:
-) -> another_case_of_returning_a_deeply_nested_import_of_a_type_i_suppose_cause_why_not:
+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() -> (
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
+ 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
- )
+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
+ argument1,
+ (one_element_tuple,),
+ argument4,
+ argument5,
+ argument6,
)
@@ -103,12 +57,5 @@
# Inner trailing comma causes outer to explode
some_module.some_function(
- argument1,
- (
- one,
- two,
- ),
- argument4,
- argument5,
- argument6,
+ argument1, (one, two,), argument4, argument5, argument6
)
```
## Ruff Output
```py
def f(
a,
):
d = {
"key": "value",
}
def f(a,):
d = {'key': 'value',}
tup = (1,)
def f2(a,b,):
d = {'key': 'value', 'key2': 'value2',}
tup = (1,2,)
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],
)
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"]
):
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,
],
},
},
}
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
def some_function_with_a_really_long_name() -> (
returning_a_deeply_nested_import_of_a_type_i_suppose
):
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 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,
argument1, (one_element_tuple,), argument4, argument5, argument6
)
# Inner trailing comma causes outer to explode
some_module.some_function(
argument1,
(
one,
two,
),
argument4,
argument5,
argument6,
argument1, (one, two,), argument4, argument5, argument6
)
```

View file

@ -0,0 +1,242 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/import_spacing.py
---
## Input
```py
"""The asyncio package, tracking PEP 3156."""
# flake8: noqa
from logging import (
WARNING
)
from logging import (
ERROR,
)
import sys
# This relies on each of the submodules having an __all__ variable.
from .base_events import *
from .coroutines import *
from .events import * # comment here
from .futures import *
from .locks import * # comment here
from .protocols import *
from ..runners import * # comment here
from ..queues import *
from ..streams import *
from some_library import (
Just, Enough, Libraries, To, Fit, In, This, Nice, Split, Which, We, No, Longer, Use
)
from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
from .a.b.c.subprocess import *
from . import (tasks)
from . import (A, B, C)
from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \
SomeVeryLongNameAndAllOfItsAdditionalLetters2
__all__ = (
base_events.__all__
+ coroutines.__all__
+ events.__all__
+ futures.__all__
+ locks.__all__
+ protocols.__all__
+ runners.__all__
+ queues.__all__
+ streams.__all__
+ tasks.__all__
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -2,8 +2,10 @@
# flake8: noqa
-from logging import WARNING
from logging import (
+ WARNING
+)
+from logging import (
ERROR,
)
import sys
@@ -22,33 +24,16 @@
from ..streams import *
from some_library import (
- Just,
- Enough,
- Libraries,
- To,
- Fit,
- In,
- This,
- Nice,
- Split,
- Which,
- We,
- No,
- Longer,
- Use,
+ Just, Enough, Libraries, To, Fit, In, This, Nice, Split, Which, We, No, Longer, Use
)
-from name_of_a_company.extremely_long_project_name.component.ttypes import (
- CuteLittleServiceHandlerFactoryyy,
-)
+from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
from .a.b.c.subprocess import *
-from . import tasks
-from . import A, B, C
-from . import (
- SomeVeryLongNameAndAllOfItsAdditionalLetters1,
- SomeVeryLongNameAndAllOfItsAdditionalLetters2,
-)
+from . import (tasks)
+from . import (A, B, C)
+from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \
+ SomeVeryLongNameAndAllOfItsAdditionalLetters2
__all__ = (
base_events.__all__
```
## Ruff Output
```py
"""The asyncio package, tracking PEP 3156."""
# flake8: noqa
from logging import (
WARNING
)
from logging import (
ERROR,
)
import sys
# This relies on each of the submodules having an __all__ variable.
from .base_events import *
from .coroutines import *
from .events import * # comment here
from .futures import *
from .locks import * # comment here
from .protocols import *
from ..runners import * # comment here
from ..queues import *
from ..streams import *
from some_library import (
Just, Enough, Libraries, To, Fit, In, This, Nice, Split, Which, We, No, Longer, Use
)
from name_of_a_company.extremely_long_project_name.component.ttypes import CuteLittleServiceHandlerFactoryyy
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
from .a.b.c.subprocess import *
from . import (tasks)
from . import (A, B, C)
from . import SomeVeryLongNameAndAllOfItsAdditionalLetters1, \
SomeVeryLongNameAndAllOfItsAdditionalLetters2
__all__ = (
base_events.__all__
+ coroutines.__all__
+ events.__all__
+ futures.__all__
+ locks.__all__
+ protocols.__all__
+ runners.__all__
+ queues.__all__
+ streams.__all__
+ tasks.__all__
)
```
## Black Output
```py
"""The asyncio package, tracking PEP 3156."""
# flake8: noqa
from logging import WARNING
from logging import (
ERROR,
)
import sys
# This relies on each of the submodules having an __all__ variable.
from .base_events import *
from .coroutines import *
from .events import * # comment here
from .futures import *
from .locks import * # comment here
from .protocols import *
from ..runners import * # comment here
from ..queues import *
from ..streams import *
from some_library import (
Just,
Enough,
Libraries,
To,
Fit,
In,
This,
Nice,
Split,
Which,
We,
No,
Longer,
Use,
)
from name_of_a_company.extremely_long_project_name.component.ttypes import (
CuteLittleServiceHandlerFactoryyy,
)
from name_of_a_company.extremely_long_project_name.extremely_long_component_name.ttypes import *
from .a.b.c.subprocess import *
from . import tasks
from . import A, B, C
from . import (
SomeVeryLongNameAndAllOfItsAdditionalLetters1,
SomeVeryLongNameAndAllOfItsAdditionalLetters2,
)
__all__ = (
base_events.__all__
+ coroutines.__all__
+ events.__all__
+ futures.__all__
+ locks.__all__
+ protocols.__all__
+ runners.__all__
+ queues.__all__
+ streams.__all__
+ tasks.__all__
)
```

View file

@ -0,0 +1,98 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
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
@@ -4,19 +4,9 @@
b = tuple[int,]
# The magic comma still applies to multi-element subscripts.
-c: tuple[
- int,
- int,
-]
-d = tuple[
- int,
- int,
-]
+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,],
-]
+small_list = [1,]
+list_of_types = [tuple[int,],]
```
## Ruff 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,],]
```
## 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,],
]
```

View file

@ -0,0 +1,230 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/power_op_spacing.py
---
## Input
```py
def function(**kwargs):
t = a**2 + b**3
return t ** 2
def function_replace_spaces(**kwargs):
t = a **2 + b** 3 + c ** 4
def function_dont_replace_spaces():
{**a, **b, **c}
a = 5**~4
b = 5 ** f()
c = -(5**2)
d = 5 ** f["hi"]
e = lazy(lambda **kwargs: 5)
f = f() ** 5
g = a.b**c.d
h = 5 ** funcs.f()
i = funcs.f() ** 5
j = super().name ** 5
k = [(2**idx, value) for idx, value in pairs]
l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2**63], [1, 2**63])]
n = count <= 10**5
o = settings(max_examples=10**6)
p = {(k, k**2): v**2 for k, v in pairs}
q = [10**i for i in range(6)]
r = x**y
a = 5.0**~4.0
b = 5.0 ** f()
c = -(5.0**2.0)
d = 5.0 ** f["hi"]
e = lazy(lambda **kwargs: 5)
f = f() ** 5.0
g = a.b**c.d
h = 5.0 ** funcs.f()
i = funcs.f() ** 5.0
j = super().name ** 5.0
k = [(2.0**idx, value) for idx, value in pairs]
l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2.0**63.0], [1.0, 2**63.0])]
n = count <= 10**5.0
o = settings(max_examples=10**6.0)
p = {(k, k**2): v**2.0 for k, v in pairs}
q = [10.5**i for i in range(6)]
# WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873)
if hasattr(view, "sum_of_weights"):
return np.divide( # type: ignore[no-any-return]
view.variance, # type: ignore[union-attr]
view.sum_of_weights, # type: ignore[union-attr]
out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr]
where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr]
)
return np.divide(
where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore
)
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -1,10 +1,10 @@
def function(**kwargs):
t = a**2 + b**3
- return t**2
+ return t ** 2
def function_replace_spaces(**kwargs):
- t = a**2 + b**3 + c**4
+ t = a **2 + b** 3 + c ** 4
def function_dont_replace_spaces():
```
## Ruff Output
```py
def function(**kwargs):
t = a**2 + b**3
return t ** 2
def function_replace_spaces(**kwargs):
t = a **2 + b** 3 + c ** 4
def function_dont_replace_spaces():
{**a, **b, **c}
a = 5**~4
b = 5 ** f()
c = -(5**2)
d = 5 ** f["hi"]
e = lazy(lambda **kwargs: 5)
f = f() ** 5
g = a.b**c.d
h = 5 ** funcs.f()
i = funcs.f() ** 5
j = super().name ** 5
k = [(2**idx, value) for idx, value in pairs]
l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2**63], [1, 2**63])]
n = count <= 10**5
o = settings(max_examples=10**6)
p = {(k, k**2): v**2 for k, v in pairs}
q = [10**i for i in range(6)]
r = x**y
a = 5.0**~4.0
b = 5.0 ** f()
c = -(5.0**2.0)
d = 5.0 ** f["hi"]
e = lazy(lambda **kwargs: 5)
f = f() ** 5.0
g = a.b**c.d
h = 5.0 ** funcs.f()
i = funcs.f() ** 5.0
j = super().name ** 5.0
k = [(2.0**idx, value) for idx, value in pairs]
l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2.0**63.0], [1.0, 2**63.0])]
n = count <= 10**5.0
o = settings(max_examples=10**6.0)
p = {(k, k**2): v**2.0 for k, v in pairs}
q = [10.5**i for i in range(6)]
# WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873)
if hasattr(view, "sum_of_weights"):
return np.divide( # type: ignore[no-any-return]
view.variance, # type: ignore[union-attr]
view.sum_of_weights, # type: ignore[union-attr]
out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr]
where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr]
)
return np.divide(
where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore
)
```
## Black Output
```py
def function(**kwargs):
t = a**2 + b**3
return t**2
def function_replace_spaces(**kwargs):
t = a**2 + b**3 + c**4
def function_dont_replace_spaces():
{**a, **b, **c}
a = 5**~4
b = 5 ** f()
c = -(5**2)
d = 5 ** f["hi"]
e = lazy(lambda **kwargs: 5)
f = f() ** 5
g = a.b**c.d
h = 5 ** funcs.f()
i = funcs.f() ** 5
j = super().name ** 5
k = [(2**idx, value) for idx, value in pairs]
l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2**63], [1, 2**63])]
n = count <= 10**5
o = settings(max_examples=10**6)
p = {(k, k**2): v**2 for k, v in pairs}
q = [10**i for i in range(6)]
r = x**y
a = 5.0**~4.0
b = 5.0 ** f()
c = -(5.0**2.0)
d = 5.0 ** f["hi"]
e = lazy(lambda **kwargs: 5)
f = f() ** 5.0
g = a.b**c.d
h = 5.0 ** funcs.f()
i = funcs.f() ** 5.0
j = super().name ** 5.0
k = [(2.0**idx, value) for idx, value in pairs]
l = mod.weights_[0] == pytest.approx(0.95**100, abs=0.001)
m = [([2.0**63.0], [1.0, 2**63.0])]
n = count <= 10**5.0
o = settings(max_examples=10**6.0)
p = {(k, k**2): v**2.0 for k, v in pairs}
q = [10.5**i for i in range(6)]
# WE SHOULD DEFINITELY NOT EAT THESE COMMENTS (https://github.com/psf/black/issues/2873)
if hasattr(view, "sum_of_weights"):
return np.divide( # type: ignore[no-any-return]
view.variance, # type: ignore[union-attr]
view.sum_of_weights, # type: ignore[union-attr]
out=np.full(view.sum_of_weights.shape, np.nan), # type: ignore[union-attr]
where=view.sum_of_weights**2 > view.sum_of_weights_squared, # type: ignore[union-attr]
)
return np.divide(
where=view.sum_of_weights_of_weight_long**2 > view.sum_of_weights_squared, # type: ignore
)
```

View file

@ -0,0 +1,96 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/prefer_rhs_split_reformatted.py
---
## Input
```py
# Test cases separate from `prefer_rhs_split.py` that contains unformatted source.
# Left hand side fits in a single line but will still be exploded by the
# magic trailing comma.
first_value, (m1, m2,), third_value = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv(
arg1,
arg2,
)
# Make when when the left side of assignment plus the opening paren "... = (" is
# exactly line length limit + 1, it won't be split like that.
xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)] = 1
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -2,20 +2,11 @@
# Left hand side fits in a single line but will still be exploded by the
# magic trailing comma.
-(
- first_value,
- (
- m1,
- m2,
- ),
- third_value,
-) = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv(
+first_value, (m1, m2,), third_value = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv(
arg1,
arg2,
)
# Make when when the left side of assignment plus the opening paren "... = (" is
# exactly line length limit + 1, it won't be split like that.
-xxxxxxxxx_yyy_zzzzzzzz[
- xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)
-] = 1
+xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)] = 1
```
## Ruff Output
```py
# Test cases separate from `prefer_rhs_split.py` that contains unformatted source.
# Left hand side fits in a single line but will still be exploded by the
# magic trailing comma.
first_value, (m1, m2,), third_value = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv(
arg1,
arg2,
)
# Make when when the left side of assignment plus the opening paren "... = (" is
# exactly line length limit + 1, it won't be split like that.
xxxxxxxxx_yyy_zzzzzzzz[xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)] = 1
```
## Black Output
```py
# Test cases separate from `prefer_rhs_split.py` that contains unformatted source.
# Left hand side fits in a single line but will still be exploded by the
# magic trailing comma.
(
first_value,
(
m1,
m2,
),
third_value,
) = xxxxxx_yyyyyy_zzzzzz_wwwwww_uuuuuuu_vvvvvvvvvvv(
arg1,
arg2,
)
# Make when when the left side of assignment plus the opening paren "... = (" is
# exactly line length limit + 1, it won't be split like that.
xxxxxxxxx_yyy_zzzzzzzz[
xx.xxxxxx(x_yyy_zzzzzz.xxxxx[0]), x_yyy_zzzzzz.xxxxxx(xxxx=1)
] = 1
```

View file

@ -94,39 +94,55 @@ async def main():
```diff
--- Black
+++ Ruff
@@ -8,59 +8,63 @@
@@ -1,93 +1,81 @@
import asyncio
-
# Control example
async def main():
await asyncio.sleep(1)
-
# Remove brackets for short coroutine/task
async def main():
- await asyncio.sleep(1)
-
+ await (asyncio.sleep(1))
async def main():
- await asyncio.sleep(1)
+ await (asyncio.sleep(1))
-
+ await (
+ asyncio.sleep(1)
+ )
async def main():
- await asyncio.sleep(1)
+ await (asyncio.sleep(1))
-
+ await (asyncio.sleep(1)
+ )
# Check comments
async def main():
- await asyncio.sleep(1) # Hello
+ await (asyncio.sleep(1))
-
+ await ( # Hello
+ asyncio.sleep(1)
+ )
async def main():
- await asyncio.sleep(1) # Hello
+ await (asyncio.sleep(1)) # Hello
-
+ await (
+ asyncio.sleep(1) # Hello
+ )
async def main():
- await asyncio.sleep(1) # Hello
+ await (asyncio.sleep(1)) # Hello
-
+ await (
+ asyncio.sleep(1)
+ ) # Hello
# Long lines
async def main():
@ -138,18 +154,9 @@ async def main():
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
+ (
+ await asyncio.gather(
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ )
)
- )
-
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1))
# Same as above but with magic trailing comma in function
async def main():
@ -161,40 +168,58 @@ async def main():
- asyncio.sleep(1),
- asyncio.sleep(1),
- asyncio.sleep(1),
+ (
+ await asyncio.gather(
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ asyncio.sleep(1),
+ )
)
- )
-
+ await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),)
# Cr@zY Br@ck3Tz
async def main():
- await black(1)
+ await (black(1))
-
+ await (
+ (((((((((((((
+ ((( (((
+ ((( (((
+ ((( (((
+ ((( (((
+ ((black(1)))
+ ))) )))
+ ))) )))
+ ))) )))
+ ))) )))
+ )))))))))))))
+ )
# Keep brackets around non power operations and nested awaits
@@ -82,11 +86,11 @@
async def main():
await (set_of_tasks | other_set)
-
async def main():
await (await asyncio.sleep(1))
-
# It's awaits all the way down...
async def main():
await (await x)
-
async def main():
await (yield x)
-
async def main():
- await (await asyncio.sleep(1))
-
+ await (await (asyncio.sleep(1)))
async def main():
- await (await (await (await (await asyncio.sleep(1)))))
-
+ await (await (await (await (await (asyncio.sleep(1))))))
async def main():
await (yield)
```
## Ruff Output
@ -202,99 +227,83 @@ async def main():
```py
import asyncio
# Control example
async def main():
await asyncio.sleep(1)
# Remove brackets for short coroutine/task
async def main():
await (asyncio.sleep(1))
async def main():
await (
asyncio.sleep(1)
)
async def main():
await (asyncio.sleep(1))
async def main():
await (asyncio.sleep(1))
await (asyncio.sleep(1)
)
# Check comments
async def main():
await (asyncio.sleep(1))
await ( # Hello
asyncio.sleep(1)
)
async def main():
await (asyncio.sleep(1)) # Hello
await (
asyncio.sleep(1) # Hello
)
async def main():
await (asyncio.sleep(1)) # Hello
await (
asyncio.sleep(1)
) # Hello
# Long lines
async def main():
(
await asyncio.gather(
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
)
)
await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1))
# Same as above but with magic trailing comma in function
async def main():
(
await asyncio.gather(
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
asyncio.sleep(1),
)
)
await asyncio.gather(asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1), asyncio.sleep(1),)
# Cr@zY Br@ck3Tz
async def main():
await (black(1))
await (
(((((((((((((
((( (((
((( (((
((( (((
((( (((
((black(1)))
))) )))
))) )))
))) )))
))) )))
)))))))))))))
)
# Keep brackets around non power operations and nested awaits
async def main():
await (set_of_tasks | other_set)
async def main():
await (await asyncio.sleep(1))
# It's awaits all the way down...
async def main():
await (await x)
async def main():
await (yield x)
async def main():
await (await (asyncio.sleep(1)))
async def main():
await (await (await (await (await (asyncio.sleep(1))))))
async def main():
await (yield)
```

View file

@ -57,7 +57,7 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
raise err
# This is tuple of exceptions.
@@ -21,9 +21,7 @@
@@ -21,22 +21,15 @@
# Test long variants.
try:
a.something
@ -68,6 +68,21 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
raise err
try:
a.something
-except (
- some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,
-) as err:
+except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err:
raise err
try:
a.something
-except (
- some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,
- some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,
-) as err:
+except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error, some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err:
raise err
```
## Ruff Output
@ -101,17 +116,12 @@ except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.ov
try:
a.something
except (
some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,
) as err:
except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,) as err:
raise err
try:
a.something
except (
some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,
some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error,
) as err:
except (some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error, some.really.really.really.looooooooooooooooooooooooooooooooong.module.over89.chars.Error) as err:
raise err
```

View file

@ -32,24 +32,44 @@ for (((((k, v))))) in d.items():
```diff
--- Black
+++ Ruff
@@ -17,9 +17,7 @@
for (
k,
v,
@@ -1,5 +1,5 @@
# Only remove tuple brackets after `for`
-for k, v in d.items():
+for (k, v) in d.items():
print(k, v)
# Don't touch tuple brackets after `in`
@@ -8,20 +8,12 @@
module._verify_python3_env = lambda: None
# Brackets remain for long for loop lines
-for (
- why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long,
- i_dont_know_but_we_should_still_check_the_behaviour_if_they_do,
-) in d.items():
+for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items():
print(k, v)
-for (
- k,
- v,
-) in (
- dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items()
-):
+) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
+for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
print(k, v)
# Test deeply nested brackets
-for k, v in d.items():
+for (((((k, v))))) in d.items():
print(k, v)
```
## Ruff Output
```py
# Only remove tuple brackets after `for`
for k, v in d.items():
for (k, v) in d.items():
print(k, v)
# Don't touch tuple brackets after `in`
@ -58,20 +78,14 @@ for module in (core, _unicodefun):
module._verify_python3_env = lambda: None
# Brackets remain for long for loop lines
for (
why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long,
i_dont_know_but_we_should_still_check_the_behaviour_if_they_do,
) in d.items():
for (why_would_anyone_choose_to_name_a_loop_variable_with_a_name_this_long, i_dont_know_but_we_should_still_check_the_behaviour_if_they_do) in d.items():
print(k, v)
for (
k,
v,
) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
for (k, v) in dfkasdjfldsjflkdsjflkdsjfdslkfjldsjfgkjdshgkljjdsfldgkhsdofudsfudsofajdslkfjdslkfjldisfjdffjsdlkfjdlkjjkdflskadjldkfjsalkfjdasj.items():
print(k, v)
# Test deeply nested brackets
for k, v in d.items():
for (((((k, v))))) in d.items():
print(k, v)
```

View file

@ -0,0 +1,428 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/remove_newline_after_code_block_open.py
---
## Input
```py
import random
def foo1():
print("The newline above me should be deleted!")
def foo2():
print("All the newlines above me should be deleted!")
def foo3():
print("No newline above me!")
print("There is a newline above me, and that's OK!")
def foo4():
# There is a comment here
print("The newline above me should not be deleted!")
class Foo:
def bar(self):
print("The newline above me should be deleted!")
for i in range(5):
print(f"{i}) The line above me should be removed!")
for i in range(5):
print(f"{i}) The lines above me should be removed!")
for i in range(5):
for j in range(7):
print(f"{i}) The lines above me should be removed!")
if random.randint(0, 3) == 0:
print("The new line above me is about to be removed!")
if random.randint(0, 3) == 0:
print("The new lines above me is about to be removed!")
if random.randint(0, 3) == 0:
if random.uniform(0, 1) > 0.5:
print("Two lines above me are about to be removed!")
while True:
print("The newline above me should be deleted!")
while True:
print("The newlines above me should be deleted!")
while True:
while False:
print("The newlines above me should be deleted!")
with open("/path/to/file.txt", mode="w") as file:
file.write("The new line above me is about to be removed!")
with open("/path/to/file.txt", mode="w") as file:
file.write("The new lines above me is about to be removed!")
with open("/path/to/file.txt", mode="r") as read_file:
with open("/path/to/output_file.txt", mode="w") as write_file:
write_file.writelines(read_file.readlines())
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -2,20 +2,26 @@
def foo1():
+
print("The newline above me should be deleted!")
def foo2():
+
+
+
print("All the newlines above me should be deleted!")
def foo3():
+
print("No newline above me!")
print("There is a newline above me, and that's OK!")
def foo4():
+
# There is a comment here
print("The newline above me should not be deleted!")
@@ -23,27 +29,39 @@
class Foo:
def bar(self):
+
print("The newline above me should be deleted!")
for i in range(5):
+
print(f"{i}) The line above me should be removed!")
for i in range(5):
+
+
+
print(f"{i}) The lines above me should be removed!")
for i in range(5):
+
for j in range(7):
+
print(f"{i}) The lines above me should be removed!")
if random.randint(0, 3) == 0:
+
print("The new line above me is about to be removed!")
if random.randint(0, 3) == 0:
+
+
+
+
print("The new lines above me is about to be removed!")
@@ -53,26 +71,38 @@
while True:
+
print("The newline above me should be deleted!")
while True:
+
+
+
print("The newlines above me should be deleted!")
while True:
+
while False:
+
print("The newlines above me should be deleted!")
with open("/path/to/file.txt", mode="w") as file:
+
file.write("The new line above me is about to be removed!")
with open("/path/to/file.txt", mode="w") as file:
+
+
+
file.write("The new lines above me is about to be removed!")
with open("/path/to/file.txt", mode="r") as read_file:
+
with open("/path/to/output_file.txt", mode="w") as write_file:
+
write_file.writelines(read_file.readlines())
```
## Ruff Output
```py
import random
def foo1():
print("The newline above me should be deleted!")
def foo2():
print("All the newlines above me should be deleted!")
def foo3():
print("No newline above me!")
print("There is a newline above me, and that's OK!")
def foo4():
# There is a comment here
print("The newline above me should not be deleted!")
class Foo:
def bar(self):
print("The newline above me should be deleted!")
for i in range(5):
print(f"{i}) The line above me should be removed!")
for i in range(5):
print(f"{i}) The lines above me should be removed!")
for i in range(5):
for j in range(7):
print(f"{i}) The lines above me should be removed!")
if random.randint(0, 3) == 0:
print("The new line above me is about to be removed!")
if random.randint(0, 3) == 0:
print("The new lines above me is about to be removed!")
if random.randint(0, 3) == 0:
if random.uniform(0, 1) > 0.5:
print("Two lines above me are about to be removed!")
while True:
print("The newline above me should be deleted!")
while True:
print("The newlines above me should be deleted!")
while True:
while False:
print("The newlines above me should be deleted!")
with open("/path/to/file.txt", mode="w") as file:
file.write("The new line above me is about to be removed!")
with open("/path/to/file.txt", mode="w") as file:
file.write("The new lines above me is about to be removed!")
with open("/path/to/file.txt", mode="r") as read_file:
with open("/path/to/output_file.txt", mode="w") as write_file:
write_file.writelines(read_file.readlines())
```
## Black Output
```py
import random
def foo1():
print("The newline above me should be deleted!")
def foo2():
print("All the newlines above me should be deleted!")
def foo3():
print("No newline above me!")
print("There is a newline above me, and that's OK!")
def foo4():
# There is a comment here
print("The newline above me should not be deleted!")
class Foo:
def bar(self):
print("The newline above me should be deleted!")
for i in range(5):
print(f"{i}) The line above me should be removed!")
for i in range(5):
print(f"{i}) The lines above me should be removed!")
for i in range(5):
for j in range(7):
print(f"{i}) The lines above me should be removed!")
if random.randint(0, 3) == 0:
print("The new line above me is about to be removed!")
if random.randint(0, 3) == 0:
print("The new lines above me is about to be removed!")
if random.randint(0, 3) == 0:
if random.uniform(0, 1) > 0.5:
print("Two lines above me are about to be removed!")
while True:
print("The newline above me should be deleted!")
while True:
print("The newlines above me should be deleted!")
while True:
while False:
print("The newlines above me should be deleted!")
with open("/path/to/file.txt", mode="w") as file:
file.write("The new line above me is about to be removed!")
with open("/path/to/file.txt", mode="w") as file:
file.write("The new lines above me is about to be removed!")
with open("/path/to/file.txt", mode="r") as read_file:
with open("/path/to/output_file.txt", mode="w") as write_file:
write_file.writelines(read_file.readlines())
```

View file

@ -68,127 +68,166 @@ def example8():
```diff
--- Black
+++ Ruff
@@ -1,18 +1,14 @@
x = 1
x = 1.2
-data = (
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
-).encode()
+data = ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").encode()
@@ -1,85 +1,55 @@
-x = 1
-x = 1.2
+x = (1)
+x = (1.2)
data = (
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
).encode()
-
async def show_status():
while True:
try:
if report_host:
- data = (
data = (
- f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- ).encode()
+ data = (f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").encode()
+ f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ ).encode()
except Exception as e:
pass
-
@@ -30,15 +26,11 @@
def example():
- return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example1():
- return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+ return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example1point5():
- return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
+ return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))))))
def example2():
- return (
- "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
- )
+ return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
+ return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example3():
- return (
- 1111111111111111111111111111111111111111111111111111111111111111111111111111111
- )
+ return 1111111111111111111111111111111111111111111111111111111111111111111111111111111
+ return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example4():
- return True
+ return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example5():
- return ()
+ return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example6():
- return {a: a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}
+ return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]})))))))))
def example7():
- return {
- a: a
- for a in [
- 1,
- 2,
- 3,
- 4,
- 5,
- 6,
- 7,
- 8,
- 9,
- 10,
- 11,
- 12,
- 13,
- 14,
- 15,
- 16,
- 17,
- 18,
- 19,
- 20000000000000000000,
- ]
- }
+ return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]})))))))))
def example8():
- return None
+ return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
```
## Ruff Output
```py
x = 1
x = 1.2
data = ("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").encode()
x = (1)
x = (1.2)
data = (
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
).encode()
async def show_status():
while True:
try:
if report_host:
data = (f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx").encode()
data = (
f"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
).encode()
except Exception as e:
pass
def example():
return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example1():
return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example1point5():
return 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111
return ((((((1111111111111111111111111111111111111111111111111111111111111111111111111111111111111))))))
def example2():
return "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
return (("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"))
def example3():
return 1111111111111111111111111111111111111111111111111111111111111111111111111111111
return ((1111111111111111111111111111111111111111111111111111111111111111111111111111111))
def example4():
return True
return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((True))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example5():
return ()
return ((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((()))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
def example6():
return {a: a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]}
return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17]})))))))))
def example7():
return {
a: a
for a in [
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20000000000000000000,
]
}
return ((((((((({a:a for a in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20000000000000000000]})))))))))
def example8():
return None
return (((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((None)))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
```
## Black Output

View file

@ -101,131 +101,159 @@ def foo() -> tuple[int, int, int,]:
```diff
--- Black
+++ Ruff
@@ -1,52 +1,53 @@
@@ -1,120 +1,88 @@
# Control
def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
+ return 2*a
-
# Remove the brackets
def double(a: int) -> int:
-def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
-
+def double(a: int) -> (int):
+ return 2*a
# Some newline variations
def double(a: int) -> int:
-def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
+def double(a: int) -> (
+ int):
+ return 2*a
def double(a: int) -> int:
-
-def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
def double(a: int) -> int:
-
-
-def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
+def double(a: int) -> (int
+):
+ return 2*a
+def double(a: int) -> (
+ int
+):
+ return 2*a
# Don't lose the comments
def double(a: int) -> int: # Hello
-def double(a: int) -> int: # Hello
- return 2 * a
+ return 2
+ * a
-
+def double(a: int) -> ( # Hello
+ int
+):
+ return 2*a
-def double(a: int) -> int: # Hello
- return 2 * a
+def double(a: int) -> int:
+ return 2
+ * a
-
+def double(a: int) -> (
+ int # Hello
+):
+ return 2*a
# Really long annotations
-def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-):
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
def foo() -> (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
):
return 2
-
-def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-):
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
-
-def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
- | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-):
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
+| intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
-
-def foo(
- a: int,
- b: int,
- c: int,
-) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
+def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
@@ -62,10 +63,8 @@
a: int,
b: int,
c: int,
-
-def foo(
- a: int,
- b: int,
- c: int,
-) -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
- | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-):
+) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
+| intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
+def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
-
# Split args but no need to split return
-def foo(
- a: int,
- b: int,
- c: int,
-) -> int:
+def foo(a: int, b: int, c: int,) -> int:
return 2
@@ -81,16 +80,16 @@
-
# Deeply nested brackets
# with *interesting* spacing
def double(a: int) -> int:
-def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
def double(a: int) -> int:
-
-
-def double(a: int) -> int:
- return 2 * a
+ return 2
+ * a
+def double(a: int) -> (((((int))))):
+ return 2*a
+def double(a: int) -> (
+ ( (
+ ((int)
+ )
+ )
+ )
+ ):
+ return 2*a
-def foo() -> (
- intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
def foo() -> (
+ ( (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
-):
+def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
+)
+)):
return 2
@@ -99,22 +98,18 @@
return 2
-def foo() -> (
-
# Return type with commas
-def foo() -> tuple[int, int, int]:
- return 2
-
-
def foo() -> (
- tuple[
- loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
- loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
- loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
- ]
-):
+def foo() -> tuple[
+ loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
+ loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
+ loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
+]:
+ tuple[int, int, int]
):
return 2
+def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]:
+ return 2
# Magic trailing comma example
-def foo() -> (
@ -235,11 +263,7 @@ def foo() -> tuple[int, int, int,]:
- int,
- ]
-):
+def foo() -> tuple[
+ int,
+ int,
+ int,
+]:
+def foo() -> tuple[int, int, int,]:
return 2
```
@ -248,118 +272,91 @@ def foo() -> tuple[int, int, int,]:
```py
# Control
def double(a: int) -> int:
return 2
* a
return 2*a
# Remove the brackets
def double(a: int) -> int:
return 2
* a
def double(a: int) -> (int):
return 2*a
# Some newline variations
def double(a: int) -> int:
return 2
* a
def double(a: int) -> (
int):
return 2*a
def double(a: int) -> (int
):
return 2*a
def double(a: int) -> int:
return 2
* a
def double(a: int) -> int:
return 2
* a
def double(a: int) -> (
int
):
return 2*a
# Don't lose the comments
def double(a: int) -> int: # Hello
return 2
* a
def double(a: int) -> int:
return 2
* a
def double(a: int) -> ( # Hello
int
):
return 2*a
def double(a: int) -> (
int # Hello
):
return 2*a
# Really long annotations
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
def foo() -> (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
):
return 2
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
| intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
def foo(
a: int,
b: int,
c: int,
) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
def foo(
a: int,
b: int,
c: int,
) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
| intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
def foo(a: int, b: int, c: int,) -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds | intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
# Split args but no need to split return
def foo(
a: int,
b: int,
c: int,
) -> int:
def foo(a: int, b: int, c: int,) -> int:
return 2
# Deeply nested brackets
# with *interesting* spacing
def double(a: int) -> int:
def double(a: int) -> (((((int))))):
return 2*a
def double(a: int) -> (
( (
((int)
)
)
)
):
return 2*a
def foo() -> (
( (
intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds
)
)):
return 2
* a
def double(a: int) -> int:
return 2
* a
def foo() -> intsdfsafafafdfdsasdfsfsdfasdfafdsafdfdsfasdskdsdsfdsafdsafsdfdasfffsfdsfdsafafhdskfhdsfjdslkfdlfsdkjhsdfjkdshfkljds:
return 2
# Return type with commas
def foo() -> tuple[int, int, int]:
def foo() -> (
tuple[int, int, int]
):
return 2
def foo() -> tuple[
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong,
]:
def foo() -> tuple[loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong, loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong]:
return 2
# Magic trailing comma example
def foo() -> tuple[
int,
int,
int,
]:
def foo() -> tuple[int, int, int,]:
return 2
```

View file

@ -60,38 +60,24 @@ func(
```diff
--- Black
+++ Ruff
@@ -3,23 +3,61 @@
@@ -3,23 +3,45 @@
b = tuple[int,]
# But commas in multiple element subscripts should be removed.
-c: tuple[int, int]
-d = tuple[int, int]
+c: tuple[
+ int,
+ int,
+]
+d = tuple[
+ int,
+ int,
+]
+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,]}
+small_list = [
+ 1,
+]
+list_of_types = [
+ tuple[int,],
+]
+small_set = {
+ 1,
+}
+set_of_types = {
+ tuple[int,],
+}
+small_list = [1,]
+list_of_types = [tuple[int,],]
+small_set = {1,}
+set_of_types = {tuple[int,],}
# Except single element tuples
small_tuple = (1,)
@ -107,11 +93,7 @@ func(
+)
-func1(arg1).func2(arg2).func3(arg3).func4(arg4).func5(arg5)
+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)
+(
@ -119,7 +101,9 @@ func(
+ b,
+ c,
+ d,
+) = func1(arg1) and func2(arg2)
+) = func1(
+ arg1
+) and func2(arg2)
-func(argument1, (one, two), argument4, argument5, argument6)
+func(
@ -142,28 +126,14 @@ a: tuple[int,]
b = tuple[int,]
# But commas in multiple element subscripts should be removed.
c: tuple[
int,
int,
]
d = tuple[
int,
int,
]
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,],
}
small_list = [1,]
list_of_types = [tuple[int,],]
small_set = {1,}
set_of_types = {tuple[int,],}
# Except single element tuples
small_tuple = (1,)
@ -177,18 +147,16 @@ zero(
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)
) = func1(
arg1
) and func2(arg2)
func(
argument1,

View file

@ -0,0 +1,223 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/slices.py
---
## Input
```py
slice[a.b : c.d]
slice[d :: d + 1]
slice[d + 1 :: d]
slice[d::d]
slice[0]
slice[-1]
slice[:-1]
slice[::-1]
slice[:c, c - 1]
slice[c, c + 1, d::]
slice[ham[c::d] :: 1]
slice[ham[cheese**2 : -1] : 1 : 1, ham[1:2]]
slice[:-1:]
slice[lambda: None : lambda: None]
slice[lambda x, y, *args, really=2, **kwargs: None :, None::]
slice[1 or 2 : True and False]
slice[not so_simple : 1 < val <= 10]
slice[(1 for i in range(42)) : x]
slice[:: [i for i in range(42)]]
async def f():
slice[await x : [i async for i in arange(42)] : 42]
# These are from PEP-8:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
slice[::, ::]
slice[
# A
:
# B
:
# C
]
slice[
# A
1:
# B
2:
# C
3
]
slice[
# A
1
+ 2 :
# B
3 :
# C
4
]
x[
1: # A
2: # B
3 # C
]
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -56,4 +56,8 @@
# C
4
]
-x[1:2:3] # A # B # C
+x[
+ 1: # A
+ 2: # B
+ 3 # C
+]
```
## Ruff Output
```py
slice[a.b : c.d]
slice[d :: d + 1]
slice[d + 1 :: d]
slice[d::d]
slice[0]
slice[-1]
slice[:-1]
slice[::-1]
slice[:c, c - 1]
slice[c, c + 1, d::]
slice[ham[c::d] :: 1]
slice[ham[cheese**2 : -1] : 1 : 1, ham[1:2]]
slice[:-1:]
slice[lambda: None : lambda: None]
slice[lambda x, y, *args, really=2, **kwargs: None :, None::]
slice[1 or 2 : True and False]
slice[not so_simple : 1 < val <= 10]
slice[(1 for i in range(42)) : x]
slice[:: [i for i in range(42)]]
async def f():
slice[await x : [i async for i in arange(42)] : 42]
# These are from PEP-8:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
slice[::, ::]
slice[
# A
:
# B
:
# C
]
slice[
# A
1:
# B
2:
# C
3
]
slice[
# A
1
+ 2 :
# B
3 :
# C
4
]
x[
1: # A
2: # B
3 # C
]
```
## Black Output
```py
slice[a.b : c.d]
slice[d :: d + 1]
slice[d + 1 :: d]
slice[d::d]
slice[0]
slice[-1]
slice[:-1]
slice[::-1]
slice[:c, c - 1]
slice[c, c + 1, d::]
slice[ham[c::d] :: 1]
slice[ham[cheese**2 : -1] : 1 : 1, ham[1:2]]
slice[:-1:]
slice[lambda: None : lambda: None]
slice[lambda x, y, *args, really=2, **kwargs: None :, None::]
slice[1 or 2 : True and False]
slice[not so_simple : 1 < val <= 10]
slice[(1 for i in range(42)) : x]
slice[:: [i for i in range(42)]]
async def f():
slice[await x : [i async for i in arange(42)] : 42]
# These are from PEP-8:
ham[1:9], ham[1:9:3], ham[:9:3], ham[1::3], ham[1:9:]
ham[lower:upper], ham[lower:upper:], ham[lower::step]
# ham[lower+offset : upper+offset]
ham[: upper_fn(x) : step_fn(x)], ham[:: step_fn(x)]
ham[lower + offset : upper + offset]
slice[::, ::]
slice[
# A
:
# B
:
# C
]
slice[
# A
1:
# B
2:
# C
3
]
slice[
# A
1
+ 2 :
# B
3 :
# C
4
]
x[1:2:3] # A # B # C
```

View file

@ -33,21 +33,25 @@ def docstring_multiline():
```diff
--- Black
+++ Ruff
@@ -1,12 +1,12 @@
@@ -1,13 +1,13 @@
#!/usr/bin/env python3
name = "Łukasz"
-(f"hello {name}", f"hello {name}")
-(b"", b"")
-("", "")
+(f"hello {name}", F"hello {name}")
(b"", b"")
("", "")
+(b"", B"")
+(u"", U"")
(r"", R"")
-(rf"", rf"", Rf"", Rf"", rf"", rf"", Rf"", Rf"")
-(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"")
+(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"")
(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"")
+(rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"")
def docstring_singleline():
```
## Ruff Output
@ -57,12 +61,12 @@ def docstring_multiline():
name = "Łukasz"
(f"hello {name}", F"hello {name}")
(b"", b"")
("", "")
(b"", B"")
(u"", U"")
(r"", R"")
(rf"", fr"", Rf"", fR"", rF"", Fr"", RF"", FR"")
(rb"", rb"", Rb"", Rb"", rb"", rb"", Rb"", Rb"")
(rb"", br"", Rb"", bR"", rB"", Br"", RB"", BR"")
def docstring_singleline():

View file

@ -42,17 +42,17 @@ assert (
```diff
--- Black
+++ Ruff
@@ -1,21 +1,23 @@
importA
(
()
@@ -1,58 +1,29 @@
-importA
-(
- ()
- << 0
- ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525
+ << 0**101234234242352525425252352352525234890264906820496920680926538059059209922523523525
) #
-) #
+importA;() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 #
-assert sort_by_dependency(
- {
assert sort_by_dependency(
{
- "1": {"2", "3"},
- "2": {"2a", "2b"},
- "3": {"3a", "3b"},
@ -60,54 +60,50 @@ assert (
- "2b": set(),
- "3a": set(),
- "3b": set(),
- }
-) == ["2a", "2b", "2", "3a", "3b", "3", "1"]
+assert (
+ sort_by_dependency(
+ {
+ "1": {"2", "3"},
+ "2": {"2a", "2b"},
+ "3": {"3a", "3b"},
+ "2a": set(),
+ "2b": set(),
+ "3a": set(),
+ "3b": set(),
+ }
+ )
+ == ["2a", "2b", "2", "3a", "3b", "3", "1"]
+)
+ "1": {"2", "3"}, "2": {"2a", "2b"}, "3": {"3a", "3b"},
+ "2a": set(), "2b": set(), "3a": set(), "3b": set()
}
) == ["2a", "2b", "2", "3a", "3b", "3", "1"]
importA
0
@@ -25,13 +27,12 @@
-0
-0 ^ 0 #
-
+0;0^0#
class A:
def foo(self):
for _ in range(10):
- aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc(
- xxxxxxxxxxxx
+ aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( # pylint: disable=no-member
xxxxxxxxxxxx
- ) # pylint: disable=no-member
+ aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc(xxxxxxxxxxxx) # pylint: disable=no-member
-
+ )
def test(self, othr):
- return 1 == 2 and (
+ return 1 == 2
+ and (
name,
description,
self.default,
@@ -40,7 +41,8 @@
self.parameters,
self.meta_data,
self.schedule,
- name,
- description,
- self.default,
- self.selected,
- self.auto_generated,
- self.parameters,
- self.meta_data,
- self.schedule,
- ) == (
+ )
+ == (
name,
description,
othr.default,
@@ -52,7 +54,13 @@
)
- name,
- description,
- othr.default,
- othr.selected,
- othr.auto_generated,
- othr.parameters,
- othr.meta_data,
- othr.schedule,
- )
+ return (1 == 2 and
+ (name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) ==
+ (name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule))
-assert a_function(
@ -115,85 +111,42 @@ assert (
- which_is_eighty_eight_in_this_case_plus_a_bit_more,
-) == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"}
+assert (
+ a_function(
+ very_long_arguments_that_surpass_the_limit,
+ which_is_eighty_eight_in_this_case_plus_a_bit_more,
+ )
+ == {
+ "x": "this need to pass the line limit as well",
+ "b": "but only by a little bit",
+ }
+ a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more)
+ == {"x": "this need to pass the line limit as well", "b": "but only by a little bit"}
+)
```
## Ruff Output
```py
importA
(
()
<< 0**101234234242352525425252352352525234890264906820496920680926538059059209922523523525
) #
importA;() << 0 ** 101234234242352525425252352352525234890264906820496920680926538059059209922523523525 #
assert (
sort_by_dependency(
{
"1": {"2", "3"},
"2": {"2a", "2b"},
"3": {"3a", "3b"},
"2a": set(),
"2b": set(),
"3a": set(),
"3b": set(),
}
)
== ["2a", "2b", "2", "3a", "3b", "3", "1"]
)
assert sort_by_dependency(
{
"1": {"2", "3"}, "2": {"2a", "2b"}, "3": {"3a", "3b"},
"2a": set(), "2b": set(), "3a": set(), "3b": set()
}
) == ["2a", "2b", "2", "3a", "3b", "3", "1"]
importA
0
0 ^ 0 #
0;0^0#
class A:
def foo(self):
for _ in range(10):
aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc(xxxxxxxxxxxx) # pylint: disable=no-member
aaaaaaaaaaaaaaaaaaa = bbbbbbbbbbbbbbb.cccccccccc( # pylint: disable=no-member
xxxxxxxxxxxx
)
def test(self, othr):
return 1 == 2
and (
name,
description,
self.default,
self.selected,
self.auto_generated,
self.parameters,
self.meta_data,
self.schedule,
)
== (
name,
description,
othr.default,
othr.selected,
othr.auto_generated,
othr.parameters,
othr.meta_data,
othr.schedule,
)
return (1 == 2 and
(name, description, self.default, self.selected, self.auto_generated, self.parameters, self.meta_data, self.schedule) ==
(name, description, othr.default, othr.selected, othr.auto_generated, othr.parameters, othr.meta_data, othr.schedule))
assert (
a_function(
very_long_arguments_that_surpass_the_limit,
which_is_eighty_eight_in_this_case_plus_a_bit_more,
)
== {
"x": "this need to pass the line limit as well",
"b": "but only by a little bit",
}
a_function(very_long_arguments_that_surpass_the_limit, which_is_eighty_eight_in_this_case_plus_a_bit_more)
== {"x": "this need to pass the line limit as well", "b": "but only by a little bit"}
)
```

View file

@ -38,64 +38,53 @@ class A:
```diff
--- Black
+++ Ruff
@@ -1,7 +1,6 @@
@@ -1,19 +1,11 @@
-if e1234123412341234.winerror not in (
- _winapi.ERROR_SEM_TIMEOUT,
- _winapi.ERROR_PIPE_BUSY,
-) or _check_timeout(t):
+if e1234123412341234.winerror
+not in (_winapi.ERROR_SEM_TIMEOUT, _winapi.ERROR_PIPE_BUSY)
+or _check_timeout(t):
+if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT,
+ _winapi.ERROR_PIPE_BUSY) or _check_timeout(t):
pass
if x:
@@ -21,14 +20,20 @@
if y:
- new_id = (
- max(
- Vegetable.objects.order_by("-id")[0].id,
- Mineral.objects.order_by("-id")[0].id,
- )
- + 1
- )
-
+ new_id = max(Vegetable.objects.order_by('-id')[0].id,
+ Mineral.objects.order_by('-id')[0].id) + 1
class X:
def get_help_text(self):
@@ -21,8 +13,7 @@
"Your password must contain at least %(min_length)d character.",
"Your password must contain at least %(min_length)d characters.",
self.min_length,
- ) % {"min_length": self.min_length}
+ )
+ % {"min_length": self.min_length}
-
+ ) % {'min_length': self.min_length}
class A:
def b(self):
- if self.connection.mysql_is_mariadb and (
- 10,
- 4,
- 3,
- ) < self.connection.mysql_version < (10, 5, 2):
+ if (
+ self.connection.mysql_is_mariadb
+ and (
+ 10,
+ 4,
+ 3,
+ )
+ < self.connection.mysql_version
+ < (10, 5, 2)
+ ):
pass
```
## Ruff Output
```py
if e1234123412341234.winerror
not in (_winapi.ERROR_SEM_TIMEOUT, _winapi.ERROR_PIPE_BUSY)
or _check_timeout(t):
if e1234123412341234.winerror not in (_winapi.ERROR_SEM_TIMEOUT,
_winapi.ERROR_PIPE_BUSY) or _check_timeout(t):
pass
if x:
if y:
new_id = (
max(
Vegetable.objects.order_by("-id")[0].id,
Mineral.objects.order_by("-id")[0].id,
)
+ 1
)
new_id = max(Vegetable.objects.order_by('-id')[0].id,
Mineral.objects.order_by('-id')[0].id) + 1
class X:
def get_help_text(self):
@ -103,22 +92,15 @@ class X:
"Your password must contain at least %(min_length)d character.",
"Your password must contain at least %(min_length)d characters.",
self.min_length,
)
% {"min_length": self.min_length}
) % {'min_length': self.min_length}
class A:
def b(self):
if (
self.connection.mysql_is_mariadb
and (
10,
4,
3,
)
< self.connection.mysql_version
< (10, 5, 2)
):
if self.connection.mysql_is_mariadb and (
10,
4,
3,
) < self.connection.mysql_version < (10, 5, 2):
pass
```

View file

@ -16,26 +16,22 @@ if (e123456.get_tk_patchlevel() >= (8, 6, 0, 'final') or
```diff
--- Black
+++ Ruff
@@ -1,6 +1,5 @@
@@ -1,6 +1,3 @@
-if e123456.get_tk_patchlevel() >= (8, 6, 0, "final") or (
- 8,
- 5,
- 8,
-) <= get_tk_patchlevel() < (8, 6):
+if (
+ e123456.get_tk_patchlevel() >= (8, 6, 0, "final")
+ or (8, 5, 8) <= get_tk_patchlevel() < (8, 6)
+):
+if (e123456.get_tk_patchlevel() >= (8, 6, 0, 'final') or
+ (8, 5, 8) <= get_tk_patchlevel() < (8, 6)):
pass
```
## Ruff Output
```py
if (
e123456.get_tk_patchlevel() >= (8, 6, 0, "final")
or (8, 5, 8) <= get_tk_patchlevel() < (8, 6)
):
if (e123456.get_tk_patchlevel() >= (8, 6, 0, 'final') or
(8, 5, 8) <= get_tk_patchlevel() < (8, 6)):
pass
```

View file

@ -1,60 +0,0 @@
---
source: crates/ruff_python_formatter/src/lib.rs
expression: snapshot
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/simple_cases/trailing_comma_optional_parens3.py
---
## Input
```py
if True:
if True:
if True:
return _(
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweas "
+ "qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwegqweasdzxcqweasdzxc.",
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwe",
) % {"reported_username": reported_username, "report_reason": report_reason}
```
## Black Differences
```diff
--- Black
+++ Ruff
@@ -5,4 +5,5 @@
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweas "
+ "qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwegqweasdzxcqweasdzxc.",
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwe",
- ) % {"reported_username": reported_username, "report_reason": report_reason}
+ )
+ % {"reported_username": reported_username, "report_reason": report_reason}
```
## Ruff Output
```py
if True:
if True:
if True:
return _(
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweas "
+ "qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwegqweasdzxcqweasdzxc.",
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwe",
)
% {"reported_username": reported_username, "report_reason": report_reason}
```
## Black Output
```py
if True:
if True:
if True:
return _(
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweas "
+ "qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwegqweasdzxcqweasdzxc.",
"qweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqweasdzxcqwe",
) % {"reported_username": reported_username, "report_reason": report_reason}
```

View file

@ -46,55 +46,51 @@ assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
```diff
--- Black
+++ Ruff
@@ -20,9 +20,7 @@
b,
c,
d,
@@ -1,28 +1,11 @@
-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)
# Inner one-element tuple shouldn't explode
func1(arg1).func2(arg1, (one_tuple,)).func3(arg3)
-(
- a,
- b,
- c,
- d,
-) = func1(
- arg1
-) and func2(arg2)
+) = func1(arg1) and func2(arg2)
+(a, b, c, d,) = func1(arg1) and func2(arg2)
# Example from https://github.com/psf/black/issues/3229
@@ -43,8 +41,6 @@
)
# Regression test for https://github.com/psf/black/issues/3414.
-assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
- xxxxxxxxx
-).xxxxxxxxxxxxxxxxxx(), (
+assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(xxxxxxxxx).xxxxxxxxxxxxxxxxxx(), (
"xxx {xxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
```
## Ruff Output
```py
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)
# Inner one-element tuple shouldn't explode
func1(arg1).func2(arg1, (one_tuple,)).func3(arg3)
(
a,
b,
c,
d,
) = func1(arg1) and func2(arg2)
(a, b, c, d,) = func1(arg1) and func2(arg2)
# Example from https://github.com/psf/black/issues/3229
@ -115,7 +111,9 @@ assert (
)
# Regression test for https://github.com/psf/black/issues/3414.
assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(xxxxxxxxx).xxxxxxxxxxxxxxxxxx(), (
assert xxxxxxxxx.xxxxxxxxx.xxxxxxxxx(
xxxxxxxxx
).xxxxxxxxxxxxxxxxxx(), (
"xxx {xxxxxxxxx} xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
)
```

View file

@ -20,30 +20,31 @@ this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890")
```diff
--- Black
+++ Ruff
@@ -4,7 +4,7 @@
sdfjsdfjlksdljkfsdlkf,
sdfsdjfklsdfjlksdljkf,
sdsfsdfjskdflsfsdf,
@@ -1,12 +1,7 @@
# This is a standalone comment.
-(
- sdfjklsdfsjldkflkjsf,
- sdfjsdfjlksdljkfsdlkf,
- sdfsdjfklsdfjlksdljkf,
- sdsfsdfjskdflsfsdf,
-) = (1, 2, 3)
+) = 1, 2, 3
+sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3
# This is as well.
(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890")
-(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890")
+this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890")
(a,) = call()
```
## Ruff Output
```py
# This is a standalone comment.
(
sdfjklsdfsjldkflkjsf,
sdfjsdfjlksdljkfsdlkf,
sdfsdjfklsdfjlksdljkf,
sdsfsdfjskdflsfsdf,
) = 1, 2, 3
sdfjklsdfsjldkflkjsf, sdfjsdfjlksdljkfsdlkf, sdfsdjfklsdfjlksdljkf, sdsfsdfjskdflsfsdf = 1, 2, 3
# This is as well.
(this_will_be_wrapped_in_parens,) = struct.unpack(b"12345678901234567890")
this_will_be_wrapped_in_parens, = struct.unpack(b"12345678901234567890")
(a,) = call()
```

File diff suppressed because it is too large Load diff