Compare commits

...

9 Commits

Author SHA1 Message Date
Alex Waygood
5e6de4e0c6 Changelog for Ruff v0.7 (#13794)
Co-authored-by: Dhruv Manilawala <dhruvmanila@gmail.com>
2024-10-17 16:14:21 +00:00
Zanie Blue
70e5c4a8ba Recode TRY302 to TRY203 (#13502)
Closes https://github.com/astral-sh/ruff/issues/13492
2024-10-17 16:35:12 +01:00
Micha Reiser
9218d6bedc Remove allow-unused-imports setting from the common lint options (#13677)
Fixes https://github.com/astral-sh/ruff/issues/13668
2024-10-17 16:35:12 +01:00
Alex Waygood
1b79ae9817 [ruff-0.7] Stabilise the expansion of open-file-with-context-handler to work with other standard-library IO modules (SIM115) (#13680)
Closes #7313.
2024-10-17 16:35:12 +01:00
Alexey Preobrazhenskiy
2b87587ac2 [flake8-pytest-style] Fix defaults when lint.flake8-pytest-style config section is empty (PT001, PT023) (#13292) 2024-10-17 16:35:12 +01:00
Micha Reiser
d1e15f6246 Remove tab-size setting (#12835)
Co-authored-by: Alex Waygood <alex.waygood@gmail.com>
Closes https://github.com/astral-sh/ruff/issues/12041
2024-10-17 16:35:12 +01:00
Micha Reiser
89a82158a1 Remove error messages for removed CLI aliases (#12833)
Closes https://github.com/astral-sh/ruff/issues/10171
2024-10-17 16:35:12 +01:00
Micha Reiser
202c6a6d75 Remove output-format=text setting (#12836) 2024-10-17 16:35:12 +01:00
David Peter
5c3c0c4705 [red-knot] Inference for comparison of union types (#13781)
## Summary

Add type inference for comparisons involving union types. For example:
```py
one_or_two = 1 if flag else 2

reveal_type(one_or_two <= 2)  # revealed: Literal[True]
reveal_type(one_or_two <= 1)  # revealed: bool
reveal_type(one_or_two <= 0)  # revealed: Literal[False]
```

closes #13779

## Test Plan

See `resources/mdtest/comparison/unions.md`
2024-10-17 11:03:37 +02:00
33 changed files with 519 additions and 661 deletions

View File

@@ -1,5 +1,52 @@
# Changelog
## 0.7.0
Check out the [blog post](https://astral.sh/blog/ruff-v0.7.0) for a migration guide and overview of the changes!
### Breaking changes
- The pytest rules `PT001` and `PT023` now default to omitting the decorator parentheses when there are no arguments
([#12838](https://github.com/astral-sh/ruff/pull/12838), [#13292](https://github.com/astral-sh/ruff/pull/13292)).
This was a change that we attempted to make in Ruff v0.6.0, but only partially made due to an error on our part.
See the [blog post](https://astral.sh/blog/ruff-v0.7.0) for more details.
- The `useless-try-except` rule (in our `tryceratops` category) has been recoded from `TRY302` to
`TRY203` ([#13502](https://github.com/astral-sh/ruff/pull/13502)). This ensures Ruff's code is consistent with
the same rule in the [`tryceratops`](https://github.com/guilatrova/tryceratops) linter.
- The `lint.allow-unused-imports` setting has been removed ([#13677](https://github.com/astral-sh/ruff/pull/13677)). Use
[`lint.pyflakes.allow-unused-imports`](https://docs.astral.sh/ruff/settings/#lint_pyflakes_allowed-unused-imports)
instead.
### Formatter preview style
- Normalize implicit concatenated f-string quotes per part ([#13539](https://github.com/astral-sh/ruff/pull/13539))
### Preview linter features
- \[`refurb`\] implement `hardcoded-string-charset` (FURB156) ([#13530](https://github.com/astral-sh/ruff/pull/13530))
- \[`refurb`\] Count codepoints not bytes for `slice-to-remove-prefix-or-suffix (FURB188)` ([#13631](https://github.com/astral-sh/ruff/pull/13631))
### Rule changes
- \[`pylint`\] Mark `PLE1141` fix as unsafe ([#13629](https://github.com/astral-sh/ruff/pull/13629))
- \[`flake8-async`\] Consider async generators to be "checkpoints" for `cancel-scope-no-checkpoint` (`ASYNC100`) ([#13639](https://github.com/astral-sh/ruff/pull/13639))
- \[`flake8-bugbear`\] Do not suggest setting parameter `strict=` to `False` in `B905` diagnostic message ([#13656](https://github.com/astral-sh/ruff/pull/13656))
- \[`flake8-todos`\] Only flag the word "TODO", not words starting with "todo" (`TD006`) ([#13640](https://github.com/astral-sh/ruff/pull/13640))
- \[`pycodestyle`\] Fix whitespace-related false positives and false negatives inside type-parameter lists (`E231`, `E251`) ([#13704](https://github.com/astral-sh/ruff/pull/13704))
- \[`flake8-simplify`\] Stabilize preview behavior for `SIM115` so that the rule can detect files
being opened from a wider range of standard-library functions ([#12959](https://github.com/astral-sh/ruff/pull/12959)).
### CLI
- Add explanation of fixable in `--statistics` command ([#13774](https://github.com/astral-sh/ruff/pull/13774))
### Bug fixes
- \[`pyflakes`\] Allow `ipytest` cell magic (`F401`) ([#13745](https://github.com/astral-sh/ruff/pull/13745))
- \[`flake8-use-pathlib`\] Fix `PTH123` false positive when `open` is passed a file descriptor ([#13616](https://github.com/astral-sh/ruff/pull/13616))
- \[`flake8-bandit`\] Detect patterns from multi line SQL statements (`S608`) ([#13574](https://github.com/astral-sh/ruff/pull/13574))
- \[`flake8-pyi`\] - Fix dropped expressions in `PYI030` autofix ([#13727](https://github.com/astral-sh/ruff/pull/13727))
## 0.6.9
### Preview features

6
Cargo.lock generated
View File

@@ -2320,7 +2320,7 @@ dependencies = [
[[package]]
name = "ruff"
version = "0.6.9"
version = "0.7.0"
dependencies = [
"anyhow",
"argfile",
@@ -2539,7 +2539,7 @@ dependencies = [
[[package]]
name = "ruff_linter"
version = "0.6.9"
version = "0.7.0"
dependencies = [
"aho-corasick",
"annotate-snippets 0.9.2",
@@ -2859,7 +2859,7 @@ dependencies = [
[[package]]
name = "ruff_wasm"
version = "0.6.9"
version = "0.7.0"
dependencies = [
"console_error_panic_hook",
"console_log",

View File

@@ -136,8 +136,8 @@ curl -LsSf https://astral.sh/ruff/install.sh | sh
powershell -c "irm https://astral.sh/ruff/install.ps1 | iex"
# For a specific version.
curl -LsSf https://astral.sh/ruff/0.6.9/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.6.9/install.ps1 | iex"
curl -LsSf https://astral.sh/ruff/0.7.0/install.sh | sh
powershell -c "irm https://astral.sh/ruff/0.7.0/install.ps1 | iex"
```
You can also install Ruff via [Homebrew](https://formulae.brew.sh/formula/ruff), [Conda](https://anaconda.org/conda-forge/ruff),
@@ -170,7 +170,7 @@ Ruff can also be used as a [pre-commit](https://pre-commit.com/) hook via [`ruff
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
rev: v0.7.0
hooks:
# Run the linter.
- id: ruff

View File

@@ -0,0 +1,76 @@
# Comparison: Unions
## Union on one side of the comparison
Comparisons on union types need to consider all possible cases:
```py
one_or_two = 1 if flag else 2
reveal_type(one_or_two <= 2) # revealed: Literal[True]
reveal_type(one_or_two <= 1) # revealed: bool
reveal_type(one_or_two <= 0) # revealed: Literal[False]
reveal_type(2 >= one_or_two) # revealed: Literal[True]
reveal_type(1 >= one_or_two) # revealed: bool
reveal_type(0 >= one_or_two) # revealed: Literal[False]
reveal_type(one_or_two < 1) # revealed: Literal[False]
reveal_type(one_or_two < 2) # revealed: bool
reveal_type(one_or_two < 3) # revealed: Literal[True]
reveal_type(one_or_two > 0) # revealed: Literal[True]
reveal_type(one_or_two > 1) # revealed: bool
reveal_type(one_or_two > 2) # revealed: Literal[False]
reveal_type(one_or_two == 3) # revealed: Literal[False]
reveal_type(one_or_two == 1) # revealed: bool
reveal_type(one_or_two != 3) # revealed: Literal[True]
reveal_type(one_or_two != 1) # revealed: bool
a_or_ab = "a" if flag else "ab"
reveal_type(a_or_ab in "ab") # revealed: Literal[True]
reveal_type("a" in a_or_ab) # revealed: Literal[True]
reveal_type("c" not in a_or_ab) # revealed: Literal[True]
reveal_type("a" not in a_or_ab) # revealed: Literal[False]
reveal_type("b" in a_or_ab) # revealed: bool
reveal_type("b" not in a_or_ab) # revealed: bool
one_or_none = 1 if flag else None
reveal_type(one_or_none is None) # revealed: bool
reveal_type(one_or_none is not None) # revealed: bool
```
## Union on both sides of the comparison
With unions on both sides, we need to consider the full cross product of
options when building the resulting (union) type:
```py
small = 1 if flag_s else 2
large = 2 if flag_l else 3
reveal_type(small <= large) # revealed: Literal[True]
reveal_type(small >= large) # revealed: bool
reveal_type(small < large) # revealed: bool
reveal_type(small > large) # revealed: Literal[False]
```
## Unsupported operations
Make sure we emit a diagnostic if *any* of the possible comparisons is
unsupported. For now, we fall back to `bool` for the result type instead of
trying to infer something more precise from the other (supported) variants:
```py
x = [1, 2] if flag else 1
result = 1 in x # error: "Operator `in` is not supported"
reveal_type(result) # revealed: bool
```

View File

@@ -415,6 +415,11 @@ impl<'db> Type<'db> {
(_, Type::Unknown | Type::Any | Type::Todo) => false,
(Type::Never, _) => true,
(_, Type::Never) => false,
(Type::BooleanLiteral(_), Type::Instance(class))
if class.is_known(db, KnownClass::Bool) =>
{
true
}
(Type::IntLiteral(_), Type::Instance(class)) if class.is_known(db, KnownClass::Int) => {
true
}

View File

@@ -374,6 +374,12 @@ mod tests {
let union = UnionType::from_elements(&db, [t0, t1, t2, t3]).expect_union();
assert_eq!(union.elements(&db), &[bool_instance_ty, t3]);
let result_ty = UnionType::from_elements(&db, [bool_instance_ty, t0]);
assert_eq!(result_ty, bool_instance_ty);
let result_ty = UnionType::from_elements(&db, [t0, bool_instance_ty]);
assert_eq!(result_ty, bool_instance_ty);
}
#[test]

View File

@@ -57,7 +57,7 @@ use crate::types::{
};
use crate::Db;
use super::KnownClass;
use super::{KnownClass, UnionBuilder};
/// Infer all types for a [`ScopeId`], including all definitions and expressions in that scope.
/// Use when checking a scope, or needing to provide a type for an arbitrary expression in the
@@ -2711,6 +2711,21 @@ impl<'db> TypeInferenceBuilder<'db> {
// - `[ast::CompOp::Is]`: return `false` if unequal, `bool` if equal
// - `[ast::CompOp::IsNot]`: return `true` if unequal, `bool` if equal
match (left, right) {
(Type::Union(union), other) => {
let mut builder = UnionBuilder::new(self.db);
for element in union.elements(self.db) {
builder = builder.add(self.infer_binary_type_comparison(*element, op, other)?);
}
Some(builder.build())
}
(other, Type::Union(union)) => {
let mut builder = UnionBuilder::new(self.db);
for element in union.elements(self.db) {
builder = builder.add(self.infer_binary_type_comparison(other, op, *element)?);
}
Some(builder.build())
}
(Type::IntLiteral(n), Type::IntLiteral(m)) => match op {
ast::CmpOp::Eq => Some(Type::BooleanLiteral(n == m)),
ast::CmpOp::NotEq => Some(Type::BooleanLiteral(n != m)),
@@ -2902,6 +2917,7 @@ impl<'db> TypeInferenceBuilder<'db> {
}
}
}
// Lookup the rich comparison `__dunder__` methods on instances
(Type::Instance(left_class_ty), Type::Instance(right_class_ty)) => match op {
ast::CmpOp::Lt => {
@@ -2911,7 +2927,10 @@ impl<'db> TypeInferenceBuilder<'db> {
_ => Some(Type::Todo),
},
// TODO: handle more types
_ => Some(Type::Todo),
_ => match op {
ast::CmpOp::Is | ast::CmpOp::IsNot => Some(KnownClass::Bool.to_instance(self.db)),
_ => Some(Type::Todo),
},
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff"
version = "0.6.9"
version = "0.7.0"
publish = true
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -5,7 +5,7 @@ use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;
use anyhow::{anyhow, bail};
use anyhow::bail;
use clap::builder::{TypedValueParser, ValueParserFactory};
use clap::{command, Parser, Subcommand};
use colored::Colorize;
@@ -729,7 +729,7 @@ impl CheckCommand {
unsafe_fixes: resolve_bool_arg(self.unsafe_fixes, self.no_unsafe_fixes)
.map(UnsafeFixes::from),
force_exclude: resolve_bool_arg(self.force_exclude, self.no_force_exclude),
output_format: resolve_output_format(self.output_format)?,
output_format: self.output_format,
show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
extension: self.extension,
..ExplicitConfigOverrides::default()
@@ -984,17 +984,6 @@ The path `{value}` does not point to a configuration file"
}
}
#[allow(deprecated)]
fn resolve_output_format(
output_format: Option<OutputFormat>,
) -> anyhow::Result<Option<OutputFormat>> {
if let Some(OutputFormat::Text) = output_format {
Err(anyhow!("`--output-format=text` is no longer supported. Use `--output-format=full` or `--output-format=concise` instead."))
} else {
Ok(output_format)
}
}
/// CLI settings that are distinct from configuration (commands, lists of files,
/// etc.).
#[allow(clippy::struct_excessive_bools)]

View File

@@ -1,13 +1,11 @@
use std::io::Write;
use std::process::ExitCode;
use clap::{Parser, Subcommand};
use clap::Parser;
use colored::Colorize;
use log::error;
use std::io::Write;
use ruff::args::{Args, Command};
use ruff::args::Args;
use ruff::{run, ExitStatus};
use ruff_linter::logging::{set_up_logging, LogLevel};
#[cfg(target_os = "windows")]
#[global_allocator]
@@ -41,47 +39,6 @@ pub fn main() -> ExitCode {
let args = wild::args_os();
let args = argfile::expand_args_from(args, argfile::parse_fromfile, argfile::PREFIX).unwrap();
// We can't use `warn_user` here because logging isn't set up at this point
// and we also don't know if the user runs ruff with quiet.
// Keep the message and pass it to `run` that is responsible for emitting the warning.
let deprecated_alias_error = match args.get(1).and_then(|arg| arg.to_str()) {
// Deprecated aliases that are handled by clap
Some("--explain") => {
Some("`ruff --explain <RULE>` has been removed. Use `ruff rule <RULE>` instead.")
}
Some("--clean") => {
Some("`ruff --clean` has been removed. Use `ruff clean` instead.")
}
Some("--generate-shell-completion") => {
Some("`ruff --generate-shell-completion <SHELL>` has been removed. Use `ruff generate-shell-completion <SHELL>` instead.")
}
// Deprecated `ruff` alias to `ruff check`
// Clap doesn't support default subcommands but we want to run `check` by
// default for convenience and backwards-compatibility, so we just
// preprocess the arguments accordingly before passing them to Clap.
Some(arg) if !Command::has_subcommand(arg)
&& arg != "-h"
&& arg != "--help"
&& arg != "-V"
&& arg != "--version"
&& arg != "help" => {
{
Some("`ruff <path>` has been removed. Use `ruff check <path>` instead.")
}
},
_ => None
};
if let Some(error) = deprecated_alias_error {
#[allow(clippy::print_stderr)]
if set_up_logging(LogLevel::Default).is_ok() {
error!("{}", error);
} else {
eprintln!("{}", error.red().bold());
}
return ExitCode::FAILURE;
}
let args = Args::parse_from(args);
match run(args) {

View File

@@ -244,10 +244,7 @@ impl Printer {
#[allow(deprecated)]
if matches!(
self.format,
OutputFormat::Text
| OutputFormat::Full
| OutputFormat::Concise
| OutputFormat::Grouped
OutputFormat::Full | OutputFormat::Concise | OutputFormat::Grouped
) {
if self.flags.intersects(Flags::SHOW_FIX_SUMMARY) {
if !diagnostics.fixed.is_empty() {
@@ -325,8 +322,6 @@ impl Printer {
OutputFormat::Sarif => {
SarifEmitter.emit(writer, &diagnostics.messages, &context)?;
}
#[allow(deprecated)]
OutputFormat::Text => unreachable!("Text is deprecated and should have been automatically converted to the default serialization format")
}
writer.flush()?;
@@ -368,8 +363,7 @@ impl Printer {
}
match self.format {
#[allow(deprecated)]
OutputFormat::Text | OutputFormat::Full | OutputFormat::Concise => {
OutputFormat::Full | OutputFormat::Concise => {
// Compute the maximum number of digits in the count and code, for all messages,
// to enable pretty-printing.
let count_width = num_digits(

View File

@@ -1,36 +0,0 @@
//! A test suite that ensures deprecated command line options have appropriate warnings / behaviors
use ruff_linter::settings::types::OutputFormat;
use std::process::Command;
use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
const BIN_NAME: &str = "ruff";
const STDIN: &str = "l = 1";
fn ruff_check(output_format: OutputFormat) -> Command {
let mut cmd = Command::new(get_cargo_bin(BIN_NAME));
let output_format = output_format.to_string();
cmd.arg("check")
.arg("--output-format")
.arg(output_format)
.arg("--no-cache");
cmd.arg("-");
cmd
}
#[test]
#[allow(deprecated)]
fn ensure_output_format_is_deprecated() {
assert_cmd_snapshot!(ruff_check(OutputFormat::Text).pass_stdin(STDIN), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: `--output-format=text` is no longer supported. Use `--output-format=full` or `--output-format=concise` instead.
"###);
}

View File

@@ -818,7 +818,13 @@ if True:
----- stderr -----
ruff failed
Cause: The `tab-size` option has been renamed to `indent-width` to emphasize that it configures the indentation used by the formatter as well as the tab width. Please update `[RUFF-TOML-PATH]` to use `indent-width = <value>` instead.
Cause: Failed to parse [RUFF-TOML-PATH]
Cause: TOML parse error at line 1, column 1
|
1 |
| ^
unknown field `tab-size`
"###);
});
Ok(())

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_linter"
version = "0.6.9"
version = "0.7.0"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -855,9 +855,9 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Tryceratops, "004") => (RuleGroup::Stable, rules::tryceratops::rules::TypeCheckWithoutTypeError),
(Tryceratops, "200") => (RuleGroup::Removed, rules::tryceratops::rules::ReraiseNoCause),
(Tryceratops, "201") => (RuleGroup::Stable, rules::tryceratops::rules::VerboseRaise),
(Tryceratops, "203") => (RuleGroup::Stable, rules::tryceratops::rules::UselessTryExcept),
(Tryceratops, "300") => (RuleGroup::Stable, rules::tryceratops::rules::TryConsiderElse),
(Tryceratops, "301") => (RuleGroup::Stable, rules::tryceratops::rules::RaiseWithinTry),
(Tryceratops, "302") => (RuleGroup::Stable, rules::tryceratops::rules::UselessTryExcept),
(Tryceratops, "400") => (RuleGroup::Stable, rules::tryceratops::rules::ErrorInsteadOfException),
(Tryceratops, "401") => (RuleGroup::Stable, rules::tryceratops::rules::VerboseLogMessage),

View File

@@ -125,5 +125,7 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("PLW0117", "PLW0177"),
// See: https://github.com/astral-sh/ruff/issues/12110
("RUF025", "C420"),
// See: https://github.com/astral-sh/ruff/issues/13492
("TRY302", "TRY203"),
])
});

View File

@@ -58,7 +58,6 @@ mod tests {
}
#[test_case(Rule::IfElseBlockInsteadOfIfExp, Path::new("SIM108.py"))]
#[test_case(Rule::OpenFileWithContextHandler, Path::new("SIM115.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",

View File

@@ -14,13 +14,9 @@ use crate::checkers::ast::Checker;
/// ## Why is this bad?
/// If a file is opened without a context manager, it is not guaranteed that
/// the file will be closed (e.g., if an exception is raised), which can cause
/// resource leaks.
///
/// ## Preview-mode behavior
/// If [preview] mode is enabled, this rule will detect a wide array of IO calls where
/// context managers could be used, such as `tempfile.TemporaryFile()` or
/// `tarfile.TarFile(...).gzopen()`. If preview mode is not enabled, only `open()`,
/// `builtins.open()` and `pathlib.Path(...).open()` are detected.
/// resource leaks. The rule detects a wide array of IO calls where context managers
/// could be used, such as `open`, `pathlib.Path(...).open()`, `tempfile.TemporaryFile()`
/// or`tarfile.TarFile(...).gzopen()`.
///
/// ## Example
/// ```python
@@ -118,36 +114,9 @@ fn match_exit_stack(semantic: &SemanticModel) -> bool {
false
}
/// Return `true` if `func` is the builtin `open` or `pathlib.Path(...).open`.
fn is_open(semantic: &SemanticModel, call: &ast::ExprCall) -> bool {
// Ex) `open(...)`
if semantic.match_builtin_expr(&call.func, "open") {
return true;
}
// Ex) `pathlib.Path(...).open()`
let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = &*call.func else {
return false;
};
if attr != "open" {
return false;
}
let Expr::Call(ast::ExprCall {
func: value_func, ..
}) = &**value
else {
return false;
};
semantic
.resolve_qualified_name(value_func)
.is_some_and(|qualified_name| matches!(qualified_name.segments(), ["pathlib", "Path"]))
}
/// Return `true` if the expression is an `open` call or temporary file constructor.
fn is_open_preview(semantic: &SemanticModel, call: &ast::ExprCall) -> bool {
/// Return `true` if the expression is a call to `open()`,
/// or a call to some other standard-library function that opens a file.
fn is_open_call(semantic: &SemanticModel, call: &ast::ExprCall) -> bool {
let func = &*call.func;
// Ex) `open(...)`
@@ -203,8 +172,8 @@ fn is_open_preview(semantic: &SemanticModel, call: &ast::ExprCall) -> bool {
)
}
/// Return `true` if the current expression is followed by a `close` call.
fn is_closed(semantic: &SemanticModel) -> bool {
/// Return `true` if the current expression is immediately followed by a `.close()` call.
fn is_immediately_closed(semantic: &SemanticModel) -> bool {
let Some(expr) = semantic.current_expression_grandparent() else {
return false;
};
@@ -231,18 +200,12 @@ fn is_closed(semantic: &SemanticModel) -> bool {
pub(crate) fn open_file_with_context_handler(checker: &mut Checker, call: &ast::ExprCall) {
let semantic = checker.semantic();
if checker.settings.preview.is_disabled() {
if !is_open(semantic, call) {
return;
}
} else {
if !is_open_preview(semantic, call) {
return;
}
if !is_open_call(semantic, call) {
return;
}
// Ex) `open("foo.txt").close()`
if is_closed(semantic) {
if is_immediately_closed(semantic) {
return;
}

View File

@@ -59,3 +59,276 @@ SIM115.py:39:9: SIM115 Use a context manager for opening files
40 |
41 | # OK
|
SIM115.py:80:5: SIM115 Use a context manager for opening files
|
78 | import fileinput
79 |
80 | f = tempfile.NamedTemporaryFile()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
81 | f = tempfile.TemporaryFile()
82 | f = tempfile.SpooledTemporaryFile()
|
SIM115.py:81:5: SIM115 Use a context manager for opening files
|
80 | f = tempfile.NamedTemporaryFile()
81 | f = tempfile.TemporaryFile()
| ^^^^^^^^^^^^^^^^^^^^^^ SIM115
82 | f = tempfile.SpooledTemporaryFile()
83 | f = tarfile.open("foo.tar")
|
SIM115.py:82:5: SIM115 Use a context manager for opening files
|
80 | f = tempfile.NamedTemporaryFile()
81 | f = tempfile.TemporaryFile()
82 | f = tempfile.SpooledTemporaryFile()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
83 | f = tarfile.open("foo.tar")
84 | f = TarFile("foo.tar").open()
|
SIM115.py:83:5: SIM115 Use a context manager for opening files
|
81 | f = tempfile.TemporaryFile()
82 | f = tempfile.SpooledTemporaryFile()
83 | f = tarfile.open("foo.tar")
| ^^^^^^^^^^^^ SIM115
84 | f = TarFile("foo.tar").open()
85 | f = tarfile.TarFile("foo.tar").open()
|
SIM115.py:84:5: SIM115 Use a context manager for opening files
|
82 | f = tempfile.SpooledTemporaryFile()
83 | f = tarfile.open("foo.tar")
84 | f = TarFile("foo.tar").open()
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM115
85 | f = tarfile.TarFile("foo.tar").open()
86 | f = tarfile.TarFile().open()
|
SIM115.py:85:5: SIM115 Use a context manager for opening files
|
83 | f = tarfile.open("foo.tar")
84 | f = TarFile("foo.tar").open()
85 | f = tarfile.TarFile("foo.tar").open()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
86 | f = tarfile.TarFile().open()
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
|
SIM115.py:86:5: SIM115 Use a context manager for opening files
|
84 | f = TarFile("foo.tar").open()
85 | f = tarfile.TarFile("foo.tar").open()
86 | f = tarfile.TarFile().open()
| ^^^^^^^^^^^^^^^^^^^^^^ SIM115
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
88 | f = io.open("foo.txt")
|
SIM115.py:87:5: SIM115 Use a context manager for opening files
|
85 | f = tarfile.TarFile("foo.tar").open()
86 | f = tarfile.TarFile().open()
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
88 | f = io.open("foo.txt")
89 | f = io.open_code("foo.txt")
|
SIM115.py:88:5: SIM115 Use a context manager for opening files
|
86 | f = tarfile.TarFile().open()
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
88 | f = io.open("foo.txt")
| ^^^^^^^ SIM115
89 | f = io.open_code("foo.txt")
90 | f = codecs.open("foo.txt")
|
SIM115.py:89:5: SIM115 Use a context manager for opening files
|
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
88 | f = io.open("foo.txt")
89 | f = io.open_code("foo.txt")
| ^^^^^^^^^^^^ SIM115
90 | f = codecs.open("foo.txt")
91 | f = bz2.open("foo.txt")
|
SIM115.py:90:5: SIM115 Use a context manager for opening files
|
88 | f = io.open("foo.txt")
89 | f = io.open_code("foo.txt")
90 | f = codecs.open("foo.txt")
| ^^^^^^^^^^^ SIM115
91 | f = bz2.open("foo.txt")
92 | f = gzip.open("foo.txt")
|
SIM115.py:91:5: SIM115 Use a context manager for opening files
|
89 | f = io.open_code("foo.txt")
90 | f = codecs.open("foo.txt")
91 | f = bz2.open("foo.txt")
| ^^^^^^^^ SIM115
92 | f = gzip.open("foo.txt")
93 | f = dbm.open("foo.db")
|
SIM115.py:92:5: SIM115 Use a context manager for opening files
|
90 | f = codecs.open("foo.txt")
91 | f = bz2.open("foo.txt")
92 | f = gzip.open("foo.txt")
| ^^^^^^^^^ SIM115
93 | f = dbm.open("foo.db")
94 | f = dbm.gnu.open("foo.db")
|
SIM115.py:93:5: SIM115 Use a context manager for opening files
|
91 | f = bz2.open("foo.txt")
92 | f = gzip.open("foo.txt")
93 | f = dbm.open("foo.db")
| ^^^^^^^^ SIM115
94 | f = dbm.gnu.open("foo.db")
95 | f = dbm.ndbm.open("foo.db")
|
SIM115.py:94:5: SIM115 Use a context manager for opening files
|
92 | f = gzip.open("foo.txt")
93 | f = dbm.open("foo.db")
94 | f = dbm.gnu.open("foo.db")
| ^^^^^^^^^^^^ SIM115
95 | f = dbm.ndbm.open("foo.db")
96 | f = dbm.dumb.open("foo.db")
|
SIM115.py:95:5: SIM115 Use a context manager for opening files
|
93 | f = dbm.open("foo.db")
94 | f = dbm.gnu.open("foo.db")
95 | f = dbm.ndbm.open("foo.db")
| ^^^^^^^^^^^^^ SIM115
96 | f = dbm.dumb.open("foo.db")
97 | f = lzma.open("foo.xz")
|
SIM115.py:96:5: SIM115 Use a context manager for opening files
|
94 | f = dbm.gnu.open("foo.db")
95 | f = dbm.ndbm.open("foo.db")
96 | f = dbm.dumb.open("foo.db")
| ^^^^^^^^^^^^^ SIM115
97 | f = lzma.open("foo.xz")
98 | f = lzma.LZMAFile("foo.xz")
|
SIM115.py:97:5: SIM115 Use a context manager for opening files
|
95 | f = dbm.ndbm.open("foo.db")
96 | f = dbm.dumb.open("foo.db")
97 | f = lzma.open("foo.xz")
| ^^^^^^^^^ SIM115
98 | f = lzma.LZMAFile("foo.xz")
99 | f = shelve.open("foo.db")
|
SIM115.py:98:5: SIM115 Use a context manager for opening files
|
96 | f = dbm.dumb.open("foo.db")
97 | f = lzma.open("foo.xz")
98 | f = lzma.LZMAFile("foo.xz")
| ^^^^^^^^^^^^^ SIM115
99 | f = shelve.open("foo.db")
100 | f = tokenize.open("foo.py")
|
SIM115.py:99:5: SIM115 Use a context manager for opening files
|
97 | f = lzma.open("foo.xz")
98 | f = lzma.LZMAFile("foo.xz")
99 | f = shelve.open("foo.db")
| ^^^^^^^^^^^ SIM115
100 | f = tokenize.open("foo.py")
101 | f = wave.open("foo.wav")
|
SIM115.py:100:5: SIM115 Use a context manager for opening files
|
98 | f = lzma.LZMAFile("foo.xz")
99 | f = shelve.open("foo.db")
100 | f = tokenize.open("foo.py")
| ^^^^^^^^^^^^^ SIM115
101 | f = wave.open("foo.wav")
102 | f = tarfile.TarFile.taropen("foo.tar")
|
SIM115.py:101:5: SIM115 Use a context manager for opening files
|
99 | f = shelve.open("foo.db")
100 | f = tokenize.open("foo.py")
101 | f = wave.open("foo.wav")
| ^^^^^^^^^ SIM115
102 | f = tarfile.TarFile.taropen("foo.tar")
103 | f = fileinput.input("foo.txt")
|
SIM115.py:102:5: SIM115 Use a context manager for opening files
|
100 | f = tokenize.open("foo.py")
101 | f = wave.open("foo.wav")
102 | f = tarfile.TarFile.taropen("foo.tar")
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM115
103 | f = fileinput.input("foo.txt")
104 | f = fileinput.FileInput("foo.txt")
|
SIM115.py:103:5: SIM115 Use a context manager for opening files
|
101 | f = wave.open("foo.wav")
102 | f = tarfile.TarFile.taropen("foo.tar")
103 | f = fileinput.input("foo.txt")
| ^^^^^^^^^^^^^^^ SIM115
104 | f = fileinput.FileInput("foo.txt")
|
SIM115.py:104:5: SIM115 Use a context manager for opening files
|
102 | f = tarfile.TarFile.taropen("foo.tar")
103 | f = fileinput.input("foo.txt")
104 | f = fileinput.FileInput("foo.txt")
| ^^^^^^^^^^^^^^^^^^^ SIM115
105 |
106 | with contextlib.suppress(Exception):
|
SIM115.py:240:9: SIM115 Use a context manager for opening files
|
238 | def aliased():
239 | from shelve import open as open_shelf
240 | x = open_shelf("foo.dbm")
| ^^^^^^^^^^ SIM115
241 | x.close()
|
SIM115.py:244:9: SIM115 Use a context manager for opening files
|
243 | from tarfile import TarFile as TF
244 | f = TF("foo").open()
| ^^^^^^^^^^^^^^ SIM115
245 | f.close()
|
SIM115.py:257:5: SIM115 Use a context manager for opening files
|
256 | # SIM115
257 | f = dbm.sqlite3.open("foo.db")
| ^^^^^^^^^^^^^^^^ SIM115
258 | f.close()
|

View File

@@ -1,334 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM115.py:8:5: SIM115 Use a context manager for opening files
|
7 | # SIM115
8 | f = open("foo.txt")
| ^^^^ SIM115
9 | f = Path("foo.txt").open()
10 | f = pathlib.Path("foo.txt").open()
|
SIM115.py:9:5: SIM115 Use a context manager for opening files
|
7 | # SIM115
8 | f = open("foo.txt")
9 | f = Path("foo.txt").open()
| ^^^^^^^^^^^^^^^^^^^^ SIM115
10 | f = pathlib.Path("foo.txt").open()
11 | f = pl.Path("foo.txt").open()
|
SIM115.py:10:5: SIM115 Use a context manager for opening files
|
8 | f = open("foo.txt")
9 | f = Path("foo.txt").open()
10 | f = pathlib.Path("foo.txt").open()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
11 | f = pl.Path("foo.txt").open()
12 | f = P("foo.txt").open()
|
SIM115.py:11:5: SIM115 Use a context manager for opening files
|
9 | f = Path("foo.txt").open()
10 | f = pathlib.Path("foo.txt").open()
11 | f = pl.Path("foo.txt").open()
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM115
12 | f = P("foo.txt").open()
13 | data = f.read()
|
SIM115.py:12:5: SIM115 Use a context manager for opening files
|
10 | f = pathlib.Path("foo.txt").open()
11 | f = pl.Path("foo.txt").open()
12 | f = P("foo.txt").open()
| ^^^^^^^^^^^^^^^^^ SIM115
13 | data = f.read()
14 | f.close()
|
SIM115.py:39:9: SIM115 Use a context manager for opening files
|
37 | # SIM115
38 | with contextlib.ExitStack():
39 | f = open("filename")
| ^^^^ SIM115
40 |
41 | # OK
|
SIM115.py:80:5: SIM115 Use a context manager for opening files
|
78 | import fileinput
79 |
80 | f = tempfile.NamedTemporaryFile()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
81 | f = tempfile.TemporaryFile()
82 | f = tempfile.SpooledTemporaryFile()
|
SIM115.py:81:5: SIM115 Use a context manager for opening files
|
80 | f = tempfile.NamedTemporaryFile()
81 | f = tempfile.TemporaryFile()
| ^^^^^^^^^^^^^^^^^^^^^^ SIM115
82 | f = tempfile.SpooledTemporaryFile()
83 | f = tarfile.open("foo.tar")
|
SIM115.py:82:5: SIM115 Use a context manager for opening files
|
80 | f = tempfile.NamedTemporaryFile()
81 | f = tempfile.TemporaryFile()
82 | f = tempfile.SpooledTemporaryFile()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
83 | f = tarfile.open("foo.tar")
84 | f = TarFile("foo.tar").open()
|
SIM115.py:83:5: SIM115 Use a context manager for opening files
|
81 | f = tempfile.TemporaryFile()
82 | f = tempfile.SpooledTemporaryFile()
83 | f = tarfile.open("foo.tar")
| ^^^^^^^^^^^^ SIM115
84 | f = TarFile("foo.tar").open()
85 | f = tarfile.TarFile("foo.tar").open()
|
SIM115.py:84:5: SIM115 Use a context manager for opening files
|
82 | f = tempfile.SpooledTemporaryFile()
83 | f = tarfile.open("foo.tar")
84 | f = TarFile("foo.tar").open()
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM115
85 | f = tarfile.TarFile("foo.tar").open()
86 | f = tarfile.TarFile().open()
|
SIM115.py:85:5: SIM115 Use a context manager for opening files
|
83 | f = tarfile.open("foo.tar")
84 | f = TarFile("foo.tar").open()
85 | f = tarfile.TarFile("foo.tar").open()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
86 | f = tarfile.TarFile().open()
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
|
SIM115.py:86:5: SIM115 Use a context manager for opening files
|
84 | f = TarFile("foo.tar").open()
85 | f = tarfile.TarFile("foo.tar").open()
86 | f = tarfile.TarFile().open()
| ^^^^^^^^^^^^^^^^^^^^^^ SIM115
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
88 | f = io.open("foo.txt")
|
SIM115.py:87:5: SIM115 Use a context manager for opening files
|
85 | f = tarfile.TarFile("foo.tar").open()
86 | f = tarfile.TarFile().open()
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM115
88 | f = io.open("foo.txt")
89 | f = io.open_code("foo.txt")
|
SIM115.py:88:5: SIM115 Use a context manager for opening files
|
86 | f = tarfile.TarFile().open()
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
88 | f = io.open("foo.txt")
| ^^^^^^^ SIM115
89 | f = io.open_code("foo.txt")
90 | f = codecs.open("foo.txt")
|
SIM115.py:89:5: SIM115 Use a context manager for opening files
|
87 | f = zipfile.ZipFile("foo.zip").open("foo.txt")
88 | f = io.open("foo.txt")
89 | f = io.open_code("foo.txt")
| ^^^^^^^^^^^^ SIM115
90 | f = codecs.open("foo.txt")
91 | f = bz2.open("foo.txt")
|
SIM115.py:90:5: SIM115 Use a context manager for opening files
|
88 | f = io.open("foo.txt")
89 | f = io.open_code("foo.txt")
90 | f = codecs.open("foo.txt")
| ^^^^^^^^^^^ SIM115
91 | f = bz2.open("foo.txt")
92 | f = gzip.open("foo.txt")
|
SIM115.py:91:5: SIM115 Use a context manager for opening files
|
89 | f = io.open_code("foo.txt")
90 | f = codecs.open("foo.txt")
91 | f = bz2.open("foo.txt")
| ^^^^^^^^ SIM115
92 | f = gzip.open("foo.txt")
93 | f = dbm.open("foo.db")
|
SIM115.py:92:5: SIM115 Use a context manager for opening files
|
90 | f = codecs.open("foo.txt")
91 | f = bz2.open("foo.txt")
92 | f = gzip.open("foo.txt")
| ^^^^^^^^^ SIM115
93 | f = dbm.open("foo.db")
94 | f = dbm.gnu.open("foo.db")
|
SIM115.py:93:5: SIM115 Use a context manager for opening files
|
91 | f = bz2.open("foo.txt")
92 | f = gzip.open("foo.txt")
93 | f = dbm.open("foo.db")
| ^^^^^^^^ SIM115
94 | f = dbm.gnu.open("foo.db")
95 | f = dbm.ndbm.open("foo.db")
|
SIM115.py:94:5: SIM115 Use a context manager for opening files
|
92 | f = gzip.open("foo.txt")
93 | f = dbm.open("foo.db")
94 | f = dbm.gnu.open("foo.db")
| ^^^^^^^^^^^^ SIM115
95 | f = dbm.ndbm.open("foo.db")
96 | f = dbm.dumb.open("foo.db")
|
SIM115.py:95:5: SIM115 Use a context manager for opening files
|
93 | f = dbm.open("foo.db")
94 | f = dbm.gnu.open("foo.db")
95 | f = dbm.ndbm.open("foo.db")
| ^^^^^^^^^^^^^ SIM115
96 | f = dbm.dumb.open("foo.db")
97 | f = lzma.open("foo.xz")
|
SIM115.py:96:5: SIM115 Use a context manager for opening files
|
94 | f = dbm.gnu.open("foo.db")
95 | f = dbm.ndbm.open("foo.db")
96 | f = dbm.dumb.open("foo.db")
| ^^^^^^^^^^^^^ SIM115
97 | f = lzma.open("foo.xz")
98 | f = lzma.LZMAFile("foo.xz")
|
SIM115.py:97:5: SIM115 Use a context manager for opening files
|
95 | f = dbm.ndbm.open("foo.db")
96 | f = dbm.dumb.open("foo.db")
97 | f = lzma.open("foo.xz")
| ^^^^^^^^^ SIM115
98 | f = lzma.LZMAFile("foo.xz")
99 | f = shelve.open("foo.db")
|
SIM115.py:98:5: SIM115 Use a context manager for opening files
|
96 | f = dbm.dumb.open("foo.db")
97 | f = lzma.open("foo.xz")
98 | f = lzma.LZMAFile("foo.xz")
| ^^^^^^^^^^^^^ SIM115
99 | f = shelve.open("foo.db")
100 | f = tokenize.open("foo.py")
|
SIM115.py:99:5: SIM115 Use a context manager for opening files
|
97 | f = lzma.open("foo.xz")
98 | f = lzma.LZMAFile("foo.xz")
99 | f = shelve.open("foo.db")
| ^^^^^^^^^^^ SIM115
100 | f = tokenize.open("foo.py")
101 | f = wave.open("foo.wav")
|
SIM115.py:100:5: SIM115 Use a context manager for opening files
|
98 | f = lzma.LZMAFile("foo.xz")
99 | f = shelve.open("foo.db")
100 | f = tokenize.open("foo.py")
| ^^^^^^^^^^^^^ SIM115
101 | f = wave.open("foo.wav")
102 | f = tarfile.TarFile.taropen("foo.tar")
|
SIM115.py:101:5: SIM115 Use a context manager for opening files
|
99 | f = shelve.open("foo.db")
100 | f = tokenize.open("foo.py")
101 | f = wave.open("foo.wav")
| ^^^^^^^^^ SIM115
102 | f = tarfile.TarFile.taropen("foo.tar")
103 | f = fileinput.input("foo.txt")
|
SIM115.py:102:5: SIM115 Use a context manager for opening files
|
100 | f = tokenize.open("foo.py")
101 | f = wave.open("foo.wav")
102 | f = tarfile.TarFile.taropen("foo.tar")
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM115
103 | f = fileinput.input("foo.txt")
104 | f = fileinput.FileInput("foo.txt")
|
SIM115.py:103:5: SIM115 Use a context manager for opening files
|
101 | f = wave.open("foo.wav")
102 | f = tarfile.TarFile.taropen("foo.tar")
103 | f = fileinput.input("foo.txt")
| ^^^^^^^^^^^^^^^ SIM115
104 | f = fileinput.FileInput("foo.txt")
|
SIM115.py:104:5: SIM115 Use a context manager for opening files
|
102 | f = tarfile.TarFile.taropen("foo.tar")
103 | f = fileinput.input("foo.txt")
104 | f = fileinput.FileInput("foo.txt")
| ^^^^^^^^^^^^^^^^^^^ SIM115
105 |
106 | with contextlib.suppress(Exception):
|
SIM115.py:240:9: SIM115 Use a context manager for opening files
|
238 | def aliased():
239 | from shelve import open as open_shelf
240 | x = open_shelf("foo.dbm")
| ^^^^^^^^^^ SIM115
241 | x.close()
|
SIM115.py:244:9: SIM115 Use a context manager for opening files
|
243 | from tarfile import TarFile as TF
244 | f = TF("foo").open()
| ^^^^^^^^^^^^^^ SIM115
245 | f.close()
|
SIM115.py:257:5: SIM115 Use a context manager for opening files
|
256 | # SIM115
257 | f = dbm.sqlite3.open("foo.db")
| ^^^^^^^^^^^^^^^^ SIM115
258 | f.close()
|

View File

@@ -19,9 +19,9 @@ mod tests {
#[test_case(Rule::RaiseVanillaArgs, Path::new("TRY003.py"))]
#[test_case(Rule::TypeCheckWithoutTypeError, Path::new("TRY004.py"))]
#[test_case(Rule::VerboseRaise, Path::new("TRY201.py"))]
#[test_case(Rule::UselessTryExcept, Path::new("TRY203.py"))]
#[test_case(Rule::TryConsiderElse, Path::new("TRY300.py"))]
#[test_case(Rule::RaiseWithinTry, Path::new("TRY301.py"))]
#[test_case(Rule::UselessTryExcept, Path::new("TRY302.py"))]
#[test_case(Rule::ErrorInsteadOfException, Path::new("TRY400.py"))]
#[test_case(Rule::VerboseLogMessage, Path::new("TRY401.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {

View File

@@ -38,7 +38,7 @@ impl Violation for UselessTryExcept {
}
}
/// TRY302
/// TRY203 (previously TRY302)
pub(crate) fn useless_try_except(checker: &mut Checker, handlers: &[ExceptHandler]) {
if let Some(diagnostics) = handlers
.iter()

View File

@@ -1,19 +1,19 @@
---
source: crates/ruff_linter/src/rules/tryceratops/mod.rs
---
TRY302.py:12:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:12:5: TRY203 Remove exception handler; error is immediately re-raised
|
10 | try:
11 | process()
12 | except Exception:
| _____^
13 | | raise
| |_____________^ TRY302
| |_____________^ TRY203
14 |
15 | def bad():
|
TRY302.py:18:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:18:5: TRY203 Remove exception handler; error is immediately re-raised
|
16 | try:
17 | process()
@@ -21,12 +21,12 @@ TRY302.py:18:5: TRY302 Remove exception handler; error is immediately re-raised
| _____^
19 | | raise
20 | | print("this code is pointless!")
| |________________________________________^ TRY302
| |________________________________________^ TRY203
21 |
22 | def bad():
|
TRY302.py:25:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:25:5: TRY203 Remove exception handler; error is immediately re-raised
|
23 | try:
24 | process()
@@ -34,117 +34,115 @@ TRY302.py:25:5: TRY302 Remove exception handler; error is immediately re-raised
| _____^
26 | | # I am a comment, not a statement!
27 | | raise
| |_____________^ TRY302
| |_____________^ TRY203
28 |
29 | def bad():
|
TRY302.py:32:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:32:5: TRY203 Remove exception handler; error is immediately re-raised
|
30 | try:
31 | process()
32 | except Exception:
| _____^
33 | | raise
| |_____________^ TRY302
| |_____________^ TRY203
34 |
35 | def bad():
|
TRY302.py:38:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:38:5: TRY203 Remove exception handler; error is immediately re-raised
|
36 | try:
37 | process()
38 | except Exception as e:
| _____^
39 | | raise
| |_____________^ TRY302
| |_____________^ TRY203
40 |
41 | def bad():
|
TRY302.py:44:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:44:5: TRY203 Remove exception handler; error is immediately re-raised
|
42 | try:
43 | process()
44 | except Exception as e:
| _____^
45 | | raise e
| |_______________^ TRY302
| |_______________^ TRY203
46 |
47 | def bad():
|
TRY302.py:50:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:50:5: TRY203 Remove exception handler; error is immediately re-raised
|
48 | try:
49 | process()
50 | except MyException:
| _____^
51 | | raise
| |_____________^ TRY302
| |_____________^ TRY203
52 | except Exception:
53 | raise
|
TRY302.py:52:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:52:5: TRY203 Remove exception handler; error is immediately re-raised
|
50 | except MyException:
51 | raise
52 | except Exception:
| _____^
53 | | raise
| |_____________^ TRY302
| |_____________^ TRY203
54 |
55 | def bad():
|
TRY302.py:58:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:58:5: TRY203 Remove exception handler; error is immediately re-raised
|
56 | try:
57 | process()
58 | except MyException as e:
| _____^
59 | | raise e
| |_______________^ TRY302
| |_______________^ TRY203
60 | except Exception as e:
61 | raise e
|
TRY302.py:60:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:60:5: TRY203 Remove exception handler; error is immediately re-raised
|
58 | except MyException as e:
59 | raise e
60 | except Exception as e:
| _____^
61 | | raise e
| |_______________^ TRY302
| |_______________^ TRY203
62 |
63 | def bad():
|
TRY302.py:66:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:66:5: TRY203 Remove exception handler; error is immediately re-raised
|
64 | try:
65 | process()
66 | except MyException as ex:
| _____^
67 | | raise ex
| |________________^ TRY302
| |________________^ TRY203
68 | except Exception as e:
69 | raise e
|
TRY302.py:68:5: TRY302 Remove exception handler; error is immediately re-raised
TRY203.py:68:5: TRY203 Remove exception handler; error is immediately re-raised
|
66 | except MyException as ex:
67 | raise ex
68 | except Exception as e:
| _____^
69 | | raise e
| |_______________^ TRY302
| |_______________^ TRY203
70 |
71 | def fine():
|

View File

@@ -1,5 +1,3 @@
#![allow(deprecated)]
use std::fmt::{Display, Formatter};
use std::hash::{Hash, Hasher};
use std::ops::Deref;
@@ -511,12 +509,6 @@ impl FromIterator<ExtensionPair> for ExtensionMapping {
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum OutputFormat {
// Remove the module level `#![allow(deprecated)` when removing the text variant.
// Adding the `#[deprecated]` attribute to text creates clippy warnings about
// using a deprecated item in the derived code and there seems to be no way to suppress the clippy error
// other than disabling the warning for the entire module and/or moving `OutputFormat` to another module.
#[deprecated(note = "Use `concise` or `full` instead")]
Text,
Concise,
#[default]
Full,
@@ -535,7 +527,6 @@ pub enum OutputFormat {
impl Display for OutputFormat {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Text => write!(f, "text"),
Self::Concise => write!(f, "concise"),
Self::Full => write!(f, "full"),
Self::Json => write!(f, "json"),

View File

@@ -1,6 +1,6 @@
[package]
name = "ruff_wasm"
version = "0.6.9"
version = "0.7.0"
publish = false
authors = { workspace = true }
edition = { workspace = true }

View File

@@ -347,9 +347,7 @@ impl Configuration {
.unwrap_or_default(),
flake8_pytest_style: lint
.flake8_pytest_style
.map(|options| {
Flake8PytestStyleOptions::try_into_settings(options, lint_preview)
})
.map(Flake8PytestStyleOptions::try_into_settings)
.transpose()?
.unwrap_or_default(),
flake8_quotes: lint
@@ -445,26 +443,6 @@ impl Configuration {
}
};
#[allow(deprecated)]
if options.tab_size.is_some() {
let config_to_update = path.map_or_else(
|| String::from("your `--config` CLI arguments"),
|path| format!("`{}`", fs::relativize_path(path)),
);
return Err(anyhow!("The `tab-size` option has been renamed to `indent-width` to emphasize that it configures the indentation used by the formatter as well as the tab width. Please update {config_to_update} to use `indent-width = <value>` instead."));
}
#[allow(deprecated)]
if options.output_format == Some(OutputFormat::Text) {
let config_to_update = path.map_or_else(
|| String::from("your `--config` CLI arguments"),
|path| format!("`{}`", fs::relativize_path(path)),
);
return Err(anyhow!(
r#"The option `output_format=text` is no longer supported. Update {config_to_update} to use `output-format="concise"` or `output-format="full"` instead."#
));
}
Ok(Self {
builtins: options.builtins,
cache_dir: options
@@ -626,7 +604,6 @@ pub struct LintConfiguration {
pub logger_objects: Option<Vec<String>>,
pub task_tags: Option<Vec<String>>,
pub typing_modules: Option<Vec<String>>,
pub allowed_unused_imports: Option<Vec<String>>,
// Plugins
pub flake8_annotations: Option<Flake8AnnotationsOptions>,
@@ -739,7 +716,7 @@ impl LintConfiguration {
task_tags: options.common.task_tags,
logger_objects: options.common.logger_objects,
typing_modules: options.common.typing_modules,
allowed_unused_imports: options.common.allowed_unused_imports,
// Plugins
flake8_annotations: options.common.flake8_annotations,
flake8_bandit: options.common.flake8_bandit,
@@ -1108,9 +1085,7 @@ impl LintConfiguration {
.or(config.explicit_preview_rules),
task_tags: self.task_tags.or(config.task_tags),
typing_modules: self.typing_modules.or(config.typing_modules),
allowed_unused_imports: self
.allowed_unused_imports
.or(config.allowed_unused_imports),
// Plugins
flake8_annotations: self.flake8_annotations.combine(config.flake8_annotations),
flake8_bandit: self.flake8_bandit.combine(config.flake8_bandit),
@@ -1332,7 +1307,6 @@ fn warn_about_deprecated_top_level_lint_options(
explicit_preview_rules,
task_tags,
typing_modules,
allowed_unused_imports,
unfixable,
flake8_annotations,
flake8_bandit,
@@ -1431,9 +1405,6 @@ fn warn_about_deprecated_top_level_lint_options(
if typing_modules.is_some() {
used_options.push("typing-modules");
}
if allowed_unused_imports.is_some() {
used_options.push("allowed-unused-imports");
}
if unfixable.is_some() {
used_options.push("unfixable");

View File

@@ -27,7 +27,7 @@ use ruff_linter::rules::{
pycodestyle, pydocstyle, pyflakes, pylint, pyupgrade, ruff,
};
use ruff_linter::settings::types::{
IdentifierPattern, OutputFormat, PreviewMode, PythonVersion, RequiredVersion,
IdentifierPattern, OutputFormat, PythonVersion, RequiredVersion,
};
use ruff_linter::{warn_user_once, RuleSelector};
use ruff_macros::{CombineOptions, OptionsMetadata};
@@ -415,17 +415,6 @@ pub struct Options {
)]
pub indent_width: Option<IndentWidth>,
/// The number of spaces a tab is equal to when enforcing long-line violations (like `E501`)
/// or formatting code with the formatter.
///
/// This option changes the number of spaces inserted by the formatter when
/// using soft-tabs (`indent-style = space`).
#[deprecated(
since = "0.1.2",
note = "The `tab-size` option has been renamed to `indent-width` to emphasize that it configures the indentation used by the formatter as well as the tab width. Please update your configuration to use `indent-width = <value>` instead."
)]
pub tab_size: Option<IndentWidth>,
#[option_group]
pub lint: Option<LintOptions>,
@@ -796,16 +785,6 @@ pub struct LintCommonOptions {
)]
pub typing_modules: Option<Vec<String>>,
/// A list of modules which is allowed even though they are not used
/// in the code.
///
/// This is useful when a module has a side effect when imported.
#[option(
default = r#"[]"#,
value_type = "list[str]",
example = r#"allowed-unused-imports = ["hvplot.pandas"]"#
)]
pub allowed_unused_imports: Option<Vec<String>>,
/// A list of rule codes or prefixes to consider non-fixable.
#[option(
default = "[]",
@@ -1511,12 +1490,9 @@ pub struct Flake8PytestStyleOptions {
}
impl Flake8PytestStyleOptions {
pub fn try_into_settings(
self,
preview: PreviewMode,
) -> anyhow::Result<flake8_pytest_style::settings::Settings> {
pub fn try_into_settings(self) -> anyhow::Result<flake8_pytest_style::settings::Settings> {
Ok(flake8_pytest_style::settings::Settings {
fixture_parentheses: self.fixture_parentheses.unwrap_or(preview.is_disabled()),
fixture_parentheses: self.fixture_parentheses.unwrap_or_default(),
parametrize_names_type: self.parametrize_names_type.unwrap_or_default(),
parametrize_values_type: self.parametrize_values_type.unwrap_or_default(),
parametrize_values_row_type: self.parametrize_values_row_type.unwrap_or_default(),
@@ -1542,7 +1518,7 @@ impl Flake8PytestStyleOptions {
.transpose()
.map_err(SettingsError::InvalidRaisesExtendRequireMatchFor)?
.unwrap_or_default(),
mark_parentheses: self.mark_parentheses.unwrap_or(preview.is_disabled()),
mark_parentheses: self.mark_parentheses.unwrap_or_default(),
})
}
}

View File

@@ -589,7 +589,7 @@ Options:
Ignore any `# noqa` comments
--output-format <OUTPUT_FORMAT>
Output serialization format for violations. The default serialization
format is "full" [env: RUFF_OUTPUT_FORMAT=] [possible values: text,
format is "full" [env: RUFF_OUTPUT_FORMAT=] [possible values:
concise, full, json, json-lines, junit, grouped, github, gitlab,
pylint, rdjson, azure, sarif]
-o, --output-file <OUTPUT_FILE>

View File

@@ -78,7 +78,7 @@ Ruff can be used as a [pre-commit](https://pre-commit.com) hook via [`ruff-pre-c
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
rev: v0.7.0
hooks:
# Run the linter.
- id: ruff
@@ -91,7 +91,7 @@ To enable lint fixes, add the `--fix` argument to the lint hook:
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
rev: v0.7.0
hooks:
# Run the linter.
- id: ruff
@@ -105,7 +105,7 @@ To run the hooks over Jupyter Notebooks too, add `jupyter` to the list of allowe
```yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
# Ruff version.
rev: v0.6.9
rev: v0.7.0
hooks:
# Run the linter.
- id: ruff

View File

@@ -4,7 +4,7 @@ build-backend = "maturin"
[project]
name = "ruff"
version = "0.6.9"
version = "0.7.0"
description = "An extremely fast Python linter and code formatter, written in Rust."
authors = [{ name = "Astral Software Inc.", email = "hey@astral.sh" }]
readme = "README.md"

74
ruff.schema.json generated
View File

@@ -16,17 +16,6 @@
"minLength": 1
}
},
"allowed-unused-imports": {
"description": "A list of modules which is allowed even though they are not used in the code.\n\nThis is useful when a module has a side effect when imported.",
"deprecated": true,
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"analyze": {
"description": "Options to configure import map generation.",
"anyOf": [
@@ -702,18 +691,6 @@
"type": "string"
}
},
"tab-size": {
"description": "The number of spaces a tab is equal to when enforcing long-line violations (like `E501`) or formatting code with the formatter.\n\nThis option changes the number of spaces inserted by the formatter when using soft-tabs (`indent-style = space`).",
"deprecated": true,
"anyOf": [
{
"$ref": "#/definitions/IndentWidth"
},
{
"type": "null"
}
]
},
"target-version": {
"description": "The minimum Python version to target, e.g., when considering automatic code upgrades, like rewriting type annotations. Ruff will not propose changes using features that are not available in the given version.\n\nFor example, to represent supporting Python >=3.10 or ==3.10 specify `target-version = \"py310\"`.\n\nIf you're already using a `pyproject.toml` file, we recommend `project.requires-python` instead, as it's based on Python packaging standards, and will be respected by other tools. For example, Ruff treats the following as identical to `target-version = \"py38\"`:\n\n```toml [project] requires-python = \">=3.8\" ```\n\nIf both are specified, `target-version` takes precedence over `requires-python`.\n\nNote that a stub file can [sometimes make use of a typing feature](https://typing.readthedocs.io/en/latest/spec/distributing.html#syntax) before it is available at runtime, as long as the stub does not make use of new *syntax*. For example, a type checker will understand `int | str` in a stub as being a `Union` type annotation, even if the type checker is run using Python 3.9, despite the fact that the `|` operator can only be used to create union types at runtime on Python 3.10+. As such, Ruff will often recommend newer features in a stub file than it would for an equivalent runtime file with the same target version.",
"anyOf": [
@@ -1898,16 +1875,6 @@
"minLength": 1
}
},
"allowed-unused-imports": {
"description": "A list of modules which is allowed even though they are not used in the code.\n\nThis is useful when a module has a side effect when imported.",
"type": [
"array",
"null"
],
"items": {
"type": "string"
}
},
"dummy-variable-rgx": {
"description": "A regular expression used to identify \"dummy\" variables, or those which should be ignored when enforcing (e.g.) unused-variable rules. The default expression matches `_`, `__`, and `_var`, but not `_var_`.",
"type": [
@@ -2423,31 +2390,20 @@
"type": "string"
},
"OutputFormat": {
"oneOf": [
{
"type": "string",
"enum": [
"concise",
"full",
"json",
"json-lines",
"junit",
"grouped",
"github",
"gitlab",
"pylint",
"rdjson",
"azure",
"sarif"
]
},
{
"deprecated": true,
"type": "string",
"enum": [
"text"
]
}
"type": "string",
"enum": [
"concise",
"full",
"json",
"json-lines",
"junit",
"grouped",
"github",
"gitlab",
"pylint",
"rdjson",
"azure",
"sarif"
]
},
"ParametrizeNameType": {
@@ -4053,11 +4009,11 @@
"TRY2",
"TRY20",
"TRY201",
"TRY203",
"TRY3",
"TRY30",
"TRY300",
"TRY301",
"TRY302",
"TRY4",
"TRY40",
"TRY400",

View File

@@ -1,6 +1,6 @@
[tool.poetry]
name = "scripts"
version = "0.6.9"
version = "0.7.0"
description = ""
authors = ["Charles Marsh <charlie.r.marsh@gmail.com>"]