Ruff 2024.2 style (#9639)

This commit is contained in:
Micha Reiser 2024-02-29 09:30:54 +01:00 committed by GitHub
parent 0293908b71
commit a6f32ddc5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
47 changed files with 835 additions and 2362 deletions

View file

@ -8,7 +8,6 @@ use ruff_python_trivia::{SimpleToken, SimpleTokenKind, SimpleTokenizer};
use ruff_text_size::{Ranged, TextRange, TextSize};
use crate::comments::{leading_alternate_branch_comments, trailing_comments, SourceComment};
use crate::preview::is_dummy_implementations_enabled;
use crate::statement::suite::{contains_only_an_ellipsis, SuiteKind};
use crate::verbatim::write_suppressed_clause_header;
use crate::{has_skip_comment, prelude::*};
@ -405,8 +404,7 @@ impl Format<PyFormatContext<'_>> for FormatClauseBody<'_> {
// In stable, stubs are only collapsed in stub files, in preview stubs in functions
// or classes are collapsed too
let should_collapse_stub = f.options().source_type().is_stub()
|| (is_dummy_implementations_enabled(f.context())
&& matches!(self.kind, SuiteKind::Function | SuiteKind::Class));
|| matches!(self.kind, SuiteKind::Function | SuiteKind::Class);
if should_collapse_stub
&& contains_only_an_ellipsis(self.body, f.context().comments())

View file

@ -2,12 +2,8 @@ use ruff_formatter::write;
use ruff_python_ast::StmtAnnAssign;
use crate::comments::SourceComment;
use crate::expression::is_splittable_expression;
use crate::expression::parentheses::Parentheses;
use crate::expression::{has_parentheses, is_splittable_expression};
use crate::preview::{
is_parenthesize_long_type_hints_enabled,
is_prefer_splitting_right_hand_side_of_assignments_enabled,
};
use crate::statement::stmt_assign::{
AnyAssignmentOperator, AnyBeforeOperator, FormatStatementsLastExpression,
};
@ -30,13 +26,7 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
write!(f, [target.format(), token(":"), space()])?;
if let Some(value) = value {
if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context())
// The `has_parentheses` check can be removed when stabilizing `is_parenthesize_long_type_hints`.
// because `is_splittable_expression` covers both.
&& (has_parentheses(annotation, f.context()).is_some()
|| (is_parenthesize_long_type_hints_enabled(f.context())
&& is_splittable_expression(annotation, f.context())))
{
if is_splittable_expression(annotation, f.context()) {
FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::Expression(annotation),
operator: AnyAssignmentOperator::Assign,
@ -47,23 +37,20 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
} else {
// Remove unnecessary parentheses around the annotation if the parenthesize long type hints preview style is enabled.
// Ensure we keep the parentheses if the annotation has any comments.
if is_parenthesize_long_type_hints_enabled(f.context()) {
if f.context().comments().has_leading(annotation.as_ref())
|| f.context().comments().has_trailing(annotation.as_ref())
{
annotation
.format()
.with_options(Parentheses::Always)
.fmt(f)?;
} else {
annotation
.format()
.with_options(Parentheses::Never)
.fmt(f)?;
}
if f.context().comments().has_leading(annotation.as_ref())
|| f.context().comments().has_trailing(annotation.as_ref())
{
annotation
.format()
.with_options(Parentheses::Always)
.fmt(f)?;
} else {
annotation.format().fmt(f)?;
annotation
.format()
.with_options(Parentheses::Never)
.fmt(f)?;
}
write!(
f,
[
@ -83,11 +70,7 @@ impl FormatNodeRule<StmtAnnAssign> for FormatStmtAnnAssign {
// Decimal # the user's age, used to determine if it's safe for them to use ruff
// )
// ```
if is_parenthesize_long_type_hints_enabled(f.context()) {
FormatStatementsLastExpression::left_to_right(annotation, item).fmt(f)?;
} else {
annotation.format().fmt(f)?;
}
FormatStatementsLastExpression::left_to_right(annotation, item).fmt(f)?;
}
if f.options().source_type().is_ipynb()

View file

@ -16,10 +16,6 @@ use crate::expression::{
can_omit_optional_parentheses, has_own_parentheses, has_parentheses,
maybe_parenthesize_expression,
};
use crate::preview::{
is_parenthesize_long_type_hints_enabled,
is_prefer_splitting_right_hand_side_of_assignments_enabled,
};
use crate::statement::trailing_semicolon;
use crate::{has_skip_comment, prelude::*};
@ -44,53 +40,47 @@ impl FormatNodeRule<StmtAssign> for FormatStmtAssign {
preserve_parentheses: true,
};
if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context()) {
// Avoid parenthesizing the value if the last target before the assigned value expands.
if let Some((last, head)) = rest.split_last() {
format_first.fmt(f)?;
// Avoid parenthesizing the value if the last target before the assigned value expands.
if let Some((last, head)) = rest.split_last() {
format_first.fmt(f)?;
for target in head {
FormatTargetWithEqualOperator {
target,
preserve_parentheses: false,
}
.fmt(f)?;
}
FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::Expression(last),
operator: AnyAssignmentOperator::Assign,
value,
statement: item.into(),
for target in head {
FormatTargetWithEqualOperator {
target,
preserve_parentheses: false,
}
.fmt(f)?;
}
// Avoid parenthesizing the value for single-target assignments where the
// target has its own parentheses (list, dict, tuple, ...) and the target expands.
else if has_target_own_parentheses(first, f.context())
&& !is_expression_parenthesized(
first.into(),
f.context().comments().ranges(),
f.context().source(),
)
{
FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::Expression(first),
operator: AnyAssignmentOperator::Assign,
value,
statement: item.into(),
}
.fmt(f)?;
}
// For single targets that have no split points, parenthesize the value only
// if it makes it fit. Otherwise omit the parentheses.
else {
format_first.fmt(f)?;
FormatStatementsLastExpression::left_to_right(value, item).fmt(f)?;
}
} else {
write!(f, [format_first, FormatTargets { targets: rest }])?;
FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::Expression(last),
operator: AnyAssignmentOperator::Assign,
value,
statement: item.into(),
}
.fmt(f)?;
}
// Avoid parenthesizing the value for single-target assignments where the
// target has its own parentheses (list, dict, tuple, ...) and the target expands.
else if has_target_own_parentheses(first, f.context())
&& !is_expression_parenthesized(
first.into(),
f.context().comments().ranges(),
f.context().source(),
)
{
FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::Expression(first),
operator: AnyAssignmentOperator::Assign,
value,
statement: item.into(),
}
.fmt(f)?;
}
// For single targets that have no split points, parenthesize the value only
// if it makes it fit. Otherwise omit the parentheses.
else {
format_first.fmt(f)?;
FormatStatementsLastExpression::left_to_right(value, item).fmt(f)?;
}
@ -114,77 +104,6 @@ impl FormatNodeRule<StmtAssign> for FormatStmtAssign {
}
}
/// Formats the targets so that they split left-to right.
#[derive(Debug)]
struct FormatTargets<'a> {
targets: &'a [Expr],
}
impl Format<PyFormatContext<'_>> for FormatTargets<'_> {
fn fmt(&self, f: &mut PyFormatter) -> FormatResult<()> {
if let Some((first, rest)) = self.targets.split_first() {
let comments = f.context().comments();
let parenthesize = if comments.has_leading(first) || comments.has_trailing(first) {
ParenthesizeTarget::Always
} else if has_target_own_parentheses(first, f.context()) {
ParenthesizeTarget::Never
} else {
ParenthesizeTarget::IfBreaks
};
let group_id = if parenthesize == ParenthesizeTarget::Never {
Some(f.group_id("assignment_parentheses"))
} else {
None
};
let format_first = format_with(|f: &mut PyFormatter| {
let mut f = WithNodeLevel::new(NodeLevel::Expression(group_id), f);
match parenthesize {
ParenthesizeTarget::Always => {
write!(f, [first.format().with_options(Parentheses::Always)])
}
ParenthesizeTarget::Never => {
write!(f, [first.format().with_options(Parentheses::Never)])
}
ParenthesizeTarget::IfBreaks => {
write!(
f,
[
if_group_breaks(&token("(")),
soft_block_indent(&first.format().with_options(Parentheses::Never)),
if_group_breaks(&token(")"))
]
)
}
}
});
write!(
f,
[group(&format_args![
format_first,
space(),
token("="),
space(),
FormatTargets { targets: rest }
])
.with_group_id(group_id)]
)
} else {
Ok(())
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParenthesizeTarget {
Always,
Never,
IfBreaks,
}
/// Formats a single target with the equal operator.
struct FormatTargetWithEqualOperator<'a> {
target: &'a Expr,
@ -693,9 +612,7 @@ impl Format<PyFormatContext<'_>> for AnyBeforeOperator<'_> {
}
// Never parenthesize targets that come with their own parentheses, e.g. don't parenthesize lists or dictionary literals.
else if should_parenthesize_target(expression, f.context()) {
if is_parenthesize_long_type_hints_enabled(f.context())
&& can_omit_optional_parentheses(expression, f.context())
{
if can_omit_optional_parentheses(expression, f.context()) {
optional_parentheses(&expression.format().with_options(Parentheses::Never))
.fmt(f)
} else {

View file

@ -3,7 +3,6 @@ use ruff_python_ast::StmtAugAssign;
use crate::comments::SourceComment;
use crate::expression::parentheses::is_expression_parenthesized;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::{
has_target_own_parentheses, AnyAssignmentOperator, AnyBeforeOperator,
FormatStatementsLastExpression,
@ -24,8 +23,7 @@ impl FormatNodeRule<StmtAugAssign> for FormatStmtAugAssign {
range: _,
} = item;
if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context())
&& has_target_own_parentheses(target, f.context())
if has_target_own_parentheses(target, f.context())
&& !is_expression_parenthesized(
target.into(),
f.context().comments().ranges(),

View file

@ -2,7 +2,6 @@ use ruff_formatter::write;
use ruff_python_ast::StmtTypeAlias;
use crate::comments::SourceComment;
use crate::preview::is_prefer_splitting_right_hand_side_of_assignments_enabled;
use crate::statement::stmt_assign::{
AnyAssignmentOperator, AnyBeforeOperator, FormatStatementsLastExpression,
};
@ -23,17 +22,13 @@ impl FormatNodeRule<StmtTypeAlias> for FormatStmtTypeAlias {
write!(f, [token("type"), space(), name.as_ref().format()])?;
if let Some(type_params) = type_params {
if is_prefer_splitting_right_hand_side_of_assignments_enabled(f.context()) {
return FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::TypeParams(type_params),
operator: AnyAssignmentOperator::Assign,
value,
statement: item.into(),
}
.fmt(f);
};
write!(f, [type_params.format()])?;
return FormatStatementsLastExpression::RightToLeft {
before_operator: AnyBeforeOperator::TypeParams(type_params),
operator: AnyAssignmentOperator::Assign,
value,
statement: item.into(),
}
.fmt(f);
}
write!(

View file

@ -12,7 +12,6 @@ use crate::expression::parentheses::{
};
use crate::other::commas;
use crate::prelude::*;
use crate::preview::is_wrap_multiple_context_managers_in_parens_enabled;
use crate::statement::clause::{clause_body, clause_header, ClauseHeader};
use crate::{PyFormatOptions, PythonVersion};
@ -152,8 +151,7 @@ fn should_parenthesize(
return Ok(ParenthesizeWith::IfExpands);
}
let can_parenthesize = (is_wrap_multiple_context_managers_in_parens_enabled(context)
&& options.target_version() >= PythonVersion::Py39)
let can_parenthesize = options.target_version() >= PythonVersion::Py39
|| are_with_items_parenthesized(with, context)?;
if !can_parenthesize {
@ -176,9 +174,7 @@ fn should_parenthesize(
// Preserve the parentheses around the context expression instead of parenthesizing the entire
// with items.
ParenthesizeWith::UnlessCommented
} else if is_wrap_multiple_context_managers_in_parens_enabled(context)
&& can_omit_optional_parentheses(&single.context_expr, context)
{
} else if can_omit_optional_parentheses(&single.context_expr, context) {
ParenthesizeWith::Optional
} else {
ParenthesizeWith::IfExpands

View file

@ -13,11 +13,6 @@ use crate::comments::{
use crate::context::{NodeLevel, TopLevelStatementPosition, WithIndentLevel, WithNodeLevel};
use crate::expression::expr_string_literal::ExprStringLiteralKind;
use crate::prelude::*;
use crate::preview::{
is_blank_line_after_nested_stub_class_enabled, is_dummy_implementations_enabled,
is_format_module_docstring_enabled, is_module_docstring_newlines_enabled,
is_no_blank_line_before_class_docstring_enabled,
};
use crate::statement::stmt_expr::FormatStmtExpr;
use crate::verbatim::{
suppressed_node, write_suppressed_statements_starting_with_leading_comment,
@ -102,7 +97,7 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
SuiteChildStatement::Other(first)
}
SuiteKind::Function => {
SuiteKind::Function | SuiteKind::Class | SuiteKind::TopLevel => {
if let Some(docstring) =
DocstringStmt::try_from_statement(first, self.kind, source_type)
{
@ -111,53 +106,6 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
SuiteChildStatement::Other(first)
}
}
SuiteKind::Class => {
if let Some(docstring) =
DocstringStmt::try_from_statement(first, self.kind, source_type)
{
if !comments.has_leading(first)
&& lines_before(first.start(), source) > 1
&& !source_type.is_stub()
&& !is_no_blank_line_before_class_docstring_enabled(f.context())
{
// Allow up to one empty line before a class docstring, e.g., this is
// stable formatting:
//
// ```python
// class Test:
//
// """Docstring"""
// ```
//
// But, in preview mode, we don't want to allow any empty lines before a
// class docstring, e.g., this is preview formatting:
//
// ```python
// class Test:
// """Docstring"""
// ```
empty_line().fmt(f)?;
}
SuiteChildStatement::Docstring(docstring)
} else {
SuiteChildStatement::Other(first)
}
}
SuiteKind::TopLevel => {
if is_format_module_docstring_enabled(f.context()) {
if let Some(docstring) =
DocstringStmt::try_from_statement(first, self.kind, source_type)
{
SuiteChildStatement::Docstring(docstring)
} else {
SuiteChildStatement::Other(first)
}
} else {
SuiteChildStatement::Other(first)
}
}
};
let first_comments = comments.leading_dangling_trailing(first);
@ -188,16 +136,12 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
&& self.kind == SuiteKind::Class
{
true
} else if is_module_docstring_newlines_enabled(f.context())
&& self.kind == SuiteKind::TopLevel
&& DocstringStmt::try_from_statement(first.statement(), self.kind, source_type)
.is_some()
{
// Only in preview mode, insert a newline after a module level docstring, but treat
// it as a docstring otherwise. See: https://github.com/psf/black/pull/3932.
true
} else {
false
// Insert a newline after a module level docstring, but treat
// it as a docstring otherwise. See: https://github.com/psf/black/pull/3932.
self.kind == SuiteKind::TopLevel
&& DocstringStmt::try_from_statement(first.statement(), self.kind, source_type)
.is_some()
};
(first.statement(), empty_line_after_docstring)
@ -284,20 +228,19 @@ impl FormatRule<Suite, PyFormatContext<'_>> for FormatSuite {
} else {
// Preserve empty lines after a stub implementation but don't insert a new one if there isn't any present in the source.
// This is useful when having multiple function overloads that should be grouped to getter by omitting new lines between them.
let is_preceding_stub_function_without_empty_line =
is_dummy_implementations_enabled(f.context())
&& following.is_function_def_stmt()
&& preceding
.as_function_def_stmt()
.is_some_and(|preceding_stub| {
contains_only_an_ellipsis(
&preceding_stub.body,
f.context().comments(),
) && lines_after_ignoring_end_of_line_trivia(
preceding_stub.end(),
f.context().source(),
) < 2
});
let is_preceding_stub_function_without_empty_line = following
.is_function_def_stmt()
&& preceding
.as_function_def_stmt()
.is_some_and(|preceding_stub| {
contains_only_an_ellipsis(
&preceding_stub.body,
f.context().comments(),
) && lines_after_ignoring_end_of_line_trivia(
preceding_stub.end(),
f.context().source(),
) < 2
});
if !is_preceding_stub_function_without_empty_line {
match self.kind {
@ -529,11 +472,10 @@ pub(crate) fn should_insert_blank_line_after_class_in_stub_file(
following: Option<AnyNodeRef<'_>>,
context: &PyFormatContext,
) -> bool {
if !(is_blank_line_after_nested_stub_class_enabled(context)
&& context.options().source_type().is_stub())
{
if !context.options().source_type().is_stub() {
return false;
}
let comments = context.comments();
match preceding.as_stmt_class_def() {
Some(class) if contains_only_an_ellipsis(&class.body, comments) => {