mirror of
https://github.com/astral-sh/ruff.git
synced 2025-11-19 12:16:43 +00:00
Remove parentheses around multiple exception types on Python 3.14+ (#20768)
Summary -- This PR implements the black preview style from https://github.com/psf/black/pull/4720. As of Python 3.14, you're allowed to omit the parentheses around groups of exceptions, as long as there's no `as` binding: **3.13** ```pycon Python 3.13.4 (main, Jun 4 2025, 17:37:06) [Clang 20.1.4 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> try: ... ... except (Exception, BaseException): ... ... Ellipsis >>> try: ... ... except Exception, BaseException: ... ... File "<python-input-1>", line 2 except Exception, BaseException: ... ^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: multiple exception types must be parenthesized ``` **3.14** ```pycon Python 3.14.0rc2 (main, Sep 2 2025, 14:20:56) [Clang 20.1.4 ] on linux Type "help", "copyright", "credits" or "license" for more information. >>> try: ... ... except Exception, BaseException: ... ... Ellipsis >>> try: ... ... except (Exception, BaseException): ... ... Ellipsis >>> try: ... ... except Exception, BaseException as e: ... ... File "<python-input-2>", line 2 except Exception, BaseException as e: ... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SyntaxError: multiple exception types must be parenthesized when using 'as' ``` I think this ended up being pretty straightforward, at least once Micha showed me where to start :) Test Plan -- New tests At first I thought we were deviating from black in how we handle comments within the exception type tuple, but I think this applies to how we format all tuples, not specifically with the new preview style.
This commit is contained in:
parent
1ed9b215b9
commit
591e9bbccb
8 changed files with 497 additions and 450 deletions
8
crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/try.options.json
vendored
Normal file
8
crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/try.options.json
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"target_version": "3.13"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"target_version": "3.14"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
@ -166,3 +166,40 @@ else:
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
pass
|
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
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use anyhow::{Context, Result};
|
||||||
use clap::{Parser, ValueEnum, command};
|
use clap::{Parser, ValueEnum, command};
|
||||||
|
|
||||||
use ruff_formatter::SourceCode;
|
use ruff_formatter::SourceCode;
|
||||||
use ruff_python_ast::PySourceType;
|
use ruff_python_ast::{PySourceType, PythonVersion};
|
||||||
use ruff_python_parser::{ParseOptions, parse};
|
use ruff_python_parser::{ParseOptions, parse};
|
||||||
use ruff_python_trivia::CommentRanges;
|
use ruff_python_trivia::CommentRanges;
|
||||||
use ruff_text_size::Ranged;
|
use ruff_text_size::Ranged;
|
||||||
|
|
@ -42,13 +42,19 @@ pub struct Cli {
|
||||||
pub print_comments: bool,
|
pub print_comments: bool,
|
||||||
#[clap(long, short = 'C')]
|
#[clap(long, short = 'C')]
|
||||||
pub skip_magic_trailing_comma: bool,
|
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> {
|
pub fn format_and_debug_print(source: &str, cli: &Cli, source_path: &Path) -> Result<String> {
|
||||||
let source_type = PySourceType::from(source_path);
|
let source_type = PySourceType::from(source_path);
|
||||||
|
|
||||||
// Parse the AST.
|
// 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)
|
let options = PyFormatOptions::from_extension(source_path)
|
||||||
.with_preview(if cli.preview {
|
.with_preview(if cli.preview {
|
||||||
|
|
@ -60,7 +66,8 @@ pub fn format_and_debug_print(source: &str, cli: &Cli, source_path: &Path) -> Re
|
||||||
MagicTrailingComma::Ignore
|
MagicTrailingComma::Ignore
|
||||||
} else {
|
} else {
|
||||||
MagicTrailingComma::Respect
|
MagicTrailingComma::Respect
|
||||||
});
|
})
|
||||||
|
.with_target_version(cli.target_version);
|
||||||
|
|
||||||
let source_code = SourceCode::new(source);
|
let source_code = SourceCode::new(source);
|
||||||
let comment_ranges = CommentRanges::from(parsed.tokens());
|
let comment_ranges = CommentRanges::from(parsed.tokens());
|
||||||
|
|
|
||||||
|
|
@ -39,8 +39,8 @@ pub enum TupleParentheses {
|
||||||
///
|
///
|
||||||
/// ```python
|
/// ```python
|
||||||
/// return len(self.nodeseeeeeeeee), sum(
|
/// 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,
|
OptionalParentheses,
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
use ruff_formatter::FormatRuleWithOptions;
|
use ruff_formatter::FormatRuleWithOptions;
|
||||||
use ruff_formatter::write;
|
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::maybe_parenthesize_expression;
|
||||||
use crate::expression::parentheses::Parenthesize;
|
use crate::expression::parentheses::Parenthesize;
|
||||||
use crate::prelude::*;
|
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::clause::{ClauseHeader, clause_body, clause_header};
|
||||||
use crate::statement::suite::SuiteKind;
|
use crate::statement::suite::SuiteKind;
|
||||||
|
|
||||||
|
|
@ -57,7 +59,7 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
|
||||||
clause_header(
|
clause_header(
|
||||||
ClauseHeader::ExceptHandler(item),
|
ClauseHeader::ExceptHandler(item),
|
||||||
dangling_comments,
|
dangling_comments,
|
||||||
&format_with(|f| {
|
&format_with(|f: &mut PyFormatter| {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
[
|
[
|
||||||
|
|
@ -69,21 +71,50 @@ impl FormatNodeRule<ExceptHandlerExceptHandler> for FormatExceptHandlerExceptHan
|
||||||
]
|
]
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
if let Some(type_) = type_ {
|
match type_.as_deref() {
|
||||||
write!(
|
// For tuples of exception types without an `as` name and on 3.14+, the
|
||||||
f,
|
// parentheses are optional.
|
||||||
[
|
//
|
||||||
space(),
|
// ```py
|
||||||
maybe_parenthesize_expression(
|
// try:
|
||||||
type_,
|
// ...
|
||||||
item,
|
// except BaseException, Exception: # Ok
|
||||||
Parenthesize::IfBreaks
|
// ...
|
||||||
|
// ```
|
||||||
|
Some(Expr::Tuple(tuple))
|
||||||
|
if f.options().target_version() >= PythonVersion::PY314
|
||||||
|
&& is_remove_parens_around_except_types_enabled(
|
||||||
|
f.context(),
|
||||||
)
|
)
|
||||||
]
|
&& name.is_none() =>
|
||||||
)?;
|
{
|
||||||
if let Some(name) = name {
|
write!(
|
||||||
write!(f, [space(), token("as"), space(), name.format()])?;
|
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(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -27,3 +27,12 @@ pub(crate) const fn is_blank_line_before_decorated_class_in_stub_enabled(
|
||||||
) -> bool {
|
) -> bool {
|
||||||
context.is_preview()
|
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()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,427 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/black/cases/remove_except_types_parens.py
|
|
||||||
---
|
|
||||||
## Input
|
|
||||||
|
|
||||||
```python
|
|
||||||
# SEE PEP 758 FOR MORE DETAILS
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError,) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError,) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError, TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError, TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are not removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError, TypeError, KeyboardInterrupt) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError, TypeError, KeyboardInterrupt) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError if True else TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError if True else TypeError):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# inner except: parenthesis are removed
|
|
||||||
# outer except: parenthsis are not removed
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Differences
|
|
||||||
|
|
||||||
```diff
|
|
||||||
--- Black
|
|
||||||
+++ Ruff
|
|
||||||
@@ -74,12 +74,12 @@
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
-except ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
+except (ValueError, TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
-except* ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
+except* (ValueError, TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are not removed
|
|
||||||
@@ -109,7 +109,7 @@
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
- except TypeError, KeyboardInterrupt:
|
|
||||||
+ except (TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
@@ -117,7 +117,7 @@
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
- except* TypeError, KeyboardInterrupt:
|
|
||||||
+ except* (TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
## Ruff Output
|
|
||||||
|
|
||||||
```python
|
|
||||||
# SEE PEP 758 FOR MORE DETAILS
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError,) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError,) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError, TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError, TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are not removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError, TypeError, KeyboardInterrupt) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError, TypeError, KeyboardInterrupt) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError if True else TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError if True else TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# inner except: parenthesis are removed
|
|
||||||
# outer except: parenthsis are not removed
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (TypeError, KeyboardInterrupt):
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
||||||
## Black Output
|
|
||||||
|
|
||||||
```python
|
|
||||||
# SEE PEP 758 FOR MORE DETAILS
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError,) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError,) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# remains unchanged
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError, TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are not removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except (ValueError, TypeError, KeyboardInterrupt) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* (ValueError, TypeError, KeyboardInterrupt) as e:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# parenthesis are removed
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except ValueError if True else TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* ValueError if True else TypeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# inner except: parenthesis are removed
|
|
||||||
# outer except: parenthsis are not removed
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
except (ValueError,):
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
|
||||||
try:
|
|
||||||
pass
|
|
||||||
except* TypeError, KeyboardInterrupt:
|
|
||||||
pass
|
|
||||||
except* (ValueError,):
|
|
||||||
pass
|
|
||||||
```
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
---
|
---
|
||||||
source: crates/ruff_python_formatter/tests/fixtures.rs
|
source: crates/ruff_python_formatter/tests/fixtures.rs
|
||||||
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/try.py
|
input_file: crates/ruff_python_formatter/resources/test/fixtures/ruff/statement/try.py
|
||||||
snapshot_kind: text
|
|
||||||
---
|
---
|
||||||
## Input
|
## Input
|
||||||
```python
|
```python
|
||||||
|
|
@ -173,9 +172,61 @@ else:
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
pass
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
## Outputs
|
||||||
|
### Output 1
|
||||||
|
```
|
||||||
|
indent-style = space
|
||||||
|
line-width = 88
|
||||||
|
indent-width = 4
|
||||||
|
quote-style = Double
|
||||||
|
line-ending = LineFeed
|
||||||
|
magic-trailing-comma = Respect
|
||||||
|
docstring-code = Disabled
|
||||||
|
docstring-code-line-width = "dynamic"
|
||||||
|
preview = Disabled
|
||||||
|
target_version = 3.13
|
||||||
|
source_type = Python
|
||||||
```
|
```
|
||||||
|
|
||||||
## Output
|
|
||||||
```python
|
```python
|
||||||
try:
|
try:
|
||||||
pass
|
pass
|
||||||
|
|
@ -364,10 +415,50 @@ else:
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
pass
|
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
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Preview changes
|
#### Preview changes
|
||||||
```diff
|
```diff
|
||||||
--- Stable
|
--- Stable
|
||||||
+++ Preview
|
+++ Preview
|
||||||
|
|
@ -392,3 +483,294 @@ finally:
|
||||||
|
|
||||||
def f():
|
def f():
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Output 2
|
||||||
|
```
|
||||||
|
indent-style = space
|
||||||
|
line-width = 88
|
||||||
|
indent-width = 4
|
||||||
|
quote-style = Double
|
||||||
|
line-ending = LineFeed
|
||||||
|
magic-trailing-comma = Respect
|
||||||
|
docstring-code = Disabled
|
||||||
|
docstring-code-line-width = "dynamic"
|
||||||
|
preview = Disabled
|
||||||
|
target_version = 3.14
|
||||||
|
source_type = Python
|
||||||
|
```
|
||||||
|
|
||||||
|
```python
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except KeyError: # should remove brackets and be a single line
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try: # try
|
||||||
|
pass
|
||||||
|
# end of body
|
||||||
|
# before except
|
||||||
|
except (Exception, ValueError) as exc: # except line
|
||||||
|
pass
|
||||||
|
# before except 2
|
||||||
|
except KeyError as key: # except line 2
|
||||||
|
pass
|
||||||
|
# in body 2
|
||||||
|
# before else
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
# before finally
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# with line breaks
|
||||||
|
try: # try
|
||||||
|
pass
|
||||||
|
# end of body
|
||||||
|
|
||||||
|
# before except
|
||||||
|
except (Exception, ValueError) as exc: # except line
|
||||||
|
pass
|
||||||
|
|
||||||
|
# before except 2
|
||||||
|
except KeyError as key: # except line 2
|
||||||
|
pass
|
||||||
|
# in body 2
|
||||||
|
|
||||||
|
# before else
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# before finally
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
# with line breaks
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (
|
||||||
|
Exception,
|
||||||
|
Exception,
|
||||||
|
Exception,
|
||||||
|
Exception,
|
||||||
|
Exception,
|
||||||
|
Exception,
|
||||||
|
Exception,
|
||||||
|
) as exc: # splits exception over multiple lines
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except:
|
||||||
|
a = 10 # trailing comment1
|
||||||
|
b = 11 # trailing comment2
|
||||||
|
|
||||||
|
|
||||||
|
# try/except*, mostly the same as try
|
||||||
|
try: # try
|
||||||
|
pass
|
||||||
|
# end of body
|
||||||
|
# before except
|
||||||
|
except* (Exception, ValueError) as exc: # except line
|
||||||
|
pass
|
||||||
|
# before except 2
|
||||||
|
except* KeyError as key: # except line 2
|
||||||
|
pass
|
||||||
|
# in body 2
|
||||||
|
# before else
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
# before finally
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# try and try star are statements with body
|
||||||
|
# Minimized from https://github.com/python/cpython/blob/99b00efd5edfd5b26bf9e2a35cbfc96277fdcbb1/Lib/getpass.py#L68-L91
|
||||||
|
try:
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
finally:
|
||||||
|
print(1) # issue7208
|
||||||
|
except A:
|
||||||
|
pass
|
||||||
|
|
||||||
|
try:
|
||||||
|
f() # end-of-line last comment
|
||||||
|
except RuntimeError:
|
||||||
|
raise
|
||||||
|
|
||||||
|
try:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# a
|
||||||
|
except:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# b
|
||||||
|
else:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# c
|
||||||
|
finally:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# d
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass # a
|
||||||
|
except ZeroDivisionError:
|
||||||
|
pass # b
|
||||||
|
except:
|
||||||
|
pass # c
|
||||||
|
else:
|
||||||
|
pass # d
|
||||||
|
finally:
|
||||||
|
pass # e
|
||||||
|
|
||||||
|
try: # 1 preceding: any, following: first in body, enclosing: try
|
||||||
|
print(1) # 2 preceding: last in body, following: fist in alt body, enclosing: try
|
||||||
|
except (
|
||||||
|
ZeroDivisionError
|
||||||
|
): # 3 preceding: test, following: fist in alt body, enclosing: try
|
||||||
|
print(2) # 4 preceding: last in body, following: fist in alt body, enclosing: exc
|
||||||
|
except: # 5 preceding: last in body, following: fist in alt body, enclosing: try
|
||||||
|
print(2) # 6 preceding: last in body, following: fist in alt body, enclosing: exc
|
||||||
|
else: # 7 preceding: last in body, following: fist in alt body, enclosing: exc
|
||||||
|
print(3) # 8 preceding: last in body, following: fist in alt body, enclosing: try
|
||||||
|
finally: # 9 preceding: last in body, following: fist in alt body, enclosing: try
|
||||||
|
print(3) # 10 preceding: last in body, following: any, enclosing: try
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
except (
|
||||||
|
ZeroDivisionError
|
||||||
|
# comment
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
|
||||||
|
except ZeroDivisonError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
else:
|
||||||
|
pass
|
||||||
|
|
||||||
|
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
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
#### Preview changes
|
||||||
|
```diff
|
||||||
|
--- Stable
|
||||||
|
+++ Preview
|
||||||
|
@@ -117,16 +117,19 @@
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# a
|
||||||
|
+
|
||||||
|
except:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# b
|
||||||
|
+
|
||||||
|
else:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
pass
|
||||||
|
# c
|
||||||
|
+
|
||||||
|
finally:
|
||||||
|
|
||||||
|
def f():
|
||||||
|
@@ -190,7 +193,7 @@
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
# These parens can be removed on 3.14+ but not earlier
|
||||||
|
-except (BaseException, Exception, ValueError):
|
||||||
|
+except BaseException, Exception, ValueError:
|
||||||
|
pass
|
||||||
|
# But black won't remove these parentheses
|
||||||
|
except (ZeroDivisionError,):
|
||||||
|
@@ -212,7 +215,7 @@
|
||||||
|
try:
|
||||||
|
pass
|
||||||
|
# They can also be omitted for `except*`
|
||||||
|
-except* (BaseException, Exception, ValueError):
|
||||||
|
+except* BaseException, Exception, ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# But parentheses are still required in the presence of an `as` binding
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue