Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{
"target_version": "3.13"
},
{
"target_version": "3.14"
}
]
Original file line number Diff line number Diff line change
Expand Up @@ -166,3 +166,40 @@ def f():

finally:
pass


try:
pass
# These parens can be removed on 3.14+ but not earlier
except (BaseException, Exception, ValueError):
pass
# But black won't remove these parentheses
except (ZeroDivisionError,):
pass
except ( # We wrap these and preserve the parens
BaseException, Exception, ValueError):
pass
except (
BaseException,
# Same with this comment
Exception,
ValueError
):
pass

try:
pass
# They can also be omitted for `except*`
except* (BaseException, Exception, ValueError):
pass

# But parentheses are still required in the presence of an `as` binding
try:
pass
except (BaseException, Exception, ValueError) as e:
pass

try:
pass
except* (BaseException, Exception, ValueError) as e:
pass
13 changes: 10 additions & 3 deletions crates/ruff_python_formatter/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use anyhow::{Context, Result};
use clap::{Parser, ValueEnum, command};

use ruff_formatter::SourceCode;
use ruff_python_ast::PySourceType;
use ruff_python_ast::{PySourceType, PythonVersion};
use ruff_python_parser::{ParseOptions, parse};
use ruff_python_trivia::CommentRanges;
use ruff_text_size::Ranged;
Expand Down Expand Up @@ -42,13 +42,19 @@ pub struct Cli {
pub print_comments: bool,
#[clap(long, short = 'C')]
pub skip_magic_trailing_comma: bool,
#[clap(long)]
pub target_version: PythonVersion,
}

pub fn format_and_debug_print(source: &str, cli: &Cli, source_path: &Path) -> Result<String> {
let source_type = PySourceType::from(source_path);

// Parse the AST.
let parsed = parse(source, ParseOptions::from(source_type)).context("Syntax error in input")?;
let parsed = parse(
source,
ParseOptions::from(source_type).with_target_version(cli.target_version),
)
.context("Syntax error in input")?;

let options = PyFormatOptions::from_extension(source_path)
.with_preview(if cli.preview {
Expand All @@ -60,7 +66,8 @@ pub fn format_and_debug_print(source: &str, cli: &Cli, source_path: &Path) -> Re
MagicTrailingComma::Ignore
} else {
MagicTrailingComma::Respect
});
})
.with_target_version(cli.target_version);

let source_code = SourceCode::new(source);
let comment_ranges = CommentRanges::from(parsed.tokens());
Expand Down
4 changes: 2 additions & 2 deletions crates/ruff_python_formatter/src/expression/expr_tuple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ pub enum TupleParentheses {
///
/// ```python
/// return len(self.nodeseeeeeeeee), sum(
// len(node.parents) for node in self.node_map.values()
// )
/// len(node.parents) for node in self.node_map.values()
/// )
/// ```
OptionalParentheses,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use ruff_formatter::FormatRuleWithOptions;
use ruff_formatter::write;
use ruff_python_ast::ExceptHandlerExceptHandler;
use ruff_python_ast::{ExceptHandlerExceptHandler, Expr, PythonVersion};

use crate::expression::expr_tuple::TupleParentheses;
use crate::expression::maybe_parenthesize_expression;
use crate::expression::parentheses::Parenthesize;
use crate::prelude::*;
use crate::preview::is_remove_parens_around_except_types_enabled;
use crate::statement::clause::{ClauseHeader, clause_body, clause_header};
use crate::statement::suite::SuiteKind;

Expand Down Expand Up @@ -57,7 +59,7 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
clause_header(
ClauseHeader::ExceptHandler(item),
dangling_comments,
&format_with(|f| {
&format_with(|f: &mut PyFormatter| {
write!(
f,
[
Expand All @@ -69,21 +71,50 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
]
)?;

if let Some(type_) = type_ {
write!(
f,
[
space(),
maybe_parenthesize_expression(
type_,
item,
Parenthesize::IfBreaks
match type_.as_deref() {
// For tuples of exception types without an `as` name and on 3.14+, the
// parentheses are optional.
//
// ```py
// try:
// ...
// except BaseException, Exception: # Ok
// ...
// ```
Some(Expr::Tuple(tuple))
if f.options().target_version() >= PythonVersion::PY314
&& is_remove_parens_around_except_types_enabled(
f.context(),
)
]
)?;
if let Some(name) = name {
write!(f, [space(), token("as"), space(), name.format()])?;
&& name.is_none() =>
{
write!(
f,
[
space(),
tuple
.format()
.with_options(TupleParentheses::NeverPreserve)
]
)?;
}
Some(type_) => {
write!(
f,
[
space(),
maybe_parenthesize_expression(
type_,
item,
Parenthesize::IfBreaks
)
]
)?;
if let Some(name) = name {
write!(f, [space(), token("as"), space(), name.format()])?;
}
}
_ => {}
}

Ok(())
Expand Down
9 changes: 9 additions & 0 deletions crates/ruff_python_formatter/src/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,12 @@ pub(crate) const fn is_blank_line_before_decorated_class_in_stub_enabled(
) -> bool {
context.is_preview()
}

/// Returns `true` if the
/// [`remove_parens_around_except_types`](https://github.com/astral-sh/ruff/pull/20768) preview
/// style is enabled.
pub(crate) const fn is_remove_parens_around_except_types_enabled(
context: &PyFormatContext,
) -> bool {
context.is_preview()
}
Loading