Compare commits

...

19 Commits

Author SHA1 Message Date
Zanie
fedca811ed Switch from if let to match 2024-01-30 13:57:11 -06:00
Zanie
4ba3ee334b Display deprecation warnings for prefix and linter selections with all rules deprecated 2024-01-30 13:52:32 -06:00
Zanie
7e763cf84d Lint 2024-01-30 13:51:18 -06:00
Zanie
e5bf2301bb Add handling for rules that are both deprecated and redirected 2024-01-30 13:11:31 -06:00
Zanie
c7e40e6dc1 Mark PGH rules as deprecated 2024-01-30 12:12:39 -06:00
Zanie Blue
761e148308 Add rule removal infrastructure (#9691)
Similar to https://github.com/astral-sh/ruff/pull/9689 — retains removed
rules for better error messages and documentation but removed rules
_cannot_ be used in any context.

Removes PLR1706 as a useful test case and something we want to
accomplish in #9680 anyway. The rule was in preview so we do not need to
deprecate it first.

Closes https://github.com/astral-sh/ruff/issues/9007

## Test plan

<img width="1110" alt="Rules table"
src="https://github.com/astral-sh/ruff/assets/2586601/ac9fa682-623c-44aa-8e51-d8ab0d308355">

<img width="1110" alt="Rule page"
src="https://github.com/astral-sh/ruff/assets/2586601/05850b2d-7ca5-49bb-8df8-bb931bab25cd">
2024-01-30 12:04:06 -06:00
Zanie Blue
5c75da980f Add rule deprecation infrastructure (#9689)
Adds a new `Deprecated` rule group in addition to `Stable` and
`Preview`.

Deprecated rules:
- Warn on explicit selection without preview
- Error on explicit selection with preview
- Are excluded when selected by prefix with preview

Deprecates `TRY200`, `ANN101`, and `ANN102` as a proof of concept. We
can consider deprecating them separately.
2024-01-30 12:04:06 -06:00
Zanie Blue
747728beca Remove the NURSERY selector from the json schema (#9695) 2024-01-30 12:04:06 -06:00
Zanie Blue
897b7f75b9 Always request the concise output format during ecosystem checks (#9708)
Fixes a regression in the ecosystem checks from
https://github.com/astral-sh/ruff/pull/9687 which was causing them to
run for multiple hours due to the size of the output.

We need the concise format for comparisons.

We should probably update the ecosystem checks to actually diff the full
output in the future because that'd be nice.
2024-01-30 12:04:06 -06:00
Zanie Blue
07c6a3e672 Error if nursery rules are selected without preview (#9683)
Extends #9682 to error if the nursery selector is used or nursery rules
are selected without preview.

Part of #7992 — we will remove this in 0.3.0 instead so we can provide
nice errors in 0.2.0.
2024-01-30 12:04:06 -06:00
Jane Lewis
57576fa139 Replace --show-source and --no-show-source with --output_format=<full|concise> (#9687)
Fixes #7350

## Summary

* `--show-source` and `--no-show-source` are now deprecated.
* `output-format` supports two new variants, `full` and `concise`.
`text` is now a deprecated variant, and any use of it is treated as the
default serialization format.
* `--output-format` now default to `concise`
* In preview mode, `--output-format` defaults to `full`
* `--show-source` will still set `--output-format` to `full` if the
output format is not otherwise specified.
* likewise, `--no-show-source` can override an output format that was
set in a file-based configuration, though it will also be overridden by
`--output-format`

## Test Plan

A lot of tests were updated to use `--output-format=full`. Additional
tests were added to ensure the correct deprecation warnings appeared,
and that deprecated options behaved as intended.
2024-01-30 12:04:06 -06:00
Charlie Marsh
b1c793e2ad Remove preview gating for flake8-simplify rules (#9686)
## Summary

Un-gates detecting `dict.get` rewrites in `if` expressions (rather than
just `if` statements).
2024-01-30 12:04:06 -06:00
Charlie Marsh
9fca4d830e Remove preview gating for flake8-pie rules (#9684)
## Summary

Both of the preview behaviors gated here seem like improvements, so
let's make them stable in v0.2.0
2024-01-30 12:04:06 -06:00
Charlie Marsh
d318a27b0f Remove preview gating for pycodestyle rules (#9685)
## Summary

Un-gates the behavior to allow `sys.path` modifications between imports,
which removed a bunch of false positives in the ecosystem CI at the
time.
2024-01-30 12:04:06 -06:00
Zanie
002d040c41 Remove preview gating for newly-added stable fixes (#9681)
## Summary

At present, our versioning policy forbids the addition of safe fixes to
stable rules outside of a minor release, so we've accumulated a bunch of
new fixes that are behind `--preview`, and can be ungated in v0.2.0.

To find these, I just grepped for `preview.is_enabled()` and identified
all such cases. I then audited the `preview_rules` test fixtures and
removed any tests that existed only to test this autofix behavior.
# Conflicts:
#	crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__SIM114_SIM114.py.snap
#	crates/ruff_linter/src/rules/flake8_simplify/snapshots/ruff_linter__rules__flake8_simplify__tests__preview__SIM114_SIM114.py.snap
2024-01-30 12:04:02 -06:00
Charlie Marsh
432b4da27b Recategorize static-key-dict-comprehension from RUF011 to B035 (#9428)
## Summary

This rule was added to flake8-bugbear. In general, we tend to prefer
redirecting to prominent plugins when our own rules are reimplemented
(since more projects have `B` activated than `RUF`).

## Test Plan

`cargo test`
2024-01-30 12:00:45 -06:00
Charlie Marsh
7992caed37 [flake8-pyi] Mark unaliased-collections-abc-set-import fix as safe (#9679)
## Summary

Prompted by
https://github.com/astral-sh/ruff/issues/8482#issuecomment-1859299411.
The rename is only unsafe when the symbol is exported, so we can narrow
the conditions.
2024-01-30 12:00:45 -06:00
Micha Reiser
4c8d1fe0e4 Add deprecation message for top-level lint settings (#9582) 2024-01-30 12:00:45 -06:00
Micha Reiser
8e8c632409 Promote lint. settings over top-level settings (#9476) 2024-01-30 12:00:45 -06:00
202 changed files with 3863 additions and 4752 deletions

View File

@@ -11,7 +11,7 @@ use ruff_linter::settings::types::{
ExtensionPair, FilePattern, PatternPrefixPair, PerFileIgnore, PreviewMode, PythonVersion,
SerializationFormat, UnsafeFixes,
};
use ruff_linter::{RuleParser, RuleSelector, RuleSelectorParser};
use ruff_linter::{warn_user, RuleParser, RuleSelector, RuleSelectorParser};
use ruff_workspace::configuration::{Configuration, RuleSelection};
use ruff_workspace::options::PycodestyleOptions;
use ruff_workspace::resolver::ConfigurationTransformer;
@@ -104,6 +104,7 @@ pub struct CheckCommand {
no_unsafe_fixes: bool,
/// Show violations with source code.
/// Use `--no-show-source` to disable.
/// (Deprecated: use `--output-format=full` or `--output-format=concise` instead of `--show-source` and `--no-show-source`, respectively)
#[arg(long, overrides_with("no_show_source"))]
show_source: bool,
#[clap(long, overrides_with("show_source"), hide = true)]
@@ -131,6 +132,8 @@ pub struct CheckCommand {
ignore_noqa: bool,
/// Output serialization format for violations.
/// The default serialization format is "concise".
/// In preview mode, the default serialization format is "full".
#[arg(long, value_enum, env = "RUFF_OUTPUT_FORMAT")]
pub output_format: Option<SerializationFormat>,
@@ -533,7 +536,6 @@ impl CheckCommand {
self.no_respect_gitignore,
),
select: self.select,
show_source: resolve_bool_arg(self.show_source, self.no_show_source),
target_version: self.target_version,
unfixable: self.unfixable,
// TODO(charlie): Included in `pyproject.toml`, but not inherited.
@@ -543,7 +545,11 @@ 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: self.output_format,
output_format: resolve_output_format(
self.output_format,
resolve_bool_arg(self.show_source, self.no_show_source),
resolve_bool_arg(self.preview, self.no_preview).unwrap_or_default(),
),
show_fixes: resolve_bool_arg(self.show_fixes, self.no_show_fixes),
extension: self.extension,
},
@@ -594,6 +600,43 @@ fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
}
}
fn resolve_output_format(
output_format: Option<SerializationFormat>,
show_sources: Option<bool>,
preview: bool,
) -> Option<SerializationFormat> {
Some(match (output_format, show_sources) {
(Some(o), None) => o,
(Some(SerializationFormat::Grouped), Some(true)) => {
warn_user!("`--show-source` with `--output-format=grouped` is deprecated, and will not show source files. Use `--output-format=full` to show source information.");
SerializationFormat::Grouped
}
(Some(fmt), Some(true)) => {
warn_user!("The `--show-source` argument is deprecated and has been ignored in favor of `--output-format={fmt}`.");
fmt
}
(Some(fmt), Some(false)) => {
warn_user!("The `--no-show-source` argument is deprecated and has been ignored in favor of `--output-format={fmt}`.");
fmt
}
(None, Some(true)) => {
warn_user!("The `--show-source` argument is deprecated. Use `--output-format=full` instead.");
SerializationFormat::Full
}
(None, Some(false)) => {
warn_user!("The `--no-show-source` argument is deprecated. Use `--output-format=concise` instead.");
SerializationFormat::Concise
}
(None, None) => return None
}).map(|format| match format {
SerializationFormat::Text => {
warn_user!("`--output-format=text` is deprecated. Use `--output-format=full` or `--output-format=concise` instead. `text` will be treated as `{}`.", SerializationFormat::default(preview));
SerializationFormat::default(preview)
},
other => other
})
}
/// CLI settings that are distinct from configuration (commands, lists of files,
/// etc.).
#[allow(clippy::struct_excessive_bools)]
@@ -648,7 +691,6 @@ pub struct CliOverrides {
pub preview: Option<PreviewMode>,
pub respect_gitignore: Option<bool>,
pub select: Option<Vec<RuleSelector>>,
pub show_source: Option<bool>,
pub target_version: Option<PythonVersion>,
pub unfixable: Option<Vec<RuleSelector>>,
// TODO(charlie): Captured in pyproject.toml as a default, but not part of `Settings`.
@@ -735,9 +777,6 @@ impl ConfigurationTransformer for CliOverrides {
if let Some(respect_gitignore) = &self.respect_gitignore {
config.respect_gitignore = Some(*respect_gitignore);
}
if let Some(show_source) = &self.show_source {
config.show_source = Some(*show_source);
}
if let Some(show_fixes) = &self.show_fixes {
config.show_fixes = Some(*show_fixes);
}

View File

@@ -255,7 +255,6 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
unsafe_fixes,
output_format,
show_fixes,
show_source,
..
} = pyproject_config.settings;
@@ -284,9 +283,6 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
if show_fixes {
printer_flags |= PrinterFlags::SHOW_FIX_SUMMARY;
}
if show_source {
printer_flags |= PrinterFlags::SHOW_SOURCE;
}
if cli.ecosystem_ci {
warn_user!(
"The formatting of fixes emitted by this option is a work-in-progress, subject to \
@@ -325,9 +321,14 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
printer_flags,
);
let preview = overrides.preview.unwrap_or_default().is_enabled();
if cli.watch {
if output_format != SerializationFormat::Text {
warn_user!("`--output-format text` is always used in watch mode.");
if output_format != SerializationFormat::default(preview) {
warn_user!(
"`--output-format {}` is always used in watch mode.",
SerializationFormat::default(preview)
);
}
// Configure the file watcher.
@@ -353,7 +354,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
fix_mode,
unsafe_fixes,
)?;
printer.write_continuously(&mut writer, &messages)?;
printer.write_continuously(&mut writer, &messages, preview)?;
// In watch mode, we may need to re-resolve the configuration.
// TODO(charlie): Re-compute other derivative values, like the `printer`.
@@ -386,7 +387,7 @@ pub fn check(args: CheckCommand, log_level: LogLevel) -> Result<ExitStatus> {
fix_mode,
unsafe_fixes,
)?;
printer.write_continuously(&mut writer, &messages)?;
printer.write_continuously(&mut writer, &messages, preview)?;
}
Err(err) => return Err(err.into()),
}

View File

@@ -27,8 +27,6 @@ bitflags! {
pub(crate) struct Flags: u8 {
/// Whether to show violations when emitting diagnostics.
const SHOW_VIOLATIONS = 0b0000_0001;
/// Whether to show the source code when emitting diagnostics.
const SHOW_SOURCE = 0b000_0010;
/// Whether to show a summary of the fixed violations when emitting diagnostics.
const SHOW_FIX_SUMMARY = 0b0000_0100;
/// Whether to show a diff of each fixed violation when emitting diagnostics.
@@ -218,7 +216,10 @@ impl Printer {
if !self.flags.intersects(Flags::SHOW_VIOLATIONS) {
if matches!(
self.format,
SerializationFormat::Text | SerializationFormat::Grouped
SerializationFormat::Text
| SerializationFormat::Full
| SerializationFormat::Concise
| SerializationFormat::Grouped
) {
if self.flags.intersects(Flags::SHOW_FIX_SUMMARY) {
if !diagnostics.fixed.is_empty() {
@@ -245,11 +246,12 @@ impl Printer {
SerializationFormat::Junit => {
JunitEmitter.emit(writer, &diagnostics.messages, &context)?;
}
SerializationFormat::Text => {
SerializationFormat::Concise
| SerializationFormat::Full => {
TextEmitter::default()
.with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
.with_show_fix_diff(self.flags.intersects(Flags::SHOW_FIX_DIFF))
.with_show_source(self.flags.intersects(Flags::SHOW_SOURCE))
.with_show_source(self.format == SerializationFormat::Full)
.with_unsafe_fixes(self.unsafe_fixes)
.emit(writer, &diagnostics.messages, &context)?;
@@ -265,7 +267,6 @@ impl Printer {
}
SerializationFormat::Grouped => {
GroupedEmitter::default()
.with_show_source(self.flags.intersects(Flags::SHOW_SOURCE))
.with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
.with_unsafe_fixes(self.unsafe_fixes)
.emit(writer, &diagnostics.messages, &context)?;
@@ -294,6 +295,7 @@ impl Printer {
SerializationFormat::Sarif => {
SarifEmitter.emit(writer, &diagnostics.messages, &context)?;
}
SerializationFormat::Text => unreachable!("Text is deprecated and should have been automatically converted to the default serialization format")
}
writer.flush()?;
@@ -342,7 +344,9 @@ impl Printer {
}
match self.format {
SerializationFormat::Text => {
SerializationFormat::Text
| SerializationFormat::Full
| SerializationFormat::Concise => {
// Compute the maximum number of digits in the count and code, for all messages,
// to enable pretty-printing.
let count_width = num_digits(
@@ -403,6 +407,7 @@ impl Printer {
&self,
writer: &mut dyn Write,
diagnostics: &Diagnostics,
preview: bool,
) -> Result<()> {
if matches!(self.log_level, LogLevel::Silent) {
return Ok(());
@@ -430,7 +435,7 @@ impl Printer {
let context = EmitterContext::new(&diagnostics.notebook_indexes);
TextEmitter::default()
.with_show_fix_status(show_fix_status(self.fix_mode, fixables.as_ref()))
.with_show_source(self.flags.intersects(Flags::SHOW_SOURCE))
.with_show_source(preview)
.with_unsafe_fixes(self.unsafe_fixes)
.emit(writer, &diagnostics.messages, &context)?;
}

View File

@@ -0,0 +1,149 @@
//! A test suite that ensures deprecated command line options have appropriate warnings / behaviors
use ruff_linter::settings::types::SerializationFormat;
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(show_source: Option<bool>, output_format: Option<String>) -> Command {
let mut cmd = Command::new(get_cargo_bin(BIN_NAME));
let output_format = output_format.unwrap_or(format!("{}", SerializationFormat::default(false)));
cmd.arg("--output-format");
cmd.arg(output_format);
cmd.arg("--no-cache");
match show_source {
Some(true) => {
cmd.arg("--show-source");
}
Some(false) => {
cmd.arg("--no-show-source");
}
None => {}
}
cmd.arg("-");
cmd
}
#[test]
fn ensure_show_source_is_deprecated() {
assert_cmd_snapshot!(ruff_check(Some(true), None).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: The `--show-source` argument is deprecated and has been ignored in favor of `--output-format=concise`.
"###);
}
#[test]
fn ensure_no_show_source_is_deprecated() {
assert_cmd_snapshot!(ruff_check(Some(false), None).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: The `--no-show-source` argument is deprecated and has been ignored in favor of `--output-format=concise`.
"###);
}
#[test]
fn ensure_output_format_is_deprecated() {
assert_cmd_snapshot!(ruff_check(None, Some("text".into())).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: `--output-format=text` is deprecated. Use `--output-format=full` or `--output-format=concise` instead. `text` will be treated as `concise`.
"###);
}
#[test]
fn ensure_output_format_overrides_show_source() {
assert_cmd_snapshot!(ruff_check(Some(true), Some("concise".into())).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: The `--show-source` argument is deprecated and has been ignored in favor of `--output-format=concise`.
"###);
}
#[test]
fn ensure_full_output_format_overrides_no_show_source() {
assert_cmd_snapshot!(ruff_check(Some(false), Some("full".into())).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
|
1 | l = 1
| ^ E741
|
Found 1 error.
----- stderr -----
warning: The `--no-show-source` argument is deprecated and has been ignored in favor of `--output-format=full`.
"###);
}
#[test]
fn ensure_output_format_uses_concise_over_no_show_source() {
assert_cmd_snapshot!(ruff_check(Some(false), Some("concise".into())).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: The `--no-show-source` argument is deprecated and has been ignored in favor of `--output-format=concise`.
"###);
}
#[test]
fn ensure_deprecated_output_format_overrides_show_source() {
assert_cmd_snapshot!(ruff_check(Some(true), Some("text".into())).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: The `--show-source` argument is deprecated and has been ignored in favor of `--output-format=text`.
warning: `--output-format=text` is deprecated. Use `--output-format=full` or `--output-format=concise` instead. `text` will be treated as `concise`.
"###);
}
#[test]
fn ensure_deprecated_output_format_overrides_no_show_source() {
assert_cmd_snapshot!(ruff_check(Some(false), Some("text".into())).pass_stdin(STDIN), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
Found 1 error.
----- stderr -----
warning: The `--no-show-source` argument is deprecated and has been ignored in favor of `--output-format=text`.
warning: `--output-format=text` is deprecated. Use `--output-format=full` or `--output-format=concise` instead. `text` will be treated as `concise`.
"###);
}

View File

@@ -508,6 +508,11 @@ if __name__ == '__main__':
say_hy("dear Ruff contributor")
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
- 'ignore' -> 'lint.ignore'
"###);
Ok(())
}
@@ -546,6 +551,11 @@ if __name__ == '__main__':
say_hy("dear Ruff contributor")
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
- 'ignore' -> 'lint.ignore'
"###);
Ok(())
}

View File

@@ -31,25 +31,14 @@ fn ruff_cmd() -> Command {
}
/// Builder for `ruff check` commands.
#[derive(Debug)]
#[derive(Debug, Default)]
struct RuffCheck<'a> {
output_format: &'a str,
output_format: Option<&'a str>,
config: Option<&'a Path>,
filename: Option<&'a str>,
args: Vec<&'a str>,
}
impl<'a> Default for RuffCheck<'a> {
fn default() -> RuffCheck<'a> {
RuffCheck {
output_format: "text",
config: None,
filename: None,
args: vec![],
}
}
}
impl<'a> RuffCheck<'a> {
/// Set the `--config` option.
#[must_use]
@@ -61,7 +50,7 @@ impl<'a> RuffCheck<'a> {
/// Set the `--output-format` option.
#[must_use]
fn output_format(mut self, format: &'a str) -> Self {
self.output_format = format;
self.output_format = Some(format);
self
}
@@ -82,7 +71,11 @@ impl<'a> RuffCheck<'a> {
/// Generate a [`Command`] for the `ruff check` command.
fn build(self) -> Command {
let mut cmd = ruff_cmd();
cmd.args(["--output-format", self.output_format, "--no-cache"]);
if let Some(output_format) = self.output_format {
cmd.args(["--output-format", output_format]);
}
cmd.arg("--no-cache");
if let Some(path) = self.config {
cmd.arg("--config");
cmd.arg(path);
@@ -743,8 +736,28 @@ fn stdin_parse_error() {
}
#[test]
fn show_source() {
let mut cmd = RuffCheck::default().args(["--show-source"]).build();
fn full_output_preview() {
let mut cmd = RuffCheck::default().args(["--preview"]).build();
assert_cmd_snapshot!(cmd
.pass_stdin("l = 1"), @r###"
success: false
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `l`
|
1 | l = 1
| ^ E741
|
Found 1 error.
----- stderr -----
"###);
}
#[test]
fn full_output_format() {
let mut cmd = RuffCheck::default().output_format("full").build();
assert_cmd_snapshot!(cmd
.pass_stdin("l = 1"), @r###"
success: false
@@ -839,14 +852,12 @@ fn nursery_direct() {
assert_cmd_snapshot!(cmd
.pass_stdin("I=42\n"), @r###"
success: false
exit_code: 1
exit_code: 2
----- stdout -----
-:1:2: E225 [*] Missing whitespace around operator
Found 1 error.
[*] 1 fixable with the `--fix` option.
----- stderr -----
warning: Selection of nursery rule `E225` without the `--preview` flag is deprecated.
ruff failed
Cause: Selection of unstable rule `E225` without the `--preview` flag is not allowed.
"###);
}
@@ -857,15 +868,12 @@ fn nursery_group_selector() {
assert_cmd_snapshot!(cmd
.pass_stdin("I=42\n"), @r###"
success: false
exit_code: 1
exit_code: 2
----- stdout -----
-:1:1: CPY001 Missing copyright notice at top of file
-:1:2: E225 [*] Missing whitespace around operator
Found 2 errors.
[*] 1 fixable with the `--fix` option.
----- stderr -----
warning: The `NURSERY` selector has been deprecated. Use the `--preview` flag instead.
ruff failed
Cause: The `NURSERY` selector was removed. Use the `--preview` flag instead.
"###);
}
@@ -883,7 +891,7 @@ fn nursery_group_selector_preview_enabled() {
----- stderr -----
ruff failed
Cause: The `NURSERY` selector is deprecated and cannot be used with preview mode enabled.
Cause: The `NURSERY` selector was removed. Unstable rules should be selected individually or by their respective groups.
"###);
}
@@ -899,7 +907,18 @@ fn preview_enabled_prefix() {
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `I`
|
1 | I=42
| ^ E741
|
-:1:2: E225 [*] Missing whitespace around operator
|
1 | I=42
| ^ E225
|
= help: Add missing whitespace
Found 2 errors.
[*] 1 fixable with the `--fix` option.
@@ -918,9 +937,30 @@ fn preview_enabled_all() {
exit_code: 1
----- stdout -----
-:1:1: E741 Ambiguous variable name: `I`
|
1 | I=42
| ^ E741
|
-:1:1: D100 Missing docstring in public module
|
1 | I=42
| D100
|
-:1:1: CPY001 Missing copyright notice at top of file
|
1 | I=42
| CPY001
|
-:1:2: E225 [*] Missing whitespace around operator
|
1 | I=42
| ^ E225
|
= help: Add missing whitespace
Found 4 errors.
[*] 1 fixable with the `--fix` option.
@@ -942,6 +982,12 @@ fn preview_enabled_direct() {
exit_code: 1
----- stdout -----
-:1:2: E225 [*] Missing whitespace around operator
|
1 | I=42
| ^ E225
|
= help: Add missing whitespace
Found 1 error.
[*] 1 fixable with the `--fix` option.
@@ -1049,6 +1095,317 @@ fn preview_enabled_group_ignore() {
"###);
}
#[test]
fn removed_direct() {
// Selection of a removed rule should fail
let mut cmd = RuffCheck::default().args(["--select", "PLR1706"]).build();
assert_cmd_snapshot!(cmd, @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Rule `PLR1706` was removed and cannot be selected.
"###);
}
#[test]
fn removed_indirect() {
// Selection _including_ a removed rule without matching should not fail
// nor should the rule be used
let mut cmd = RuffCheck::default().args(["--select", "PLR"]).build();
assert_cmd_snapshot!(cmd.pass_stdin(r###"
# This would have been a PLR1706 violation
x, y = 1, 2
maximum = x >= y and x or y
"""###), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
"###);
}
#[test]
fn deprecated_direct() {
// Selection of a deprecated rule without preview enabled should still work
// but a warning should be displayed
let mut cmd = RuffCheck::default().args(["--select", "TRY200"]).build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
def reciprocal(n):
try:
return 1 / n
except ZeroDivisionError:
raise ValueError
"###), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The rule `TRY200` is deprecated and will be removed in a future release.
"###);
}
#[test]
fn deprecated_multiple_direct() {
let mut cmd = RuffCheck::default()
.args(["--select", "ANN101", "--select", "ANN102"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
class Foo:
def a(self):
pass
@classmethod
def b(cls):
pass
"###), @r###"
success: false
exit_code: 1
----- stdout -----
-:3:11: ANN101 Missing type annotation for `self` in method
-:7:11: ANN102 Missing type annotation for `cls` in classmethod
Found 2 errors.
----- stderr -----
warning: The rule `ANN102` is deprecated and will be removed in a future release.
warning: The rule `ANN101` is deprecated and will be removed in a future release.
"###);
}
#[test]
fn deprecated_indirect() {
// `ANN` includes deprecated rules `ANN101` and `ANN102` but should not warn
// since it is not a "direct" selection
let mut cmd = RuffCheck::default().args(["--select", "ANN"]).build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
class Foo:
def a(self):
pass
@classmethod
def b(cls):
pass
"###), @r###"
success: false
exit_code: 1
----- stdout -----
-:3:9: ANN201 Missing return type annotation for public function `a`
-:3:11: ANN101 Missing type annotation for `self` in method
-:7:9: ANN206 Missing return type annotation for classmethod `b`
-:7:11: ANN102 Missing type annotation for `cls` in classmethod
Found 4 errors.
No fixes available (2 hidden fixes can be enabled with the `--unsafe-fixes` option).
----- stderr -----
"###);
}
#[test]
fn deprecated_prefix() {
// `ANN1` only includes deprecated rules `ANN101` and `ANN102` so it should warn
let mut cmd = RuffCheck::default().args(["--select", "ANN1"]).build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
class Foo:
def a(self):
pass
@classmethod
def b(cls):
pass
"###), @r###"
success: false
exit_code: 1
----- stdout -----
-:3:11: ANN101 Missing type annotation for `self` in method
-:7:11: ANN102 Missing type annotation for `cls` in classmethod
Found 2 errors.
----- stderr -----
warning: The rule prefix `ANN1` is deprecated and will be removed in a future release.
"###);
}
#[test]
fn deprecated_redirected() {
// Selection of a redirected deprecated rule without preview enabled should still work
// but a warning should be displayed
let mut cmd = RuffCheck::default().args(["--select", "PGH001"]).build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
x = eval(input("Enter a number: "))
"###), @r###"
success: false
exit_code: 1
----- stdout -----
-:2:5: S307 Use of possibly insecure function; consider using `ast.literal_eval`
Found 1 error.
----- stderr -----
warning: The rule `PGH001` is deprecated and will be removed in a future release. Use `S307` instead.
"###);
}
#[test]
fn deprecated_direct_preview_enabled() {
// Direct selection of a deprecated rule in preview should fail
let mut cmd = RuffCheck::default()
.args(["--select", "TRY200", "--preview"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
def reciprocal(n):
try:
return 1 / n
except ZeroDivisionError:
raise ValueError
"###), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Selection of deprecated rule `TRY200` is not allowed when preview mode is enabled.
"###);
}
#[test]
fn deprecated_redirect_preview_enabled() {
// Direct selection of a deprecated rule in preview should fail
let mut cmd = RuffCheck::default()
.args(["--select", "PGH001", "--preview"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
x = eval(input("Enter a number: "))
"###), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Selection of deprecated rule `PGH001` is not allowed when preview mode is enabled. Use `S307` instead.
"###);
}
#[test]
fn deprecated_indirect_preview_enabled() {
// `TRY200` is deprecated and should be off by default in preview.
let mut cmd = RuffCheck::default()
.args(["--select", "TRY", "--preview"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
def reciprocal(n):
try:
return 1 / n
except ZeroDivisionError:
raise ValueError
"###), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
"###);
}
#[test]
fn deprecated_linter_preview_enabled() {
// e.g. all the rules in `PGH` are and should fail in preview
let mut cmd = RuffCheck::default()
.args(["--select", "PGH", "--preview"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
x = eval(input("Enter a number: "))
"###), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Selection of deprecated rule category `PGH` is not allowed when preview mode is enabled.
"###);
}
#[test]
fn deprecated_multiple_direct_preview_enabled() {
// Direct selection of the deprecated rules in preview should fail with
// a message listing all of the rule codes
let mut cmd = RuffCheck::default()
.args(["--select", "ANN101", "--select", "ANN102", "--preview"])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
def reciprocal(n):
try:
return 1 / n
except ZeroDivisionError:
raise ValueError
"###), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Selection of deprecated rules is not allowed when preview mode is enabled. Remove selection of:
- ANN102
- ANN101
"###);
}
#[test]
fn deprecated_multiple_direct_and_redirected_preview_enabled() {
// Direct selection of the deprecated rules in preview should fail with
// a message listing all of the rule codes
// The redirected rules should include an alternative
let mut cmd = RuffCheck::default()
.args([
"--select",
"ANN101",
"--select",
"ANN102",
"--select",
"PGH001",
"--preview",
])
.build();
assert_cmd_snapshot!(cmd
.pass_stdin(r###"
x = eval(input("Enter a number: "))
def reciprocal(n):
try:
return 1 / n
except ZeroDivisionError:
raise ValueError
"###), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
ruff failed
Cause: Selection of deprecated rules is not allowed when preview mode is enabled. Remove selection of:
- ANN102
- ANN101
- PGH001 (use `S307` instead)
"###);
}
/// An unreadable pyproject.toml in non-isolated mode causes ruff to hard-error trying to build up
/// configuration globs
#[cfg(unix)]

View File

@@ -11,7 +11,7 @@ use insta_cmd::{assert_cmd_snapshot, get_cargo_bin};
use tempfile::TempDir;
const BIN_NAME: &str = "ruff";
const STDIN_BASE_OPTIONS: &[&str] = &["--no-cache", "--output-format", "text"];
const STDIN_BASE_OPTIONS: &[&str] = &["--no-cache", "--output-format", "concise"];
#[test]
fn top_level_options() -> Result<()> {
@@ -44,6 +44,11 @@ inline-quotes = "single"
[*] 2 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
- 'flake8-quotes' -> 'lint.flake8-quotes'
"###);
Ok(())
}
@@ -114,6 +119,10 @@ inline-quotes = "single"
[*] 2 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
"###);
Ok(())
}
@@ -153,6 +162,10 @@ inline-quotes = "single"
[*] 2 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'flake8-quotes' -> 'lint.flake8-quotes'
"###);
Ok(())
}
@@ -228,6 +241,10 @@ OTHER = "OTHER"
[*] 3 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
"###);
Ok(())
}
@@ -271,6 +288,10 @@ if __name__ == "__main__":
[*] 2 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
"###);
Ok(())
}
@@ -309,6 +330,11 @@ _ = "---------------------------------------------------------------------------
Found 1 error.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'select' -> 'lint.select'
- 'pycodestyle' -> 'lint.pycodestyle'
"###);
Ok(())
}
@@ -351,6 +377,10 @@ if __name__ == "__main__":
[*] 1 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
"###);
Ok(())
}
@@ -393,6 +423,10 @@ if __name__ == "__main__":
[*] 1 fixable with the `--fix` option.
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'extend-select' -> 'lint.extend-select'
"###);
Ok(())
}

View File

@@ -39,6 +39,10 @@ fn check_project_include_defaults() {
[BASEPATH]/include-test/subdirectory/c.py
----- stderr -----
warning: The top-level linter settings are deprecated in favour of their counterparts in the `lint` section. Please update the following options in your configuration:
- 'select' -> 'lint.select'
"###);
});
}

View File

@@ -51,7 +51,7 @@ else:
```
## Options
- `pyflakes.extend-generics`
- `lint.pyflakes.extend-generics`
## References
- [Python documentation: `import`](https://docs.python.org/3/reference/simple_stmts.html#the-import-statement)

View File

@@ -17,9 +17,8 @@ Settings path: "[BASEPATH]/pyproject.toml"
cache_dir = "[BASEPATH]/.ruff_cache"
fix = false
fix_only = false
output_format = text
output_format = concise
show_fixes = false
show_source = false
unsafe_fixes = hint
# File Resolver Settings

View File

@@ -26,9 +26,9 @@ pub(crate) fn main(args: &Args) -> Result<()> {
for rule in Rule::iter() {
if let Some(explanation) = rule.explanation() {
let mut output = String::new();
output.push_str(&format!("# {} ({})", rule.as_ref(), rule.noqa_code()));
output.push('\n');
output.push('\n');
let (linter, _) = Linter::parse_code(&rule.noqa_code().to_string()).unwrap();
if linter.url().is_some() {
@@ -37,6 +37,22 @@ pub(crate) fn main(args: &Args) -> Result<()> {
output.push('\n');
}
if rule.is_deprecated() {
output.push_str(
r"**Warning: This rule is deprecated and will be removed in a future release.**",
);
output.push('\n');
output.push('\n');
}
if rule.is_removed() {
output.push_str(
r"**Warning: This rule has been removed and its documentation is only available for historical reasons.**",
);
output.push('\n');
output.push('\n');
}
let fix_availability = rule.fixable();
if matches!(
fix_availability,
@@ -116,7 +132,7 @@ fn process_documentation(documentation: &str, out: &mut String, rule_name: &str)
}
}
let anchor = option.replace('.', "-");
let anchor = option.replace('.', "_");
out.push_str(&format!("- [`{option}`][{option}]\n"));
after.push_str(&format!("[{option}]: ../settings.md#{anchor}\n"));
@@ -142,13 +158,13 @@ mod tests {
let mut output = String::new();
process_documentation(
"
See also [`mccabe.max-complexity`] and [`task-tags`].
See also [`lint.mccabe.max-complexity`] and [`lint.task-tags`].
Something [`else`][other].
## Options
- `task-tags`
- `mccabe.max-complexity`
- `lint.task-tags`
- `lint.mccabe.max-complexity`
[other]: http://example.com.",
&mut output,
@@ -157,18 +173,18 @@ Something [`else`][other].
assert_eq!(
output,
"
See also [`mccabe.max-complexity`][mccabe.max-complexity] and [`task-tags`][task-tags].
See also [`lint.mccabe.max-complexity`][lint.mccabe.max-complexity] and [`lint.task-tags`][lint.task-tags].
Something [`else`][other].
## Options
- [`task-tags`][task-tags]
- [`mccabe.max-complexity`][mccabe.max-complexity]
- [`lint.task-tags`][lint.task-tags]
- [`lint.mccabe.max-complexity`][lint.mccabe.max-complexity]
[other]: http://example.com.
[task-tags]: ../settings.md#task-tags
[mccabe.max-complexity]: ../settings.md#mccabe-max-complexity
[lint.task-tags]: ../settings.md#lint_task-tags
[lint.mccabe.max-complexity]: ../settings.md#lint_mccabe_max-complexity
"
);
}

View File

@@ -1,6 +1,7 @@
//! Generate a Markdown-compatible listing of configuration options for `pyproject.toml`.
//!
//! Used for <https://docs.astral.sh/ruff/settings/>.
use itertools::Itertools;
use std::fmt::Write;
use ruff_python_trivia::textwrap;
@@ -9,16 +10,29 @@ use ruff_workspace::options_base::{OptionField, OptionSet, OptionsMetadata, Visi
pub(crate) fn generate() -> String {
let mut output = String::new();
generate_set(&mut output, &Set::Toplevel(Options::metadata()));
generate_set(
&mut output,
Set::Toplevel(Options::metadata()),
&mut Vec::new(),
);
output
}
fn generate_set(output: &mut String, set: &Set) {
if set.level() < 2 {
writeln!(output, "### {title}\n", title = set.title()).unwrap();
} else {
writeln!(output, "#### {title}\n", title = set.title()).unwrap();
fn generate_set(output: &mut String, set: Set, parents: &mut Vec<Set>) {
match &set {
Set::Toplevel(_) => {
output.push_str("### Top-level\n");
}
Set::Named { name, .. } => {
let title = parents
.iter()
.filter_map(|set| set.name())
.chain(std::iter::once(name.as_str()))
.join(".");
writeln!(output, "#### `{title}`\n",).unwrap();
}
}
if let Some(documentation) = set.metadata().documentation() {
@@ -35,72 +49,68 @@ fn generate_set(output: &mut String, set: &Set) {
fields.sort_unstable_by(|(name, _), (name2, _)| name.cmp(name2));
sets.sort_unstable_by(|(name, _), (name2, _)| name.cmp(name2));
parents.push(set);
// Generate the fields.
for (name, field) in &fields {
emit_field(output, name, field, set);
emit_field(output, name, field, parents.as_slice());
output.push_str("---\n\n");
}
// Generate all the sub-sets.
for (set_name, sub_set) in &sets {
generate_set(output, &Set::Named(set_name, *sub_set, set.level() + 1));
generate_set(
output,
Set::Named {
name: set_name.to_string(),
set: *sub_set,
},
parents,
);
}
parents.pop();
}
enum Set<'a> {
enum Set {
Toplevel(OptionSet),
Named(&'a str, OptionSet, u32),
Named { name: String, set: OptionSet },
}
impl<'a> Set<'a> {
fn name(&self) -> Option<&'a str> {
impl Set {
fn name(&self) -> Option<&str> {
match self {
Set::Toplevel(_) => None,
Set::Named(name, _, _) => Some(name),
}
}
fn title(&self) -> &'a str {
match self {
Set::Toplevel(_) => "Top-level",
Set::Named(name, _, _) => name,
Set::Named { name, .. } => Some(name),
}
}
fn metadata(&self) -> &OptionSet {
match self {
Set::Toplevel(set) => set,
Set::Named(_, set, _) => set,
}
}
fn level(&self) -> u32 {
match self {
Set::Toplevel(_) => 0,
Set::Named(_, _, level) => *level,
Set::Named { set, .. } => set,
}
}
}
fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set: &Set) {
let header_level = if parent_set.level() < 2 {
"####"
} else {
"#####"
};
fn emit_field(output: &mut String, name: &str, field: &OptionField, parents: &[Set]) {
let header_level = if parents.is_empty() { "####" } else { "#####" };
let parents_anchor = parents.iter().filter_map(|parent| parent.name()).join("_");
if parents_anchor.is_empty() {
output.push_str(&format!(
"{header_level} [`{name}`](#{name}) {{: #{name} }}\n"
));
} else {
output.push_str(&format!(
"{header_level} [`{name}`](#{parents_anchor}_{name}) {{: #{parents_anchor}_{name} }}\n"
));
// if there's a set name, we need to add it to the anchor
if let Some(set_name) = parent_set.name() {
// the anchor used to just be the name, but now it's the group name
// for backwards compatibility, we need to keep the old anchor
output.push_str(&format!("<span id=\"{name}\"></span>\n"));
output.push_str(&format!(
"{header_level} [`{name}`](#{set_name}-{name}) {{: #{set_name}-{name} }}\n"
));
} else {
output.push_str(&format!("{header_level} [`{name}`](#{name})\n"));
}
output.push('\n');
if let Some(deprecated) = &field.deprecated {
@@ -129,12 +139,12 @@ fn emit_field(output: &mut String, name: &str, field: &OptionField, parent_set:
output.push_str("**Example usage**:\n\n");
output.push_str(&format_tab(
"pyproject.toml",
&format_header(field.scope, parent_set, ConfigurationFile::PyprojectToml),
&format_header(field.scope, parents, ConfigurationFile::PyprojectToml),
field.example,
));
output.push_str(&format_tab(
"ruff.toml",
&format_header(field.scope, parent_set, ConfigurationFile::RuffToml),
&format_header(field.scope, parents, ConfigurationFile::RuffToml),
field.example,
));
output.push('\n');
@@ -152,52 +162,22 @@ fn format_tab(tab_name: &str, header: &str, content: &str) -> String {
/// Format the TOML header for the example usage for a given option.
///
/// For example: `[tool.ruff.format]` or `[tool.ruff.lint.isort]`.
fn format_header(
scope: Option<&str>,
parent_set: &Set,
configuration: ConfigurationFile,
) -> String {
match configuration {
ConfigurationFile::PyprojectToml => {
let mut header = if let Some(set_name) = parent_set.name() {
if set_name == "format" {
String::from("tool.ruff.format")
} else {
format!("tool.ruff.lint.{set_name}")
}
} else {
"tool.ruff".to_string()
};
if let Some(scope) = scope {
if !header.is_empty() {
header.push('.');
}
header.push_str(scope);
}
format!("[{header}]")
}
ConfigurationFile::RuffToml => {
let mut header = if let Some(set_name) = parent_set.name() {
if set_name == "format" {
String::from("format")
} else {
format!("lint.{set_name}")
}
} else {
String::new()
};
if let Some(scope) = scope {
if !header.is_empty() {
header.push('.');
}
header.push_str(scope);
}
if header.is_empty() {
String::new()
} else {
format!("[{header}]")
}
}
fn format_header(scope: Option<&str>, parents: &[Set], configuration: ConfigurationFile) -> String {
let tool_parent = match configuration {
ConfigurationFile::PyprojectToml => Some("tool.ruff"),
ConfigurationFile::RuffToml => None,
};
let header = tool_parent
.into_iter()
.chain(parents.iter().filter_map(|parent| parent.name()))
.chain(scope)
.join(".");
if header.is_empty() {
String::new()
} else {
format!("[{header}]")
}
}

View File

@@ -3,6 +3,7 @@
//! Used for <https://docs.astral.sh/ruff/rules/>.
use itertools::Itertools;
use ruff_linter::codes::RuleGroup;
use std::borrow::Cow;
use strum::IntoEnumIterator;
@@ -14,6 +15,10 @@ use ruff_workspace::options_base::OptionsMetadata;
const FIX_SYMBOL: &str = "🛠️";
const PREVIEW_SYMBOL: &str = "🧪";
const REMOVED_SYMBOL: &str = "";
const WARNING_SYMBOL: &str = "⚠️";
const STABLE_SYMBOL: &str = "✔️";
const SPACER: &str = "&nbsp;&nbsp;&nbsp;&nbsp;";
fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>, linter: &Linter) {
table_out.push_str("| Code | Name | Message | |");
@@ -21,20 +26,33 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
table_out.push_str("| ---- | ---- | ------- | ------: |");
table_out.push('\n');
for rule in rules {
let status_token = match rule.group() {
RuleGroup::Removed => {
format!("<span title='Rule has been removed'>{REMOVED_SYMBOL}</span>")
}
RuleGroup::Deprecated => {
format!("<span title='Rule has been deprecated'>{WARNING_SYMBOL}</span>")
}
#[allow(deprecated)]
RuleGroup::Preview | RuleGroup::Nursery => {
format!("<span title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
}
RuleGroup::Stable => {
// A full opacity checkmark is a bit aggressive for indicating stable
format!("<span title='Rule is stable' style='opacity: 0.6'>{STABLE_SYMBOL}</span>")
}
};
let fix_token = match rule.fixable() {
FixAvailability::Always | FixAvailability::Sometimes => {
format!("<span title='Automatic fix available'>{FIX_SYMBOL}</span>")
}
FixAvailability::None => {
format!("<span style='opacity: 0.1' aria-hidden='true'>{FIX_SYMBOL}</span>")
format!("<span title='Automatic fix not available' style='opacity: 0.1' aria-hidden='true'>{FIX_SYMBOL}</span>")
}
};
let preview_token = if rule.is_preview() || rule.is_nursery() {
format!("<span title='Rule is in preview'>{PREVIEW_SYMBOL}</span>")
} else {
format!("<span style='opacity: 0.1' aria-hidden='true'>{PREVIEW_SYMBOL}</span>")
};
let status_token = format!("{fix_token} {preview_token}");
let tokens = format!("{status_token} {fix_token}");
let rule_name = rule.as_ref();
@@ -48,9 +66,20 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
Cow::Borrowed(message)
};
// Start and end of style spans
let mut ss = "";
let mut se = "";
if rule.is_removed() {
ss = "<span style='opacity: 0.5', title='This rule has been removed'>";
se = "</span>";
} else if rule.is_deprecated() {
ss = "<span style='opacity: 0.8', title='This rule has been deprecated'>";
se = "</span>";
}
#[allow(clippy::or_fun_call)]
table_out.push_str(&format!(
"| {0}{1} {{ #{0}{1} }} | {2} | {3} | {4} |",
"| {ss}{0}{1}{se} {{ #{0}{1} }} | {ss}{2}{se} | {ss}{3}{se} | {ss}{4}{se} |",
linter.common_prefix(),
linter.code_for_rule(rule).unwrap(),
rule.explanation()
@@ -58,7 +87,7 @@ fn generate_table(table_out: &mut String, rules: impl IntoIterator<Item = Rule>,
.then_some(format_args!("[{rule_name}](rules/{rule_name}.md)"))
.unwrap_or(format_args!("{rule_name}")),
message,
status_token,
tokens,
));
table_out.push('\n');
}
@@ -69,15 +98,33 @@ pub(crate) fn generate() -> String {
// Generate the table string.
let mut table_out = String::new();
table_out.push_str(&format!(
"The {FIX_SYMBOL} emoji indicates that a rule is automatically fixable by the `--fix` command-line option."));
table_out.push('\n');
table_out.push_str("### Legend");
table_out.push('\n');
table_out.push_str(&format!(
"The {PREVIEW_SYMBOL} emoji indicates that a rule is in [\"preview\"](faq.md#what-is-preview)."
"{SPACER}{STABLE_SYMBOL}{SPACER} The rule is stable."
));
table_out.push('\n');
table_out.push_str("<br />");
table_out.push_str(&format!(
"{SPACER}{PREVIEW_SYMBOL}{SPACER} The rule is unstable and is in [\"preview\"](faq.md#what-is-preview)."
));
table_out.push_str("<br />");
table_out.push_str(&format!(
"{SPACER}{WARNING_SYMBOL}{SPACER} The rule has been deprecated and will be removed in a future release."
));
table_out.push_str("<br />");
table_out.push_str(&format!(
"{SPACER}{REMOVED_SYMBOL}{SPACER} The rule has been removed only the documentation is available."
));
table_out.push_str("<br />");
table_out.push_str(&format!(
"{SPACER}{FIX_SYMBOL}{SPACER} The rule is automatically fixable by the `--fix` command-line option."
));
table_out.push_str("<br />");
table_out.push('\n');
for linter in Linter::iter() {

View File

@@ -1,73 +0,0 @@
# OK
1<2 and 'b' and 'c'
1<2 or 'a' and 'b'
1<2 and 'a'
1<2 or 'a'
2>1
1<2 and 'a' or 'b' and 'c'
1<2 and 'a' or 'b' or 'c'
1<2 and 'a' or 'b' or 'c' or (lambda x: x+1)
1<2 and 'a' or 'b' or (lambda x: x+1) or 'c'
default = 'default'
if (not isinstance(default, bool) and isinstance(default, int)) \
or (isinstance(default, str) and default):
pass
docid, token = None, None
(docid is None and token is None) or (docid is not None and token is not None)
vendor, os_version = 'darwin', '14'
vendor == "debian" and os_version in ["12"] or vendor == "ubuntu" and os_version in []
# Don't emit if the parent is an `if` statement.
if (task_id in task_dict and task_dict[task_id] is not task) \
or task_id in used_group_ids:
pass
no_target, is_x64, target = True, False, 'target'
if (no_target and not is_x64) or target == 'ARM_APPL_RUST_TARGET':
pass
# Don't emit if the parent is a `bool_op` expression.
isinstance(val, str) and ((len(val) == 7 and val[0] == "#") or val in enums.NamedColor)
# Errors
1<2 and 'a' or 'b'
(lambda x: x+1) and 'a' or 'b'
'a' and (lambda x: x+1) or 'orange'
val = '#0000FF'
(len(val) == 7 and val[0] == "#") or val in {'green'}
marker = 'marker'
isinstance(marker, dict) and 'field' in marker or marker in {}
def has_oranges(oranges, apples=None) -> bool:
return apples and False or oranges
[x for x in l if a and b or c]
{x: y for x in l if a and b or c}
{x for x in l if a and b or c}
new_list = [
x
for sublist in all_lists
if a and b or c
for x in sublist
if (isinstance(operator, list) and x in operator) or x != operator
]

View File

@@ -256,25 +256,23 @@ pub(crate) fn deferred_scopes(checker: &mut Checker) {
diagnostic.set_parent(range.start());
}
if checker.settings.preview.is_enabled() {
if let Some(import) = binding.as_any_import() {
if let Some(source) = binding.source {
diagnostic.try_set_fix(|| {
let statement = checker.semantic().statement(source);
let parent = checker.semantic().parent_statement(source);
let edit = fix::edits::remove_unused_imports(
std::iter::once(import.member_name().as_ref()),
statement,
parent,
checker.locator(),
checker.stylist(),
checker.indexer(),
)?;
Ok(Fix::safe_edit(edit).isolate(Checker::isolation(
checker.semantic().parent_statement_id(source),
)))
});
}
if let Some(import) = binding.as_any_import() {
if let Some(source) = binding.source {
diagnostic.try_set_fix(|| {
let statement = checker.semantic().statement(source);
let parent = checker.semantic().parent_statement(source);
let edit = fix::edits::remove_unused_imports(
std::iter::once(import.member_name().as_ref()),
statement,
parent,
checker.locator(),
checker.stylist(),
checker.indexer(),
)?;
Ok(Fix::safe_edit(edit).isolate(Checker::isolation(
checker.semantic().parent_statement_id(source),
)))
});
}
}

View File

@@ -1446,7 +1446,7 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
}
}
if checker.enabled(Rule::StaticKeyDictComprehension) {
ruff::rules::static_key_dict_comprehension(checker, dict_comp);
flake8_bugbear::rules::static_key_dict_comprehension(checker, dict_comp);
}
}
Expr::GeneratorExp(
@@ -1508,9 +1508,6 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
if checker.enabled(Rule::RepeatedEqualityComparison) {
pylint::rules::repeated_equality_comparison(checker, bool_op);
}
if checker.enabled(Rule::AndOrTernary) {
pylint::rules::and_or_ternary(checker, bool_op);
}
if checker.enabled(Rule::UnnecessaryKeyCheck) {
ruff::rules::unnecessary_key_check(checker, expr);
}

View File

@@ -342,8 +342,7 @@ where
|| helpers::is_assignment_to_a_dunder(stmt)
|| helpers::in_nested_block(self.semantic.current_statements())
|| imports::is_matplotlib_activation(stmt, self.semantic())
|| self.settings.preview.is_enabled()
&& imports::is_sys_path_modification(stmt, self.semantic()))
|| imports::is_sys_path_modification(stmt, self.semantic()))
{
self.semantic.flags |= SemanticModelFlags::IMPORT_BOUNDARY;
}

View File

@@ -52,6 +52,11 @@ pub enum RuleGroup {
Stable,
/// The rule is unstable, and preview mode must be enabled for usage.
Preview,
/// The rule has been deprecated, warnings will be displayed during selection in stable
/// and errors will be raised if used with preview mode enabled.
Deprecated,
/// The rule has been removed, errors will be displayed on use.
Removed,
/// Legacy category for unstable rules, supports backwards compatible selection.
#[deprecated(note = "Use `RuleGroup::Preview` for new rules instead")]
Nursery,
@@ -265,7 +270,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Pylint, "R1704") => (RuleGroup::Preview, rules::pylint::rules::RedefinedArgumentFromLocal),
(Pylint, "R1711") => (RuleGroup::Stable, rules::pylint::rules::UselessReturn),
(Pylint, "R1714") => (RuleGroup::Stable, rules::pylint::rules::RepeatedEqualityComparison),
(Pylint, "R1706") => (RuleGroup::Preview, rules::pylint::rules::AndOrTernary),
(Pylint, "R1706") => (RuleGroup::Removed, rules::pylint::rules::AndOrTernary),
(Pylint, "R1722") => (RuleGroup::Stable, rules::pylint::rules::SysExitAlias),
(Pylint, "R1733") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryDictIndexLookup),
(Pylint, "R1736") => (RuleGroup::Preview, rules::pylint::rules::UnnecessaryListIndexLookup),
@@ -351,6 +356,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Bugbear, "032") => (RuleGroup::Stable, rules::flake8_bugbear::rules::UnintentionalTypeAnnotation),
(Flake8Bugbear, "033") => (RuleGroup::Stable, rules::flake8_bugbear::rules::DuplicateValue),
(Flake8Bugbear, "034") => (RuleGroup::Stable, rules::flake8_bugbear::rules::ReSubPositionalArgs),
(Flake8Bugbear, "035") => (RuleGroup::Stable, rules::flake8_bugbear::rules::StaticKeyDictComprehension),
(Flake8Bugbear, "904") => (RuleGroup::Stable, rules::flake8_bugbear::rules::RaiseWithoutFromInsideExcept),
(Flake8Bugbear, "905") => (RuleGroup::Stable, rules::flake8_bugbear::rules::ZipWithoutExplicitStrict),
@@ -423,8 +429,8 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Annotations, "001") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingTypeFunctionArgument),
(Flake8Annotations, "002") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingTypeArgs),
(Flake8Annotations, "003") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingTypeKwargs),
(Flake8Annotations, "101") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingTypeSelf),
(Flake8Annotations, "102") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingTypeCls),
(Flake8Annotations, "101") => (RuleGroup::Deprecated, rules::flake8_annotations::rules::MissingTypeSelf),
(Flake8Annotations, "102") => (RuleGroup::Deprecated, rules::flake8_annotations::rules::MissingTypeCls),
(Flake8Annotations, "201") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingReturnTypeUndocumentedPublicFunction),
(Flake8Annotations, "202") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingReturnTypePrivateFunction),
(Flake8Annotations, "204") => (RuleGroup::Stable, rules::flake8_annotations::rules::MissingReturnTypeSpecialMethod),
@@ -699,11 +705,11 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Flake8Datetimez, "012") => (RuleGroup::Stable, rules::flake8_datetimez::rules::CallDateFromtimestamp),
// pygrep-hooks
(PygrepHooks, "001") => (RuleGroup::Stable, rules::pygrep_hooks::rules::Eval),
(PygrepHooks, "002") => (RuleGroup::Stable, rules::pygrep_hooks::rules::DeprecatedLogWarn),
(PygrepHooks, "003") => (RuleGroup::Stable, rules::pygrep_hooks::rules::BlanketTypeIgnore),
(PygrepHooks, "004") => (RuleGroup::Stable, rules::pygrep_hooks::rules::BlanketNOQA),
(PygrepHooks, "005") => (RuleGroup::Stable, rules::pygrep_hooks::rules::InvalidMockAccess),
(PygrepHooks, "001") => (RuleGroup::Deprecated, rules::pygrep_hooks::rules::Eval),
(PygrepHooks, "002") => (RuleGroup::Deprecated, rules::pygrep_hooks::rules::DeprecatedLogWarn),
(PygrepHooks, "003") => (RuleGroup::Deprecated, rules::pygrep_hooks::rules::BlanketTypeIgnore),
(PygrepHooks, "004") => (RuleGroup::Deprecated, rules::pygrep_hooks::rules::BlanketNOQA),
(PygrepHooks, "005") => (RuleGroup::Deprecated, rules::pygrep_hooks::rules::InvalidMockAccess),
// pandas-vet
(PandasVet, "002") => (RuleGroup::Stable, rules::pandas_vet::rules::PandasUseOfInplaceArgument),
@@ -841,7 +847,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Tryceratops, "002") => (RuleGroup::Stable, rules::tryceratops::rules::RaiseVanillaClass),
(Tryceratops, "003") => (RuleGroup::Stable, rules::tryceratops::rules::RaiseVanillaArgs),
(Tryceratops, "004") => (RuleGroup::Stable, rules::tryceratops::rules::TypeCheckWithoutTypeError),
(Tryceratops, "200") => (RuleGroup::Stable, rules::tryceratops::rules::ReraiseNoCause),
(Tryceratops, "200") => (RuleGroup::Deprecated, rules::tryceratops::rules::ReraiseNoCause),
(Tryceratops, "201") => (RuleGroup::Stable, rules::tryceratops::rules::VerboseRaise),
(Tryceratops, "300") => (RuleGroup::Stable, rules::tryceratops::rules::TryConsiderElse),
(Tryceratops, "301") => (RuleGroup::Stable, rules::tryceratops::rules::RaiseWithinTry),
@@ -916,7 +922,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "008") => (RuleGroup::Stable, rules::ruff::rules::MutableDataclassDefault),
(Ruff, "009") => (RuleGroup::Stable, rules::ruff::rules::FunctionCallInDataclassDefaultArgument),
(Ruff, "010") => (RuleGroup::Stable, rules::ruff::rules::ExplicitFStringTypeConversion),
(Ruff, "011") => (RuleGroup::Stable, rules::ruff::rules::StaticKeyDictComprehension),
(Ruff, "012") => (RuleGroup::Stable, rules::ruff::rules::MutableClassDefault),
(Ruff, "013") => (RuleGroup::Stable, rules::ruff::rules::ImplicitOptional),
(Ruff, "015") => (RuleGroup::Stable, rules::ruff::rules::UnnecessaryIterableAllocationForFirstElement),

View File

@@ -21,6 +21,9 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("C9", "C90"),
("T1", "T10"),
("T2", "T20"),
// The PGH category is deprecated
("PGH001", "S307"),
("PGH002", "G010"),
// TODO(charlie): Remove by 2023-02-01.
("R", "RET"),
("R5", "RET5"),
@@ -98,5 +101,6 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("T002", "FIX002"),
("T003", "FIX003"),
("T004", "FIX004"),
("RUF011", "B035"),
])
});

View File

@@ -126,6 +126,51 @@ impl RuleSelector {
RuleSelector::Linter(l) => (l.common_prefix(), ""),
}
}
/// Parse [`RuleSelector`] from a string; but do not follow redirects.
pub fn from_str_no_redirect(s: &str) -> Result<Self, ParseError> {
match s {
"ALL" => Ok(Self::All),
#[allow(deprecated)]
"NURSERY" => Ok(Self::Nursery),
"C" => Ok(Self::C),
"T" => Ok(Self::T),
_ => {
let (linter, code) =
Linter::parse_code(s).ok_or_else(|| ParseError::Unknown(s.to_string()))?;
if code.is_empty() {
return Ok(Self::Linter(linter));
}
// Does the selector select a single rule?
let prefix = RuleCodePrefix::parse(&linter, code)
.map_err(|_| ParseError::Unknown(s.to_string()))?;
if is_single_rule_selector(&prefix) {
Ok(Self::Rule {
prefix,
redirected_from: None,
})
} else {
Ok(Self::Prefix {
prefix,
redirected_from: None,
})
}
}
}
}
pub fn display_kind(&self) -> &'static str {
match self {
#[allow(deprecated)]
Self::All | Self::T | Self::Nursery | Self::C => "rule selector",
Self::Rule { .. } => "rule",
Self::Prefix { .. } => "rule prefix",
Self::Linter(_) => "rule category",
}
}
}
impl Serialize for RuleSelector {
@@ -204,13 +249,17 @@ impl RuleSelector {
let preview_require_explicit = preview.require_explicit;
#[allow(deprecated)]
self.all_rules().filter(move |rule| {
// Always include rules that are not in preview or the nursery
!(rule.is_preview() || rule.is_nursery())
// Always include stable rules
rule.is_stable()
// Backwards compatibility allows selection of nursery rules by exact code or dedicated group
|| ((matches!(self, RuleSelector::Rule { .. }) || matches!(self, RuleSelector::Nursery { .. })) && rule.is_nursery())
// Enabling preview includes all preview or nursery rules unless explicit selection
// is turned on
|| (preview_enabled && (matches!(self, RuleSelector::Rule { .. }) || !preview_require_explicit))
// Deprecated rules are excluded in preview mode unless explicitly selected
|| (rule.is_deprecated() && (!preview_enabled || matches!(self, RuleSelector::Rule { .. })))
// Removed rules are included if explicitly selected but will error downstream
|| (rule.is_removed() && matches!(self, RuleSelector::Rule { .. }))
})
}
}
@@ -245,6 +294,8 @@ pub struct PreviewOptions {
#[cfg(feature = "schemars")]
mod schema {
use std::str::FromStr;
use itertools::Itertools;
use schemars::JsonSchema;
use schemars::_serde_json::Value;
@@ -267,7 +318,6 @@ mod schema {
[
// Include the non-standard "ALL" and "NURSERY" selectors.
"ALL".to_string(),
"NURSERY".to_string(),
// Include the legacy "C" and "T" selectors.
"C".to_string(),
"T".to_string(),
@@ -289,6 +339,16 @@ mod schema {
(!prefix.is_empty()).then(|| prefix.to_string())
})),
)
.filter(|p| {
// Exclude any prefixes where all of the rules are removed
if let Ok(Self::Rule { prefix, .. } | Self::Prefix { prefix, .. }) =
RuleSelector::from_str(p)
{
!prefix.rules().all(|rule| rule.is_removed())
} else {
true
}
})
.sorted()
.map(Value::String)
.collect(),

View File

@@ -24,7 +24,7 @@ use super::super::detection::comment_contains_code;
/// ```
///
/// ## Options
/// - `task-tags`
/// - `lint.task-tags`
///
/// [#4845]: https://github.com/astral-sh/ruff/issues/4845
#[violation]

View File

@@ -111,6 +111,10 @@ impl Violation for MissingTypeKwargs {
}
}
/// ## Deprecation
/// This rule is commonly disabled because type checkers can infer this type without annotation.
/// It will be removed in a future release.
///
/// ## What it does
/// Checks that instance method `self` arguments have type annotations.
///
@@ -148,6 +152,10 @@ impl Violation for MissingTypeSelf {
}
}
/// ## Deprecation
/// This rule is commonly disabled because type checkers can infer this type without annotation.
/// It will be removed in a future release.
///
/// ## What it does
/// Checks that class method `cls` arguments have type annotations.
///

View File

@@ -12,7 +12,7 @@ mod tests {
use crate::assert_messages;
use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::settings::LinterSettings;
use crate::test::test_path;
@@ -34,7 +34,6 @@ mod tests {
#[test_case(Rule::GetAttrWithConstant, Path::new("B009_B010.py"))]
#[test_case(Rule::JumpStatementInFinally, Path::new("B012.py"))]
#[test_case(Rule::LoopVariableOverridesIterator, Path::new("B020.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_B008.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_1.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_2.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_3.py"))]
@@ -42,6 +41,7 @@ mod tests {
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_5.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_6.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_7.py"))]
#[test_case(Rule::MutableArgumentDefault, Path::new("B006_B008.py"))]
#[test_case(Rule::NoExplicitStacklevel, Path::new("B028.py"))]
#[test_case(Rule::RaiseLiteral, Path::new("B016.py"))]
#[test_case(Rule::RaiseWithoutFromInsideExcept, Path::new("B904.py"))]
@@ -50,16 +50,17 @@ mod tests {
#[test_case(Rule::ReuseOfGroupbyGenerator, Path::new("B031.py"))]
#[test_case(Rule::SetAttrWithConstant, Path::new("B009_B010.py"))]
#[test_case(Rule::StarArgUnpackingAfterKeywordArg, Path::new("B026.py"))]
#[test_case(Rule::StaticKeyDictComprehension, Path::new("B035.py"))]
#[test_case(Rule::StripWithMultiCharacters, Path::new("B005.py"))]
#[test_case(Rule::UnaryPrefixIncrementDecrement, Path::new("B002.py"))]
#[test_case(Rule::UnintentionalTypeAnnotation, Path::new("B032.py"))]
#[test_case(Rule::UnreliableCallableCheck, Path::new("B004.py"))]
#[test_case(Rule::UnusedLoopControlVariable, Path::new("B007.py"))]
#[test_case(Rule::UselessComparison, Path::new("B015.py"))]
#[test_case(Rule::UselessComparison, Path::new("B015.ipynb"))]
#[test_case(Rule::UselessComparison, Path::new("B015.py"))]
#[test_case(Rule::UselessContextlibSuppress, Path::new("B022.py"))]
#[test_case(Rule::UselessExpression, Path::new("B018.py"))]
#[test_case(Rule::UselessExpression, Path::new("B018.ipynb"))]
#[test_case(Rule::UselessExpression, Path::new("B018.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
@@ -70,24 +71,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::DuplicateValue, Path::new("B033.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_bugbear").join(path).as_path(),
&LinterSettings {
preview: PreviewMode::Enabled,
..LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn zip_without_explicit_strict() -> Result<()> {
let snapshot = "B905.py";

View File

@@ -61,11 +61,9 @@ pub(crate) fn duplicate_value(checker: &mut Checker, set: &ast::ExprSet) {
elt.range(),
);
if checker.settings.preview.is_enabled() {
diagnostic.try_set_fix(|| {
remove_member(set, index, checker.locator().contents()).map(Fix::safe_edit)
});
}
diagnostic.try_set_fix(|| {
remove_member(set, index, checker.locator().contents()).map(Fix::safe_edit)
});
checker.diagnostics.push(diagnostic);
}

View File

@@ -23,11 +23,11 @@ use crate::checkers::ast::Checker;
/// calls to the function, which can lead to unexpected behaviour.
///
/// Calls can be marked as an exception to this rule with the
/// [`flake8-bugbear.extend-immutable-calls`] configuration option.
/// [`lint.flake8-bugbear.extend-immutable-calls`] configuration option.
///
/// Arguments with immutable type annotations will be ignored by this rule.
/// Types outside of the standard library can be marked as immutable with the
/// [`flake8-bugbear.extend-immutable-calls`] configuration option as well.
/// [`lint.flake8-bugbear.extend-immutable-calls`] configuration option as well.
///
/// ## Example
/// ```python
@@ -61,7 +61,7 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `flake8-bugbear.extend-immutable-calls`
/// - `lint.flake8-bugbear.extend-immutable-calls`
#[violation]
pub struct FunctionCallInDefaultArgument {
name: Option<String>,

View File

@@ -22,6 +22,7 @@ pub(crate) use redundant_tuple_in_exception_handler::*;
pub(crate) use reuse_of_groupby_generator::*;
pub(crate) use setattr_with_constant::*;
pub(crate) use star_arg_unpacking_after_keyword_arg::*;
pub(crate) use static_key_dict_comprehension::*;
pub(crate) use strip_with_multi_characters::*;
pub(crate) use unary_prefix_increment_decrement::*;
pub(crate) use unintentional_type_annotation::*;
@@ -56,6 +57,7 @@ mod redundant_tuple_in_exception_handler;
mod reuse_of_groupby_generator;
mod setattr_with_constant;
mod star_arg_unpacking_after_keyword_arg;
mod static_key_dict_comprehension;
mod strip_with_multi_characters;
mod unary_prefix_increment_decrement;
mod unintentional_type_annotation;

View File

@@ -28,7 +28,7 @@ use crate::checkers::ast::Checker;
///
/// Arguments with immutable type annotations will be ignored by this rule.
/// Types outside of the standard library can be marked as immutable with the
/// [`flake8-bugbear.extend-immutable-calls`] configuration option.
/// [`lint.flake8-bugbear.extend-immutable-calls`] configuration option.
///
/// ## Known problems
/// Mutable argument defaults can be used intentionally to cache computation
@@ -61,7 +61,7 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `flake8-bugbear.extend-immutable-calls`
/// - `lint.flake8-bugbear.extend-immutable-calls`
///
/// ## References
/// - [Python documentation: Default Argument Values](https://docs.python.org/3/tutorial/controlflow.html#default-argument-values)

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
---
B033.py:4:35: B033 Sets should not contain duplicate item `"value1"`
B033.py:4:35: B033 [*] Sets should not contain duplicate item `"value1"`
|
2 | # Errors.
3 | ###
@@ -12,7 +12,17 @@ B033.py:4:35: B033 Sets should not contain duplicate item `"value1"`
|
= help: Remove duplicate item
B033.py:5:21: B033 Sets should not contain duplicate item `1`
Safe fix
1 1 | ###
2 2 | # Errors.
3 3 | ###
4 |-incorrect_set = {"value1", 23, 5, "value1"}
4 |+incorrect_set = {"value1", 23, 5}
5 5 | incorrect_set = {1, 1, 2}
6 6 | incorrect_set_multiline = {
7 7 | "value1",
B033.py:5:21: B033 [*] Sets should not contain duplicate item `1`
|
3 | ###
4 | incorrect_set = {"value1", 23, 5, "value1"}
@@ -23,7 +33,17 @@ B033.py:5:21: B033 Sets should not contain duplicate item `1`
|
= help: Remove duplicate item
B033.py:10:5: B033 Sets should not contain duplicate item `"value1"`
Safe fix
2 2 | # Errors.
3 3 | ###
4 4 | incorrect_set = {"value1", 23, 5, "value1"}
5 |-incorrect_set = {1, 1, 2}
5 |+incorrect_set = {1, 2}
6 6 | incorrect_set_multiline = {
7 7 | "value1",
8 8 | 23,
B033.py:10:5: B033 [*] Sets should not contain duplicate item `"value1"`
|
8 | 23,
9 | 5,
@@ -34,7 +54,16 @@ B033.py:10:5: B033 Sets should not contain duplicate item `"value1"`
|
= help: Remove duplicate item
B033.py:13:21: B033 Sets should not contain duplicate item `1`
Safe fix
7 7 | "value1",
8 8 | 23,
9 9 | 5,
10 |- "value1",
11 10 | # B033
12 11 | }
13 12 | incorrect_set = {1, 1}
B033.py:13:21: B033 [*] Sets should not contain duplicate item `1`
|
11 | # B033
12 | }
@@ -45,7 +74,17 @@ B033.py:13:21: B033 Sets should not contain duplicate item `1`
|
= help: Remove duplicate item
B033.py:14:21: B033 Sets should not contain duplicate item `1`
Safe fix
10 10 | "value1",
11 11 | # B033
12 12 | }
13 |-incorrect_set = {1, 1}
13 |+incorrect_set = {1}
14 14 | incorrect_set = {1, 1,}
15 15 | incorrect_set = {0, 1, 1,}
16 16 | incorrect_set = {0, 1, 1}
B033.py:14:21: B033 [*] Sets should not contain duplicate item `1`
|
12 | }
13 | incorrect_set = {1, 1}
@@ -56,7 +95,17 @@ B033.py:14:21: B033 Sets should not contain duplicate item `1`
|
= help: Remove duplicate item
B033.py:15:24: B033 Sets should not contain duplicate item `1`
Safe fix
11 11 | # B033
12 12 | }
13 13 | incorrect_set = {1, 1}
14 |-incorrect_set = {1, 1,}
14 |+incorrect_set = {1,}
15 15 | incorrect_set = {0, 1, 1,}
16 16 | incorrect_set = {0, 1, 1}
17 17 | incorrect_set = {
B033.py:15:24: B033 [*] Sets should not contain duplicate item `1`
|
13 | incorrect_set = {1, 1}
14 | incorrect_set = {1, 1,}
@@ -67,7 +116,17 @@ B033.py:15:24: B033 Sets should not contain duplicate item `1`
|
= help: Remove duplicate item
B033.py:16:24: B033 Sets should not contain duplicate item `1`
Safe fix
12 12 | }
13 13 | incorrect_set = {1, 1}
14 14 | incorrect_set = {1, 1,}
15 |-incorrect_set = {0, 1, 1,}
15 |+incorrect_set = {0, 1,}
16 16 | incorrect_set = {0, 1, 1}
17 17 | incorrect_set = {
18 18 | 0,
B033.py:16:24: B033 [*] Sets should not contain duplicate item `1`
|
14 | incorrect_set = {1, 1,}
15 | incorrect_set = {0, 1, 1,}
@@ -78,7 +137,17 @@ B033.py:16:24: B033 Sets should not contain duplicate item `1`
|
= help: Remove duplicate item
B033.py:20:5: B033 Sets should not contain duplicate item `1`
Safe fix
13 13 | incorrect_set = {1, 1}
14 14 | incorrect_set = {1, 1,}
15 15 | incorrect_set = {0, 1, 1,}
16 |-incorrect_set = {0, 1, 1}
16 |+incorrect_set = {0, 1}
17 17 | incorrect_set = {
18 18 | 0,
19 19 | 1,
B033.py:20:5: B033 [*] Sets should not contain duplicate item `1`
|
18 | 0,
19 | 1,
@@ -88,4 +157,13 @@ B033.py:20:5: B033 Sets should not contain duplicate item `1`
|
= help: Remove duplicate item
Safe fix
17 17 | incorrect_set = {
18 18 | 0,
19 19 | 1,
20 |- 1,
21 20 | }
22 21 |
23 22 | ###

View File

@@ -1,90 +1,90 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
---
RUF011.py:17:2: RUF011 Dictionary comprehension uses static key: `"key"`
B035.py:17:2: B035 Dictionary comprehension uses static key: `"key"`
|
16 | # Errors
17 | {"key": value.upper() for value in data}
| ^^^^^ RUF011
| ^^^^^ B035
18 | {True: value.upper() for value in data}
19 | {0: value.upper() for value in data}
|
RUF011.py:18:2: RUF011 Dictionary comprehension uses static key: `True`
B035.py:18:2: B035 Dictionary comprehension uses static key: `True`
|
16 | # Errors
17 | {"key": value.upper() for value in data}
18 | {True: value.upper() for value in data}
| ^^^^ RUF011
| ^^^^ B035
19 | {0: value.upper() for value in data}
20 | {(1, "a"): value.upper() for value in data} # Constant tuple
|
RUF011.py:19:2: RUF011 Dictionary comprehension uses static key: `0`
B035.py:19:2: B035 Dictionary comprehension uses static key: `0`
|
17 | {"key": value.upper() for value in data}
18 | {True: value.upper() for value in data}
19 | {0: value.upper() for value in data}
| ^ RUF011
| ^ B035
20 | {(1, "a"): value.upper() for value in data} # Constant tuple
21 | {constant: value.upper() for value in data}
|
RUF011.py:20:2: RUF011 Dictionary comprehension uses static key: `(1, "a")`
B035.py:20:2: B035 Dictionary comprehension uses static key: `(1, "a")`
|
18 | {True: value.upper() for value in data}
19 | {0: value.upper() for value in data}
20 | {(1, "a"): value.upper() for value in data} # Constant tuple
| ^^^^^^^^ RUF011
| ^^^^^^^^ B035
21 | {constant: value.upper() for value in data}
22 | {constant + constant: value.upper() for value in data}
|
RUF011.py:21:2: RUF011 Dictionary comprehension uses static key: `constant`
B035.py:21:2: B035 Dictionary comprehension uses static key: `constant`
|
19 | {0: value.upper() for value in data}
20 | {(1, "a"): value.upper() for value in data} # Constant tuple
21 | {constant: value.upper() for value in data}
| ^^^^^^^^ RUF011
| ^^^^^^^^ B035
22 | {constant + constant: value.upper() for value in data}
23 | {constant.attribute: value.upper() for value in data}
|
RUF011.py:22:2: RUF011 Dictionary comprehension uses static key: `constant + constant`
B035.py:22:2: B035 Dictionary comprehension uses static key: `constant + constant`
|
20 | {(1, "a"): value.upper() for value in data} # Constant tuple
21 | {constant: value.upper() for value in data}
22 | {constant + constant: value.upper() for value in data}
| ^^^^^^^^^^^^^^^^^^^ RUF011
| ^^^^^^^^^^^^^^^^^^^ B035
23 | {constant.attribute: value.upper() for value in data}
24 | {constant[0]: value.upper() for value in data}
|
RUF011.py:23:2: RUF011 Dictionary comprehension uses static key: `constant.attribute`
B035.py:23:2: B035 Dictionary comprehension uses static key: `constant.attribute`
|
21 | {constant: value.upper() for value in data}
22 | {constant + constant: value.upper() for value in data}
23 | {constant.attribute: value.upper() for value in data}
| ^^^^^^^^^^^^^^^^^^ RUF011
| ^^^^^^^^^^^^^^^^^^ B035
24 | {constant[0]: value.upper() for value in data}
25 | {tokens: token for token in tokens}
|
RUF011.py:24:2: RUF011 Dictionary comprehension uses static key: `constant[0]`
B035.py:24:2: B035 Dictionary comprehension uses static key: `constant[0]`
|
22 | {constant + constant: value.upper() for value in data}
23 | {constant.attribute: value.upper() for value in data}
24 | {constant[0]: value.upper() for value in data}
| ^^^^^^^^^^^ RUF011
| ^^^^^^^^^^^ B035
25 | {tokens: token for token in tokens}
|
RUF011.py:25:2: RUF011 Dictionary comprehension uses static key: `tokens`
B035.py:25:2: B035 Dictionary comprehension uses static key: `tokens`
|
23 | {constant.attribute: value.upper() for value in data}
24 | {constant[0]: value.upper() for value in data}
25 | {tokens: token for token in tokens}
| ^^^^^^ RUF011
| ^^^^^^ B035
|

View File

@@ -1,169 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_bugbear/mod.rs
---
B033.py:4:35: B033 [*] Sets should not contain duplicate item `"value1"`
|
2 | # Errors.
3 | ###
4 | incorrect_set = {"value1", 23, 5, "value1"}
| ^^^^^^^^ B033
5 | incorrect_set = {1, 1, 2}
6 | incorrect_set_multiline = {
|
= help: Remove duplicate item
Safe fix
1 1 | ###
2 2 | # Errors.
3 3 | ###
4 |-incorrect_set = {"value1", 23, 5, "value1"}
4 |+incorrect_set = {"value1", 23, 5}
5 5 | incorrect_set = {1, 1, 2}
6 6 | incorrect_set_multiline = {
7 7 | "value1",
B033.py:5:21: B033 [*] Sets should not contain duplicate item `1`
|
3 | ###
4 | incorrect_set = {"value1", 23, 5, "value1"}
5 | incorrect_set = {1, 1, 2}
| ^ B033
6 | incorrect_set_multiline = {
7 | "value1",
|
= help: Remove duplicate item
Safe fix
2 2 | # Errors.
3 3 | ###
4 4 | incorrect_set = {"value1", 23, 5, "value1"}
5 |-incorrect_set = {1, 1, 2}
5 |+incorrect_set = {1, 2}
6 6 | incorrect_set_multiline = {
7 7 | "value1",
8 8 | 23,
B033.py:10:5: B033 [*] Sets should not contain duplicate item `"value1"`
|
8 | 23,
9 | 5,
10 | "value1",
| ^^^^^^^^ B033
11 | # B033
12 | }
|
= help: Remove duplicate item
Safe fix
7 7 | "value1",
8 8 | 23,
9 9 | 5,
10 |- "value1",
11 10 | # B033
12 11 | }
13 12 | incorrect_set = {1, 1}
B033.py:13:21: B033 [*] Sets should not contain duplicate item `1`
|
11 | # B033
12 | }
13 | incorrect_set = {1, 1}
| ^ B033
14 | incorrect_set = {1, 1,}
15 | incorrect_set = {0, 1, 1,}
|
= help: Remove duplicate item
Safe fix
10 10 | "value1",
11 11 | # B033
12 12 | }
13 |-incorrect_set = {1, 1}
13 |+incorrect_set = {1}
14 14 | incorrect_set = {1, 1,}
15 15 | incorrect_set = {0, 1, 1,}
16 16 | incorrect_set = {0, 1, 1}
B033.py:14:21: B033 [*] Sets should not contain duplicate item `1`
|
12 | }
13 | incorrect_set = {1, 1}
14 | incorrect_set = {1, 1,}
| ^ B033
15 | incorrect_set = {0, 1, 1,}
16 | incorrect_set = {0, 1, 1}
|
= help: Remove duplicate item
Safe fix
11 11 | # B033
12 12 | }
13 13 | incorrect_set = {1, 1}
14 |-incorrect_set = {1, 1,}
14 |+incorrect_set = {1,}
15 15 | incorrect_set = {0, 1, 1,}
16 16 | incorrect_set = {0, 1, 1}
17 17 | incorrect_set = {
B033.py:15:24: B033 [*] Sets should not contain duplicate item `1`
|
13 | incorrect_set = {1, 1}
14 | incorrect_set = {1, 1,}
15 | incorrect_set = {0, 1, 1,}
| ^ B033
16 | incorrect_set = {0, 1, 1}
17 | incorrect_set = {
|
= help: Remove duplicate item
Safe fix
12 12 | }
13 13 | incorrect_set = {1, 1}
14 14 | incorrect_set = {1, 1,}
15 |-incorrect_set = {0, 1, 1,}
15 |+incorrect_set = {0, 1,}
16 16 | incorrect_set = {0, 1, 1}
17 17 | incorrect_set = {
18 18 | 0,
B033.py:16:24: B033 [*] Sets should not contain duplicate item `1`
|
14 | incorrect_set = {1, 1,}
15 | incorrect_set = {0, 1, 1,}
16 | incorrect_set = {0, 1, 1}
| ^ B033
17 | incorrect_set = {
18 | 0,
|
= help: Remove duplicate item
Safe fix
13 13 | incorrect_set = {1, 1}
14 14 | incorrect_set = {1, 1,}
15 15 | incorrect_set = {0, 1, 1,}
16 |-incorrect_set = {0, 1, 1}
16 |+incorrect_set = {0, 1}
17 17 | incorrect_set = {
18 18 | 0,
19 19 | 1,
B033.py:20:5: B033 [*] Sets should not contain duplicate item `1`
|
18 | 0,
19 | 1,
20 | 1,
| ^ B033
21 | }
|
= help: Remove duplicate item
Safe fix
17 17 | incorrect_set = {
18 18 | 0,
19 19 | 1,
20 |- 1,
21 20 | }
22 21 |
23 22 | ###

View File

@@ -19,7 +19,7 @@ use super::super::helpers::shadows_builtin;
/// builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
///
/// ## Example
/// ```python
@@ -44,7 +44,7 @@ use super::super::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.builtins-ignorelist`
///
/// ## References
/// - [_Is it bad practice to use a built-in function name as an attribute or method identifier?_](https://stackoverflow.com/questions/9109333/is-it-bad-practice-to-use-a-built-in-function-name-as-an-attribute-or-method-ide)

View File

@@ -37,7 +37,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// Builtins can be marked as exceptions to this rule via the
/// [`flake8-builtins.builtins-ignorelist`] configuration option, or
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option, or
/// converted to the appropriate dunder method. Methods decorated with
/// `@typing.override` or `@typing_extensions.override` are also
/// ignored.
@@ -55,7 +55,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.builtins-ignorelist`
#[violation]
pub struct BuiltinAttributeShadowing {
kind: Kind,

View File

@@ -18,7 +18,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// builtin and vice versa.
///
/// Builtins can be marked as exceptions to this rule via the
/// [`flake8-builtins.builtins-ignorelist`] configuration option.
/// [`lint.flake8-builtins.builtins-ignorelist`] configuration option.
///
/// ## Example
/// ```python
@@ -41,7 +41,7 @@ use crate::rules::flake8_builtins::helpers::shadows_builtin;
/// ```
///
/// ## Options
/// - `flake8-builtins.builtins-ignorelist`
/// - `lint.flake8-builtins.builtins-ignorelist`
///
/// ## References
/// - [_Why is it a bad idea to name a variable `id` in Python?_](https://stackoverflow.com/questions/77552/id-is-a-bad-variable-name-in-python)

View File

@@ -59,7 +59,7 @@ impl Violation for SingleLineImplicitStringConcatenation {
///
/// By default, this rule will only trigger if the string literal is
/// concatenated via a backslash. To disallow implicit string concatenation
/// altogether, set the [`flake8-implicit-str-concat.allow-multiline`] option
/// altogether, set the [`lint.flake8-implicit-str-concat.allow-multiline`] option
/// to `false`.
///
/// ## Example
@@ -77,7 +77,7 @@ impl Violation for SingleLineImplicitStringConcatenation {
/// ```
///
/// ## Options
/// - `flake8-implicit-str-concat.allow-multiline`
/// - `lint.flake8-implicit-str-concat.allow-multiline`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length
#[violation]

View File

@@ -29,7 +29,7 @@ use ruff_text_size::Ranged;
/// ```
///
/// ## Options
/// - `flake8-import-conventions.banned-aliases`
/// - `lint.flake8-import-conventions.banned-aliases`
#[violation]
pub struct BannedImportAlias {
name: String,

View File

@@ -30,7 +30,7 @@ use ruff_text_size::Ranged;
/// ```
///
/// ## Options
/// - `flake8-import-conventions.banned-from`
/// - `lint.flake8-import-conventions.banned-from`
#[violation]
pub struct BannedImportFrom {
name: String,

View File

@@ -32,8 +32,8 @@ use crate::renamer::Renamer;
/// ```
///
/// ## Options
/// - `flake8-import-conventions.aliases`
/// - `flake8-import-conventions.extend-aliases`
/// - `lint.flake8-import-conventions.aliases`
/// - `lint.flake8-import-conventions.extend-aliases`
#[violation]
pub struct UnconventionalImportAlias {
name: String,

View File

@@ -30,9 +30,9 @@ use ruff_macros::{derive_message_formats, violation};
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -68,7 +68,7 @@ use ruff_macros::{derive_message_formats, violation};
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html)
@@ -114,9 +114,9 @@ impl Violation for LoggingStringFormat {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -152,7 +152,7 @@ impl Violation for LoggingStringFormat {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html)
@@ -197,9 +197,9 @@ impl Violation for LoggingPercentFormat {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -235,7 +235,7 @@ impl Violation for LoggingPercentFormat {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html)
@@ -279,9 +279,9 @@ impl Violation for LoggingStringConcat {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -317,7 +317,7 @@ impl Violation for LoggingStringConcat {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging`](https://docs.python.org/3/library/logging.html)
@@ -349,9 +349,9 @@ impl Violation for LoggingFString {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -368,7 +368,7 @@ impl Violation for LoggingFString {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging.warning`](https://docs.python.org/3/library/logging.html#logging.warning)
@@ -409,9 +409,9 @@ impl AlwaysFixableViolation for LoggingWarn {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -436,7 +436,7 @@ impl AlwaysFixableViolation for LoggingWarn {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: LogRecord attributes](https://docs.python.org/3/library/logging.html#logrecord-attributes)
@@ -470,9 +470,9 @@ impl Violation for LoggingExtraAttrClash {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -495,7 +495,7 @@ impl Violation for LoggingExtraAttrClash {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging.exception`](https://docs.python.org/3/library/logging.html#logging.exception)
@@ -531,9 +531,9 @@ impl Violation for LoggingExcInfo {
/// - Uses of `flask.current_app.logger` (e.g., `from flask import current_app; current_app.logger.info(...)`).
/// - Objects whose name starts with `log` or ends with `logger` or `logging`,
/// when used in the same file in which they are defined (e.g., `logger = logging.getLogger(); logger.info(...)`).
/// - Imported objects marked as loggers via the [`logger-objects`] setting, which can be
/// - Imported objects marked as loggers via the [`lint.logger-objects`] setting, which can be
/// used to enforce these rules against shared logger objects (e.g., `from module import logger; logger.info(...)`,
/// when [`logger-objects`] is set to `["module.logger"]`).
/// when [`lint.logger-objects`] is set to `["module.logger"]`).
///
/// ## Example
/// ```python
@@ -556,7 +556,7 @@ impl Violation for LoggingExcInfo {
/// ```
///
/// ## Options
/// - `logger-objects`
/// - `lint.logger-objects`
///
/// ## References
/// - [Python documentation: `logging.exception`](https://docs.python.org/3/library/logging.html#logging.exception)

View File

@@ -9,7 +9,6 @@ mod tests {
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@@ -31,24 +30,4 @@ mod tests {
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test_case(Rule::UnnecessaryPlaceholder, Path::new("PIE790.py"))]
#[test_case(Rule::UnnecessarySpread, Path::new("PIE800.py"))]
#[test_case(Rule::ReimplementedContainerBuiltin, Path::new("PIE807.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("flake8_pie").join(path).as_path(),
&settings::LinterSettings {
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
}

View File

@@ -8,10 +8,7 @@ use ruff_text_size::Ranged;
use crate::checkers::ast::Checker;
/// ## What it does
/// Checks for lambdas that can be replaced with the `list` builtin.
///
/// In [preview], this rule will also flag lambdas that can be replaced with
/// the `dict` builtin.
/// Checks for lambdas that can be replaced with the `list` or `dict` builtins.
///
/// ## Why is this bad?
/// Using container builtins are more succinct and idiomatic than wrapping
@@ -40,8 +37,6 @@ use crate::checkers::ast::Checker;
///
/// ## References
/// - [Python documentation: `list`](https://docs.python.org/3/library/functions.html#func-list)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[violation]
pub struct ReimplementedContainerBuiltin {
container: Container,
@@ -73,11 +68,7 @@ pub(crate) fn reimplemented_container_builtin(checker: &mut Checker, expr: &Expr
if parameters.is_none() {
let container = match body.as_ref() {
Expr::List(ast::ExprList { elts, .. }) if elts.is_empty() => Some(Container::List),
Expr::Dict(ast::ExprDict { values, .. })
if values.is_empty() & checker.settings.preview.is_enabled() =>
{
Some(Container::Dict)
}
Expr::Dict(ast::ExprDict { values, .. }) if values.is_empty() => Some(Container::Dict),
_ => None,
};
if let Some(container) = container {

View File

@@ -10,11 +10,8 @@ use crate::checkers::ast::Checker;
use crate::fix;
/// ## What it does
/// Checks for unnecessary `pass` statements in functions, classes, and other
/// blocks.
///
/// In [preview], this rule also checks for unnecessary ellipsis (`...`)
/// literals.
/// Checks for unnecessary `pass` statements and ellipsis (`...`) literals in
/// functions, classes, and other blocks.
///
/// ## Why is this bad?
/// In Python, the `pass` statement and ellipsis (`...`) literal serve as
@@ -40,7 +37,7 @@ use crate::fix;
/// """Placeholder docstring."""
/// ```
///
/// In [preview]:
/// Or, given:
/// ```python
/// def func():
/// """Placeholder docstring."""
@@ -55,8 +52,6 @@ use crate::fix;
///
/// ## References
/// - [Python documentation: The `pass` statement](https://docs.python.org/3/reference/simple_stmts.html#the-pass-statement)
///
/// [preview]: https://docs.astral.sh/ruff/preview/
#[violation]
pub struct UnnecessaryPlaceholder {
kind: Placeholder,
@@ -90,10 +85,7 @@ pub(crate) fn unnecessary_placeholder(checker: &mut Checker, body: &[Stmt]) {
for stmt in body {
let kind = match stmt {
Stmt::Pass(_) => Placeholder::Pass,
Stmt::Expr(expr)
if expr.value.is_ellipsis_literal_expr()
&& checker.settings.preview.is_enabled() =>
{
Stmt::Expr(expr) if expr.value.is_ellipsis_literal_expr() => {
// Ellipses are significant in protocol methods and abstract methods. Specifically,
// Pyright uses the presence of an ellipsis to indicate that a method is a stub,
// rather than a default implementation.

View File

@@ -55,10 +55,8 @@ pub(crate) fn unnecessary_spread(checker: &mut Checker, dict: &ast::ExprDict) {
// inside a dict.
if let Expr::Dict(inner) = value {
let mut diagnostic = Diagnostic::new(UnnecessarySpread, value.range());
if checker.settings.preview.is_enabled() {
if let Some(fix) = unnecessary_spread_fix(inner, prev_end, checker.locator()) {
diagnostic.set_fix(fix);
}
if let Some(fix) = unnecessary_spread_fix(inner, prev_end, checker.locator()) {
diagnostic.set_fix(fix);
}
checker.diagnostics.push(diagnostic);
}

View File

@@ -467,6 +467,176 @@ PIE790.py:150:5: PIE790 [*] Unnecessary `pass` statement
152 151 |
153 152 | def foo():
PIE790.py:155:5: PIE790 [*] Unnecessary `...` literal
|
153 | def foo():
154 | print("foo")
155 | ...
| ^^^ PIE790
|
= help: Remove unnecessary `...`
Safe fix
152 152 |
153 153 | def foo():
154 154 | print("foo")
155 |- ...
156 155 |
157 156 |
158 157 | def foo():
PIE790.py:161:5: PIE790 [*] Unnecessary `...` literal
|
159 | """A docstring."""
160 | print("foo")
161 | ...
| ^^^ PIE790
|
= help: Remove unnecessary `...`
Safe fix
158 158 | def foo():
159 159 | """A docstring."""
160 160 | print("foo")
161 |- ...
162 161 |
163 162 |
164 163 | for i in range(10):
PIE790.py:165:5: PIE790 [*] Unnecessary `...` literal
|
164 | for i in range(10):
165 | ...
| ^^^ PIE790
166 | ...
|
= help: Remove unnecessary `...`
Safe fix
163 163 |
164 164 | for i in range(10):
165 165 | ...
166 |- ...
167 166 |
168 167 | for i in range(10):
169 168 | ...
PIE790.py:166:5: PIE790 [*] Unnecessary `...` literal
|
164 | for i in range(10):
165 | ...
166 | ...
| ^^^ PIE790
167 |
168 | for i in range(10):
|
= help: Remove unnecessary `...`
Safe fix
163 163 |
164 164 | for i in range(10):
165 165 | ...
166 |- ...
167 166 |
168 167 | for i in range(10):
169 168 | ...
PIE790.py:169:5: PIE790 [*] Unnecessary `...` literal
|
168 | for i in range(10):
169 | ...
| ^^^ PIE790
170 |
171 | ...
|
= help: Remove unnecessary `...`
Safe fix
166 166 | ...
167 167 |
168 168 | for i in range(10):
169 |- ...
170 169 |
171 170 | ...
172 171 |
PIE790.py:171:5: PIE790 [*] Unnecessary `...` literal
|
169 | ...
170 |
171 | ...
| ^^^ PIE790
172 |
173 | for i in range(10):
|
= help: Remove unnecessary `...`
Safe fix
168 168 | for i in range(10):
169 169 | ...
170 170 |
171 |- ...
172 171 |
173 172 | for i in range(10):
174 173 | ... # comment
PIE790.py:174:5: PIE790 [*] Unnecessary `...` literal
|
173 | for i in range(10):
174 | ... # comment
| ^^^ PIE790
175 | ...
|
= help: Remove unnecessary `...`
Safe fix
171 171 | ...
172 172 |
173 173 | for i in range(10):
174 |- ... # comment
174 |+ # comment
175 175 | ...
176 176 |
177 177 | for i in range(10):
PIE790.py:175:5: PIE790 [*] Unnecessary `...` literal
|
173 | for i in range(10):
174 | ... # comment
175 | ...
| ^^^ PIE790
176 |
177 | for i in range(10):
|
= help: Remove unnecessary `...`
Safe fix
172 172 |
173 173 | for i in range(10):
174 174 | ... # comment
175 |- ...
176 175 |
177 176 | for i in range(10):
178 177 | ...
PIE790.py:178:5: PIE790 [*] Unnecessary `...` literal
|
177 | for i in range(10):
178 | ...
| ^^^ PIE790
179 | pass
|
= help: Remove unnecessary `...`
Safe fix
175 175 | ...
176 176 |
177 177 | for i in range(10):
178 |- ...
179 178 | pass
180 179 |
181 180 | from typing import Protocol
PIE790.py:179:5: PIE790 [*] Unnecessary `pass` statement
|
177 | for i in range(10):
@@ -487,4 +657,19 @@ PIE790.py:179:5: PIE790 [*] Unnecessary `pass` statement
181 180 | from typing import Protocol
182 181 |
PIE790.py:209:9: PIE790 [*] Unnecessary `...` literal
|
207 | def stub(self) -> str:
208 | """Docstring"""
209 | ...
| ^^^ PIE790
|
= help: Remove unnecessary `...`
Safe fix
206 206 |
207 207 | def stub(self) -> str:
208 208 | """Docstring"""
209 |- ...

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pie/mod.rs
---
PIE800.py:1:14: PIE800 Unnecessary spread `**`
PIE800.py:1:14: PIE800 [*] Unnecessary spread `**`
|
1 | {"foo": 1, **{"bar": 1}} # PIE800
| ^^^^^^^^^^ PIE800
@@ -10,7 +10,14 @@ PIE800.py:1:14: PIE800 Unnecessary spread `**`
|
= help: Remove unnecessary dict
PIE800.py:3:4: PIE800 Unnecessary spread `**`
Safe fix
1 |-{"foo": 1, **{"bar": 1}} # PIE800
1 |+{"foo": 1, "bar": 1} # PIE800
2 2 |
3 3 | {**{"bar": 10}, "a": "b"} # PIE800
4 4 |
PIE800.py:3:4: PIE800 [*] Unnecessary spread `**`
|
1 | {"foo": 1, **{"bar": 1}} # PIE800
2 |
@@ -21,7 +28,16 @@ PIE800.py:3:4: PIE800 Unnecessary spread `**`
|
= help: Remove unnecessary dict
PIE800.py:5:15: PIE800 Unnecessary spread `**`
Safe fix
1 1 | {"foo": 1, **{"bar": 1}} # PIE800
2 2 |
3 |-{**{"bar": 10}, "a": "b"} # PIE800
3 |+{"bar": 10, "a": "b"} # PIE800
4 4 |
5 5 | foo({**foo, **{"bar": True}}) # PIE800
6 6 |
PIE800.py:5:15: PIE800 [*] Unnecessary spread `**`
|
3 | {**{"bar": 10}, "a": "b"} # PIE800
4 |
@@ -32,7 +48,17 @@ PIE800.py:5:15: PIE800 Unnecessary spread `**`
|
= help: Remove unnecessary dict
PIE800.py:7:11: PIE800 Unnecessary spread `**`
Safe fix
2 2 |
3 3 | {**{"bar": 10}, "a": "b"} # PIE800
4 4 |
5 |-foo({**foo, **{"bar": True}}) # PIE800
5 |+foo({**foo, "bar": True}) # PIE800
6 6 |
7 7 | {**foo, **{"bar": 10}} # PIE800
8 8 |
PIE800.py:7:11: PIE800 [*] Unnecessary spread `**`
|
5 | foo({**foo, **{"bar": True}}) # PIE800
6 |
@@ -43,7 +69,17 @@ PIE800.py:7:11: PIE800 Unnecessary spread `**`
|
= help: Remove unnecessary dict
PIE800.py:12:7: PIE800 Unnecessary spread `**`
Safe fix
4 4 |
5 5 | foo({**foo, **{"bar": True}}) # PIE800
6 6 |
7 |-{**foo, **{"bar": 10}} # PIE800
7 |+{**foo, "bar": 10} # PIE800
8 8 |
9 9 | { # PIE800
10 10 | "a": "b",
PIE800.py:12:7: PIE800 [*] Unnecessary spread `**`
|
10 | "a": "b",
11 | # Preserve
@@ -58,7 +94,23 @@ PIE800.py:12:7: PIE800 Unnecessary spread `**`
|
= help: Remove unnecessary dict
PIE800.py:19:19: PIE800 Unnecessary spread `**`
Safe fix
9 9 | { # PIE800
10 10 | "a": "b",
11 11 | # Preserve
12 |- **{
12 |+
13 13 | # all
14 |- "bar": 10, # the
14 |+ "bar": 10 # the
15 15 | # comments
16 |- },
16 |+ ,
17 17 | }
18 18 |
19 19 | {**foo, **buzz, **{bar: 10}} # PIE800
PIE800.py:19:19: PIE800 [*] Unnecessary spread `**`
|
17 | }
18 |
@@ -69,4 +121,14 @@ PIE800.py:19:19: PIE800 Unnecessary spread `**`
|
= help: Remove unnecessary dict
Safe fix
16 16 | },
17 17 | }
18 18 |
19 |-{**foo, **buzz, **{bar: 10}} # PIE800
19 |+{**foo, **buzz, bar: 10} # PIE800
20 20 |
21 21 | {**foo, "bar": True } # OK
22 22 |

View File

@@ -20,6 +20,25 @@ PIE807.py:3:44: PIE807 [*] Prefer `list` over useless lambda
5 5 |
6 6 |
PIE807.py:4:49: PIE807 [*] Prefer `dict` over useless lambda
|
2 | class Foo:
3 | foo: List[str] = field(default_factory=lambda: []) # PIE807
4 | bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
| ^^^^^^^^^^ PIE807
|
= help: Replace with `lambda` with `dict`
Safe fix
1 1 | @dataclass
2 2 | class Foo:
3 3 | foo: List[str] = field(default_factory=lambda: []) # PIE807
4 |- bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
4 |+ bar: Dict[str, int] = field(default_factory=dict) # PIE807
5 5 |
6 6 |
7 7 | class FooTable(BaseTable):
PIE807.py:8:36: PIE807 [*] Prefer `list` over useless lambda
|
7 | class FooTable(BaseTable):
@@ -39,6 +58,25 @@ PIE807.py:8:36: PIE807 [*] Prefer `list` over useless lambda
10 10 |
11 11 |
PIE807.py:9:36: PIE807 [*] Prefer `dict` over useless lambda
|
7 | class FooTable(BaseTable):
8 | foo = fields.ListField(default=lambda: []) # PIE807
9 | bar = fields.ListField(default=lambda: {}) # PIE807
| ^^^^^^^^^^ PIE807
|
= help: Replace with `lambda` with `dict`
Safe fix
6 6 |
7 7 | class FooTable(BaseTable):
8 8 | foo = fields.ListField(default=lambda: []) # PIE807
9 |- bar = fields.ListField(default=lambda: {}) # PIE807
9 |+ bar = fields.ListField(default=dict) # PIE807
10 10 |
11 11 |
12 12 | class FooTable(BaseTable):
PIE807.py:13:28: PIE807 [*] Prefer `list` over useless lambda
|
12 | class FooTable(BaseTable):
@@ -58,4 +96,23 @@ PIE807.py:13:28: PIE807 [*] Prefer `list` over useless lambda
15 15 |
16 16 |
PIE807.py:14:36: PIE807 [*] Prefer `dict` over useless lambda
|
12 | class FooTable(BaseTable):
13 | foo = fields.ListField(lambda: []) # PIE807
14 | bar = fields.ListField(default=lambda: {}) # PIE807
| ^^^^^^^^^^ PIE807
|
= help: Replace with `lambda` with `dict`
Safe fix
11 11 |
12 12 | class FooTable(BaseTable):
13 13 | foo = fields.ListField(lambda: []) # PIE807
14 |- bar = fields.ListField(default=lambda: {}) # PIE807
14 |+ bar = fields.ListField(default=dict) # PIE807
15 15 |
16 16 |
17 17 | @dataclass

View File

@@ -1,675 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pie/mod.rs
---
PIE790.py:4:5: PIE790 [*] Unnecessary `pass` statement
|
2 | """buzz"""
3 |
4 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
1 1 | class Foo:
2 2 | """buzz"""
3 3 |
4 |- pass
5 4 |
6 5 |
7 6 | if foo:
PIE790.py:9:5: PIE790 [*] Unnecessary `pass` statement
|
7 | if foo:
8 | """foo"""
9 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
6 6 |
7 7 | if foo:
8 8 | """foo"""
9 |- pass
10 9 |
11 10 |
12 11 | def multi_statement() -> None:
PIE790.py:14:5: PIE790 [*] Unnecessary `pass` statement
|
12 | def multi_statement() -> None:
13 | """This is a function."""
14 | pass; print("hello")
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
11 11 |
12 12 | def multi_statement() -> None:
13 13 | """This is a function."""
14 |- pass; print("hello")
14 |+ print("hello")
15 15 |
16 16 |
17 17 | if foo:
PIE790.py:21:5: PIE790 [*] Unnecessary `pass` statement
|
19 | else:
20 | """bar"""
21 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
18 18 | pass
19 19 | else:
20 20 | """bar"""
21 |- pass
22 21 |
23 22 |
24 23 | while True:
PIE790.py:28:5: PIE790 [*] Unnecessary `pass` statement
|
26 | else:
27 | """bar"""
28 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
25 25 | pass
26 26 | else:
27 27 | """bar"""
28 |- pass
29 28 |
30 29 |
31 30 | for _ in range(10):
PIE790.py:35:5: PIE790 [*] Unnecessary `pass` statement
|
33 | else:
34 | """bar"""
35 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
32 32 | pass
33 33 | else:
34 34 | """bar"""
35 |- pass
36 35 |
37 36 |
38 37 | async for _ in range(10):
PIE790.py:42:5: PIE790 [*] Unnecessary `pass` statement
|
40 | else:
41 | """bar"""
42 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
39 39 | pass
40 40 | else:
41 41 | """bar"""
42 |- pass
43 42 |
44 43 |
45 44 | def foo() -> None:
PIE790.py:50:5: PIE790 [*] Unnecessary `pass` statement
|
48 | """
49 |
50 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
47 47 | buzz
48 48 | """
49 49 |
50 |- pass
51 50 |
52 51 |
53 52 | async def foo():
PIE790.py:58:5: PIE790 [*] Unnecessary `pass` statement
|
56 | """
57 |
58 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
55 55 | buzz
56 56 | """
57 57 |
58 |- pass
59 58 |
60 59 |
61 60 | try:
PIE790.py:65:5: PIE790 [*] Unnecessary `pass` statement
|
63 | buzz
64 | """
65 | pass
| ^^^^ PIE790
66 | except ValueError:
67 | pass
|
= help: Remove unnecessary `pass`
Safe fix
62 62 | """
63 63 | buzz
64 64 | """
65 |- pass
66 65 | except ValueError:
67 66 | pass
68 67 |
PIE790.py:74:5: PIE790 [*] Unnecessary `pass` statement
|
72 | except ValueError:
73 | """bar"""
74 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
71 71 | bar()
72 72 | except ValueError:
73 73 | """bar"""
74 |- pass
75 74 |
76 75 |
77 76 | for _ in range(10):
PIE790.py:79:5: PIE790 [*] Unnecessary `pass` statement
|
77 | for _ in range(10):
78 | """buzz"""
79 | pass
| ^^^^ PIE790
80 |
81 | async for _ in range(10):
|
= help: Remove unnecessary `pass`
Safe fix
76 76 |
77 77 | for _ in range(10):
78 78 | """buzz"""
79 |- pass
80 79 |
81 80 | async for _ in range(10):
82 81 | """buzz"""
PIE790.py:83:5: PIE790 [*] Unnecessary `pass` statement
|
81 | async for _ in range(10):
82 | """buzz"""
83 | pass
| ^^^^ PIE790
84 |
85 | while cond:
|
= help: Remove unnecessary `pass`
Safe fix
80 80 |
81 81 | async for _ in range(10):
82 82 | """buzz"""
83 |- pass
84 83 |
85 84 | while cond:
86 85 | """buzz"""
PIE790.py:87:5: PIE790 [*] Unnecessary `pass` statement
|
85 | while cond:
86 | """buzz"""
87 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
84 84 |
85 85 | while cond:
86 86 | """buzz"""
87 |- pass
88 87 |
89 88 |
90 89 | with bar:
PIE790.py:92:5: PIE790 [*] Unnecessary `pass` statement
|
90 | with bar:
91 | """buzz"""
92 | pass
| ^^^^ PIE790
93 |
94 | async with bar:
|
= help: Remove unnecessary `pass`
Safe fix
89 89 |
90 90 | with bar:
91 91 | """buzz"""
92 |- pass
93 92 |
94 93 | async with bar:
95 94 | """buzz"""
PIE790.py:96:5: PIE790 [*] Unnecessary `pass` statement
|
94 | async with bar:
95 | """buzz"""
96 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
93 93 |
94 94 | async with bar:
95 95 | """buzz"""
96 |- pass
97 96 |
98 97 |
99 98 | def foo() -> None:
PIE790.py:101:5: PIE790 [*] Unnecessary `pass` statement
|
99 | def foo() -> None:
100 | """buzz"""
101 | pass # bar
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
98 98 |
99 99 | def foo() -> None:
100 100 | """buzz"""
101 |- pass # bar
101 |+ # bar
102 102 |
103 103 |
104 104 | class Foo:
PIE790.py:130:5: PIE790 [*] Unnecessary `pass` statement
|
128 | def foo():
129 | print("foo")
130 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
127 127 |
128 128 | def foo():
129 129 | print("foo")
130 |- pass
131 130 |
132 131 |
133 132 | def foo():
PIE790.py:136:5: PIE790 [*] Unnecessary `pass` statement
|
134 | """A docstring."""
135 | print("foo")
136 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
133 133 | def foo():
134 134 | """A docstring."""
135 135 | print("foo")
136 |- pass
137 136 |
138 137 |
139 138 | for i in range(10):
PIE790.py:140:5: PIE790 [*] Unnecessary `pass` statement
|
139 | for i in range(10):
140 | pass
| ^^^^ PIE790
141 | pass
|
= help: Remove unnecessary `pass`
Safe fix
138 138 |
139 139 | for i in range(10):
140 140 | pass
141 |- pass
142 141 |
143 142 | for i in range(10):
144 143 | pass
PIE790.py:141:5: PIE790 [*] Unnecessary `pass` statement
|
139 | for i in range(10):
140 | pass
141 | pass
| ^^^^ PIE790
142 |
143 | for i in range(10):
|
= help: Remove unnecessary `pass`
Safe fix
138 138 |
139 139 | for i in range(10):
140 140 | pass
141 |- pass
142 141 |
143 142 | for i in range(10):
144 143 | pass
PIE790.py:144:5: PIE790 [*] Unnecessary `pass` statement
|
143 | for i in range(10):
144 | pass
| ^^^^ PIE790
145 |
146 | pass
|
= help: Remove unnecessary `pass`
Safe fix
141 141 | pass
142 142 |
143 143 | for i in range(10):
144 |- pass
145 144 |
146 145 | pass
147 146 |
PIE790.py:146:5: PIE790 [*] Unnecessary `pass` statement
|
144 | pass
145 |
146 | pass
| ^^^^ PIE790
147 |
148 | for i in range(10):
|
= help: Remove unnecessary `pass`
Safe fix
143 143 | for i in range(10):
144 144 | pass
145 145 |
146 |- pass
147 146 |
148 147 | for i in range(10):
149 148 | pass # comment
PIE790.py:149:5: PIE790 [*] Unnecessary `pass` statement
|
148 | for i in range(10):
149 | pass # comment
| ^^^^ PIE790
150 | pass
|
= help: Remove unnecessary `pass`
Safe fix
146 146 | pass
147 147 |
148 148 | for i in range(10):
149 |- pass # comment
149 |+ # comment
150 150 | pass
151 151 |
152 152 |
PIE790.py:150:5: PIE790 [*] Unnecessary `pass` statement
|
148 | for i in range(10):
149 | pass # comment
150 | pass
| ^^^^ PIE790
|
= help: Remove unnecessary `pass`
Safe fix
147 147 |
148 148 | for i in range(10):
149 149 | pass # comment
150 |- pass
151 150 |
152 151 |
153 152 | def foo():
PIE790.py:155:5: PIE790 [*] Unnecessary `...` literal
|
153 | def foo():
154 | print("foo")
155 | ...
| ^^^ PIE790
|
= help: Remove unnecessary `...`
Safe fix
152 152 |
153 153 | def foo():
154 154 | print("foo")
155 |- ...
156 155 |
157 156 |
158 157 | def foo():
PIE790.py:161:5: PIE790 [*] Unnecessary `...` literal
|
159 | """A docstring."""
160 | print("foo")
161 | ...
| ^^^ PIE790
|
= help: Remove unnecessary `...`
Safe fix
158 158 | def foo():
159 159 | """A docstring."""
160 160 | print("foo")
161 |- ...
162 161 |
163 162 |
164 163 | for i in range(10):
PIE790.py:165:5: PIE790 [*] Unnecessary `...` literal
|
164 | for i in range(10):
165 | ...
| ^^^ PIE790
166 | ...
|
= help: Remove unnecessary `...`
Safe fix
163 163 |
164 164 | for i in range(10):
165 165 | ...
166 |- ...
167 166 |
168 167 | for i in range(10):
169 168 | ...
PIE790.py:166:5: PIE790 [*] Unnecessary `...` literal
|
164 | for i in range(10):
165 | ...
166 | ...
| ^^^ PIE790
167 |
168 | for i in range(10):
|
= help: Remove unnecessary `...`
Safe fix
163 163 |
164 164 | for i in range(10):
165 165 | ...
166 |- ...
167 166 |
168 167 | for i in range(10):
169 168 | ...
PIE790.py:169:5: PIE790 [*] Unnecessary `...` literal
|
168 | for i in range(10):
169 | ...
| ^^^ PIE790
170 |
171 | ...
|
= help: Remove unnecessary `...`
Safe fix
166 166 | ...
167 167 |
168 168 | for i in range(10):
169 |- ...
170 169 |
171 170 | ...
172 171 |
PIE790.py:171:5: PIE790 [*] Unnecessary `...` literal
|
169 | ...
170 |
171 | ...
| ^^^ PIE790
172 |
173 | for i in range(10):
|
= help: Remove unnecessary `...`
Safe fix
168 168 | for i in range(10):
169 169 | ...
170 170 |
171 |- ...
172 171 |
173 172 | for i in range(10):
174 173 | ... # comment
PIE790.py:174:5: PIE790 [*] Unnecessary `...` literal
|
173 | for i in range(10):
174 | ... # comment
| ^^^ PIE790
175 | ...
|
= help: Remove unnecessary `...`
Safe fix
171 171 | ...
172 172 |
173 173 | for i in range(10):
174 |- ... # comment
174 |+ # comment
175 175 | ...
176 176 |
177 177 | for i in range(10):
PIE790.py:175:5: PIE790 [*] Unnecessary `...` literal
|
173 | for i in range(10):
174 | ... # comment
175 | ...
| ^^^ PIE790
176 |
177 | for i in range(10):
|
= help: Remove unnecessary `...`
Safe fix
172 172 |
173 173 | for i in range(10):
174 174 | ... # comment
175 |- ...
176 175 |
177 176 | for i in range(10):
178 177 | ...
PIE790.py:178:5: PIE790 [*] Unnecessary `...` literal
|
177 | for i in range(10):
178 | ...
| ^^^ PIE790
179 | pass
|
= help: Remove unnecessary `...`
Safe fix
175 175 | ...
176 176 |
177 177 | for i in range(10):
178 |- ...
179 178 | pass
180 179 |
181 180 | from typing import Protocol
PIE790.py:179:5: PIE790 [*] Unnecessary `pass` statement
|
177 | for i in range(10):
178 | ...
179 | pass
| ^^^^ PIE790
180 |
181 | from typing import Protocol
|
= help: Remove unnecessary `pass`
Safe fix
176 176 |
177 177 | for i in range(10):
178 178 | ...
179 |- pass
180 179 |
181 180 | from typing import Protocol
182 181 |
PIE790.py:209:9: PIE790 [*] Unnecessary `...` literal
|
207 | def stub(self) -> str:
208 | """Docstring"""
209 | ...
| ^^^ PIE790
|
= help: Remove unnecessary `...`
Safe fix
206 206 |
207 207 | def stub(self) -> str:
208 208 | """Docstring"""
209 |- ...

View File

@@ -1,134 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pie/mod.rs
---
PIE800.py:1:14: PIE800 [*] Unnecessary spread `**`
|
1 | {"foo": 1, **{"bar": 1}} # PIE800
| ^^^^^^^^^^ PIE800
2 |
3 | {**{"bar": 10}, "a": "b"} # PIE800
|
= help: Remove unnecessary dict
Safe fix
1 |-{"foo": 1, **{"bar": 1}} # PIE800
1 |+{"foo": 1, "bar": 1} # PIE800
2 2 |
3 3 | {**{"bar": 10}, "a": "b"} # PIE800
4 4 |
PIE800.py:3:4: PIE800 [*] Unnecessary spread `**`
|
1 | {"foo": 1, **{"bar": 1}} # PIE800
2 |
3 | {**{"bar": 10}, "a": "b"} # PIE800
| ^^^^^^^^^^^ PIE800
4 |
5 | foo({**foo, **{"bar": True}}) # PIE800
|
= help: Remove unnecessary dict
Safe fix
1 1 | {"foo": 1, **{"bar": 1}} # PIE800
2 2 |
3 |-{**{"bar": 10}, "a": "b"} # PIE800
3 |+{"bar": 10, "a": "b"} # PIE800
4 4 |
5 5 | foo({**foo, **{"bar": True}}) # PIE800
6 6 |
PIE800.py:5:15: PIE800 [*] Unnecessary spread `**`
|
3 | {**{"bar": 10}, "a": "b"} # PIE800
4 |
5 | foo({**foo, **{"bar": True}}) # PIE800
| ^^^^^^^^^^^^^ PIE800
6 |
7 | {**foo, **{"bar": 10}} # PIE800
|
= help: Remove unnecessary dict
Safe fix
2 2 |
3 3 | {**{"bar": 10}, "a": "b"} # PIE800
4 4 |
5 |-foo({**foo, **{"bar": True}}) # PIE800
5 |+foo({**foo, "bar": True}) # PIE800
6 6 |
7 7 | {**foo, **{"bar": 10}} # PIE800
8 8 |
PIE800.py:7:11: PIE800 [*] Unnecessary spread `**`
|
5 | foo({**foo, **{"bar": True}}) # PIE800
6 |
7 | {**foo, **{"bar": 10}} # PIE800
| ^^^^^^^^^^^ PIE800
8 |
9 | { # PIE800
|
= help: Remove unnecessary dict
Safe fix
4 4 |
5 5 | foo({**foo, **{"bar": True}}) # PIE800
6 6 |
7 |-{**foo, **{"bar": 10}} # PIE800
7 |+{**foo, "bar": 10} # PIE800
8 8 |
9 9 | { # PIE800
10 10 | "a": "b",
PIE800.py:12:7: PIE800 [*] Unnecessary spread `**`
|
10 | "a": "b",
11 | # Preserve
12 | **{
| _______^
13 | | # all
14 | | "bar": 10, # the
15 | | # comments
16 | | },
| |_____^ PIE800
17 | }
|
= help: Remove unnecessary dict
Safe fix
9 9 | { # PIE800
10 10 | "a": "b",
11 11 | # Preserve
12 |- **{
12 |+
13 13 | # all
14 |- "bar": 10, # the
14 |+ "bar": 10 # the
15 15 | # comments
16 |- },
16 |+ ,
17 17 | }
18 18 |
19 19 | {**foo, **buzz, **{bar: 10}} # PIE800
PIE800.py:19:19: PIE800 [*] Unnecessary spread `**`
|
17 | }
18 |
19 | {**foo, **buzz, **{bar: 10}} # PIE800
| ^^^^^^^^^ PIE800
20 |
21 | {**foo, "bar": True } # OK
|
= help: Remove unnecessary dict
Safe fix
16 16 | },
17 17 | }
18 18 |
19 |-{**foo, **buzz, **{bar: 10}} # PIE800
19 |+{**foo, **buzz, bar: 10} # PIE800
20 20 |
21 21 | {**foo, "bar": True } # OK
22 22 |

View File

@@ -1,118 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_pie/mod.rs
---
PIE807.py:3:44: PIE807 [*] Prefer `list` over useless lambda
|
1 | @dataclass
2 | class Foo:
3 | foo: List[str] = field(default_factory=lambda: []) # PIE807
| ^^^^^^^^^^ PIE807
4 | bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
|
= help: Replace with `lambda` with `list`
Safe fix
1 1 | @dataclass
2 2 | class Foo:
3 |- foo: List[str] = field(default_factory=lambda: []) # PIE807
3 |+ foo: List[str] = field(default_factory=list) # PIE807
4 4 | bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
5 5 |
6 6 |
PIE807.py:4:49: PIE807 [*] Prefer `dict` over useless lambda
|
2 | class Foo:
3 | foo: List[str] = field(default_factory=lambda: []) # PIE807
4 | bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
| ^^^^^^^^^^ PIE807
|
= help: Replace with `lambda` with `dict`
Safe fix
1 1 | @dataclass
2 2 | class Foo:
3 3 | foo: List[str] = field(default_factory=lambda: []) # PIE807
4 |- bar: Dict[str, int] = field(default_factory=lambda: {}) # PIE807
4 |+ bar: Dict[str, int] = field(default_factory=dict) # PIE807
5 5 |
6 6 |
7 7 | class FooTable(BaseTable):
PIE807.py:8:36: PIE807 [*] Prefer `list` over useless lambda
|
7 | class FooTable(BaseTable):
8 | foo = fields.ListField(default=lambda: []) # PIE807
| ^^^^^^^^^^ PIE807
9 | bar = fields.ListField(default=lambda: {}) # PIE807
|
= help: Replace with `lambda` with `list`
Safe fix
5 5 |
6 6 |
7 7 | class FooTable(BaseTable):
8 |- foo = fields.ListField(default=lambda: []) # PIE807
8 |+ foo = fields.ListField(default=list) # PIE807
9 9 | bar = fields.ListField(default=lambda: {}) # PIE807
10 10 |
11 11 |
PIE807.py:9:36: PIE807 [*] Prefer `dict` over useless lambda
|
7 | class FooTable(BaseTable):
8 | foo = fields.ListField(default=lambda: []) # PIE807
9 | bar = fields.ListField(default=lambda: {}) # PIE807
| ^^^^^^^^^^ PIE807
|
= help: Replace with `lambda` with `dict`
Safe fix
6 6 |
7 7 | class FooTable(BaseTable):
8 8 | foo = fields.ListField(default=lambda: []) # PIE807
9 |- bar = fields.ListField(default=lambda: {}) # PIE807
9 |+ bar = fields.ListField(default=dict) # PIE807
10 10 |
11 11 |
12 12 | class FooTable(BaseTable):
PIE807.py:13:28: PIE807 [*] Prefer `list` over useless lambda
|
12 | class FooTable(BaseTable):
13 | foo = fields.ListField(lambda: []) # PIE807
| ^^^^^^^^^^ PIE807
14 | bar = fields.ListField(default=lambda: {}) # PIE807
|
= help: Replace with `lambda` with `list`
Safe fix
10 10 |
11 11 |
12 12 | class FooTable(BaseTable):
13 |- foo = fields.ListField(lambda: []) # PIE807
13 |+ foo = fields.ListField(list) # PIE807
14 14 | bar = fields.ListField(default=lambda: {}) # PIE807
15 15 |
16 16 |
PIE807.py:14:36: PIE807 [*] Prefer `dict` over useless lambda
|
12 | class FooTable(BaseTable):
13 | foo = fields.ListField(lambda: []) # PIE807
14 | bar = fields.ListField(default=lambda: {}) # PIE807
| ^^^^^^^^^^ PIE807
|
= help: Replace with `lambda` with `dict`
Safe fix
11 11 |
12 12 | class FooTable(BaseTable):
13 13 | foo = fields.ListField(lambda: []) # PIE807
14 |- bar = fields.ListField(default=lambda: {}) # PIE807
14 |+ bar = fields.ListField(default=dict) # PIE807
15 15 |
16 16 |
17 17 | @dataclass

View File

@@ -1,4 +1,4 @@
use ruff_diagnostics::{Diagnostic, Fix, FixAvailability, Violation};
use ruff_diagnostics::{Applicability, Diagnostic, Fix, FixAvailability, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_semantic::Imported;
use ruff_python_semantic::{Binding, BindingKind};
@@ -29,6 +29,12 @@ use crate::renamer::Renamer;
/// ```python
/// from collections.abc import Set as AbstractSet
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as unsafe for `Set` imports defined at the
/// top-level of a module. Top-level symbols are implicitly exported by the
/// module, and so renaming a top-level symbol may break downstream modules
/// that import it.
#[violation]
pub struct UnaliasedCollectionsAbcSetImport;
@@ -69,7 +75,15 @@ pub(crate) fn unaliased_collections_abc_set_import(
diagnostic.try_set_fix(|| {
let scope = &checker.semantic().scopes[binding.scope];
let (edit, rest) = Renamer::rename(name, "AbstractSet", scope, checker.semantic())?;
Ok(Fix::unsafe_edits(edit, rest))
Ok(Fix::applicable_edits(
edit,
rest,
if scope.kind.is_module() {
Applicability::Unsafe
} else {
Applicability::Safe
},
))
});
}
Some(diagnostic)

View File

@@ -116,7 +116,7 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp
expr.range(),
);
if checker.settings.preview.is_enabled() {
diagnostic.set_fix({
let literal = Expr::Subscript(ast::ExprSubscript {
value: Box::new(literal_subscript.clone()),
slice: Box::new(Expr::Tuple(ast::ExprTuple {
@@ -130,10 +130,10 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp
if other_exprs.is_empty() {
// if the union is only literals, we just replace the whole thing with a single literal
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
Fix::safe_edit(Edit::range_replacement(
checker.generator().expr(&literal),
expr.range(),
)));
))
} else {
let elts: Vec<Expr> = std::iter::once(literal)
.chain(other_exprs.into_iter().cloned())
@@ -156,12 +156,9 @@ pub(crate) fn unnecessary_literal_union<'a>(checker: &mut Checker, expr: &'a Exp
checker.generator().expr(&pep_604_union(&elts))
};
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
content,
expr.range(),
)));
Fix::safe_edit(Edit::range_replacement(content, expr.range()))
}
}
});
checker.diagnostics.push(diagnostic);
}

View File

@@ -9,7 +9,7 @@ PYI025.py:10:33: PYI025 [*] Use `from collections.abc import Set as AbstractSet`
|
= help: Alias `Set` to `AbstractSet`
Unsafe fix
Safe fix
7 7 |
8 8 |
9 9 | def f():
@@ -29,7 +29,7 @@ PYI025.py:14:51: PYI025 [*] Use `from collections.abc import Set as AbstractSet`
|
= help: Alias `Set` to `AbstractSet`
Unsafe fix
Safe fix
11 11 |
12 12 |
13 13 | def f():

View File

@@ -11,7 +11,7 @@ PYI025.pyi:8:33: PYI025 [*] Use `from collections.abc import Set as AbstractSet`
|
= help: Alias `Set` to `AbstractSet`
Unsafe fix
Safe fix
5 5 | from collections.abc import Container, Sized, Set as AbstractSet, ValuesView # Ok
6 6 |
7 7 | def f():
@@ -31,7 +31,7 @@ PYI025.pyi:11:51: PYI025 [*] Use `from collections.abc import Set as AbstractSet
|
= help: Alias `Set` to `AbstractSet`
Unsafe fix
Safe fix
8 8 | from collections.abc import Set # PYI025
9 9 |
10 10 | def f():
@@ -52,7 +52,7 @@ PYI025.pyi:16:37: PYI025 [*] Use `from collections.abc import Set as AbstractSet
|
= help: Alias `Set` to `AbstractSet`
Unsafe fix
Safe fix
13 13 | def f():
14 14 | """Test: local symbol renaming."""
15 15 | if True:
@@ -130,7 +130,7 @@ PYI025.pyi:44:33: PYI025 [*] Use `from collections.abc import Set as AbstractSet
|
= help: Alias `Set` to `AbstractSet`
Unsafe fix
Safe fix
41 41 |
42 42 | def f():
43 43 | """Test: nonlocal symbol renaming."""

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI030.py:9:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
PYI030.py:9:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
8 | # Should emit for duplicate field types.
9 | field2: Literal[1] | Literal[2] # Error
@@ -11,7 +11,17 @@ PYI030.py:9:9: PYI030 Multiple literal members in a union. Use a single literal,
|
= help: Replace with a single `Literal`
PYI030.py:12:17: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
6 6 | field1: Literal[1] # OK
7 7 |
8 8 | # Should emit for duplicate field types.
9 |-field2: Literal[1] | Literal[2] # Error
9 |+field2: Literal[1, 2] # Error
10 10 |
11 11 | # Should emit for union types in arguments.
12 12 | def func1(arg1: Literal[1] | Literal[2]): # Error
PYI030.py:12:17: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
11 | # Should emit for union types in arguments.
12 | def func1(arg1: Literal[1] | Literal[2]): # Error
@@ -20,7 +30,17 @@ PYI030.py:12:17: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:17:16: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
9 9 | field2: Literal[1] | Literal[2] # Error
10 10 |
11 11 | # Should emit for union types in arguments.
12 |-def func1(arg1: Literal[1] | Literal[2]): # Error
12 |+def func1(arg1: Literal[1, 2]): # Error
13 13 | print(arg1)
14 14 |
15 15 |
PYI030.py:17:16: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
16 | # Should emit for unions in return types.
17 | def func2() -> Literal[1] | Literal[2]: # Error
@@ -29,7 +49,17 @@ PYI030.py:17:16: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:22:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
14 14 |
15 15 |
16 16 | # Should emit for unions in return types.
17 |-def func2() -> Literal[1] | Literal[2]: # Error
17 |+def func2() -> Literal[1, 2]: # Error
18 18 | return "my Literal[1]ing"
19 19 |
20 20 |
PYI030.py:22:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
21 | # Should emit in longer unions, even if not directly adjacent.
22 | field3: Literal[1] | Literal[2] | str # Error
@@ -39,7 +69,17 @@ PYI030.py:22:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.py:23:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
19 19 |
20 20 |
21 21 | # Should emit in longer unions, even if not directly adjacent.
22 |-field3: Literal[1] | Literal[2] | str # Error
22 |+field3: Literal[1, 2] | str # Error
23 23 | field4: str | Literal[1] | Literal[2] # Error
24 24 | field5: Literal[1] | str | Literal[2] # Error
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
PYI030.py:23:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
21 | # Should emit in longer unions, even if not directly adjacent.
22 | field3: Literal[1] | Literal[2] | str # Error
@@ -50,7 +90,17 @@ PYI030.py:23:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.py:24:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
20 20 |
21 21 | # Should emit in longer unions, even if not directly adjacent.
22 22 | field3: Literal[1] | Literal[2] | str # Error
23 |-field4: str | Literal[1] | Literal[2] # Error
23 |+field4: Literal[1, 2] | str # Error
24 24 | field5: Literal[1] | str | Literal[2] # Error
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
26 26 |
PYI030.py:24:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
22 | field3: Literal[1] | Literal[2] | str # Error
23 | field4: str | Literal[1] | Literal[2] # Error
@@ -60,7 +110,17 @@ PYI030.py:24:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.py:25:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
21 21 | # Should emit in longer unions, even if not directly adjacent.
22 22 | field3: Literal[1] | Literal[2] | str # Error
23 23 | field4: str | Literal[1] | Literal[2] # Error
24 |-field5: Literal[1] | str | Literal[2] # Error
24 |+field5: Literal[1, 2] | str # Error
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
26 26 |
27 27 | # Should emit for non-type unions.
PYI030.py:25:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
23 | field4: str | Literal[1] | Literal[2] # Error
24 | field5: Literal[1] | str | Literal[2] # Error
@@ -71,7 +131,17 @@ PYI030.py:25:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.py:28:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
22 22 | field3: Literal[1] | Literal[2] | str # Error
23 23 | field4: str | Literal[1] | Literal[2] # Error
24 24 | field5: Literal[1] | str | Literal[2] # Error
25 |-field6: Literal[1] | bool | Literal[2] | str # Error
25 |+field6: Literal[1, 2] | bool | str # Error
26 26 |
27 27 | # Should emit for non-type unions.
28 28 | field7 = Literal[1] | Literal[2] # Error
PYI030.py:28:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
27 | # Should emit for non-type unions.
28 | field7 = Literal[1] | Literal[2] # Error
@@ -81,7 +151,17 @@ PYI030.py:28:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:31:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
26 26 |
27 27 | # Should emit for non-type unions.
28 |-field7 = Literal[1] | Literal[2] # Error
28 |+field7 = Literal[1, 2] # Error
29 29 |
30 30 | # Should emit for parenthesized unions.
31 31 | field8: Literal[1] | (Literal[2] | str) # Error
PYI030.py:31:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
30 | # Should emit for parenthesized unions.
31 | field8: Literal[1] | (Literal[2] | str) # Error
@@ -91,7 +171,17 @@ PYI030.py:31:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.py:34:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
28 28 | field7 = Literal[1] | Literal[2] # Error
29 29 |
30 30 | # Should emit for parenthesized unions.
31 |-field8: Literal[1] | (Literal[2] | str) # Error
31 |+field8: Literal[1, 2] | str # Error
32 32 |
33 33 | # Should handle user parentheses when fixing.
34 34 | field9: Literal[1] | (Literal[2] | str) # Error
PYI030.py:34:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
33 | # Should handle user parentheses when fixing.
34 | field9: Literal[1] | (Literal[2] | str) # Error
@@ -100,7 +190,17 @@ PYI030.py:34:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.py:35:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
31 31 | field8: Literal[1] | (Literal[2] | str) # Error
32 32 |
33 33 | # Should handle user parentheses when fixing.
34 |-field9: Literal[1] | (Literal[2] | str) # Error
34 |+field9: Literal[1, 2] | str # Error
35 35 | field10: (Literal[1] | str) | Literal[2] # Error
36 36 |
37 37 | # Should emit for union in generic parent type.
PYI030.py:35:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
33 | # Should handle user parentheses when fixing.
34 | field9: Literal[1] | (Literal[2] | str) # Error
@@ -111,7 +211,17 @@ PYI030.py:35:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:38:15: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
32 32 |
33 33 | # Should handle user parentheses when fixing.
34 34 | field9: Literal[1] | (Literal[2] | str) # Error
35 |-field10: (Literal[1] | str) | Literal[2] # Error
35 |+field10: Literal[1, 2] | str # Error
36 36 |
37 37 | # Should emit for union in generic parent type.
38 38 | field11: dict[Literal[1] | Literal[2], str] # Error
PYI030.py:38:15: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
37 | # Should emit for union in generic parent type.
38 | field11: dict[Literal[1] | Literal[2], str] # Error
@@ -121,7 +231,17 @@ PYI030.py:38:15: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:41:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
Safe fix
35 35 | field10: (Literal[1] | str) | Literal[2] # Error
36 36 |
37 37 | # Should emit for union in generic parent type.
38 |-field11: dict[Literal[1] | Literal[2], str] # Error
38 |+field11: dict[Literal[1, 2], str] # Error
39 39 |
40 40 | # Should emit for unions with more than two cases
41 41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
PYI030.py:41:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
|
40 | # Should emit for unions with more than two cases
41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
@@ -130,7 +250,17 @@ PYI030.py:41:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:42:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
38 38 | field11: dict[Literal[1] | Literal[2], str] # Error
39 39 |
40 40 | # Should emit for unions with more than two cases
41 |-field12: Literal[1] | Literal[2] | Literal[3] # Error
41 |+field12: Literal[1, 2, 3] # Error
42 42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error
43 43 |
44 44 | # Should emit for unions with more than two cases, even if not directly adjacent
PYI030.py:42:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
40 | # Should emit for unions with more than two cases
41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
@@ -141,7 +271,17 @@ PYI030.py:42:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:45:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
Safe fix
39 39 |
40 40 | # Should emit for unions with more than two cases
41 41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
42 |-field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error
42 |+field13: Literal[1, 2, 3, 4] # Error
43 43 |
44 44 | # Should emit for unions with more than two cases, even if not directly adjacent
45 45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error
PYI030.py:45:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
|
44 | # Should emit for unions with more than two cases, even if not directly adjacent
45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error
@@ -151,7 +291,17 @@ PYI030.py:45:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:48:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, "foo", True]`
Safe fix
42 42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error
43 43 |
44 44 | # Should emit for unions with more than two cases, even if not directly adjacent
45 |-field14: Literal[1] | Literal[2] | str | Literal[3] # Error
45 |+field14: Literal[1, 2, 3] | str # Error
46 46 |
47 47 | # Should emit for unions with mixed literal internal types
48 48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error
PYI030.py:48:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, "foo", True]`
|
47 | # Should emit for unions with mixed literal internal types
48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error
@@ -161,7 +311,17 @@ PYI030.py:48:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:51:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 1]`
Safe fix
45 45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error
46 46 |
47 47 | # Should emit for unions with mixed literal internal types
48 |-field15: Literal[1] | Literal["foo"] | Literal[True] # Error
48 |+field15: Literal[1, "foo", True] # Error
49 49 |
50 50 | # Shouldn't emit for duplicate field types with same value; covered by Y016
51 51 | field16: Literal[1] | Literal[1] # OK
PYI030.py:51:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 1]`
|
50 | # Shouldn't emit for duplicate field types with same value; covered by Y016
51 | field16: Literal[1] | Literal[1] # OK
@@ -171,7 +331,17 @@ PYI030.py:51:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:60:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
48 48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error
49 49 |
50 50 | # Shouldn't emit for duplicate field types with same value; covered by Y016
51 |-field16: Literal[1] | Literal[1] # OK
51 |+field16: Literal[1, 1] # OK
52 52 |
53 53 | # Shouldn't emit if in new parent type
54 54 | field17: Literal[1] | dict[Literal[2], str] # OK
PYI030.py:60:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
59 | # Should respect name of literal type used
60 | field19: typing.Literal[1] | typing.Literal[2] # Error
@@ -181,7 +351,17 @@ PYI030.py:60:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:63:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
57 57 | field18: dict[Literal[1], Literal[2]] # OK
58 58 |
59 59 | # Should respect name of literal type used
60 |-field19: typing.Literal[1] | typing.Literal[2] # Error
60 |+field19: typing.Literal[1, 2] # Error
61 61 |
62 62 | # Should emit in cases with newlines
63 63 | field20: typing.Union[
PYI030.py:63:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
62 | # Should emit in cases with newlines
63 | field20: typing.Union[
@@ -197,7 +377,22 @@ PYI030.py:63:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:71:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
60 60 | field19: typing.Literal[1] | typing.Literal[2] # Error
61 61 |
62 62 | # Should emit in cases with newlines
63 |-field20: typing.Union[
64 |- Literal[
65 |- 1 # test
66 |- ],
67 |- Literal[2],
68 |-] # Error, newline and comment will not be emitted in message
63 |+field20: Literal[1, 2] # Error, newline and comment will not be emitted in message
69 64 |
70 65 | # Should handle multiple unions with multiple members
71 66 | field21: Literal[1, 2] | Literal[3, 4] # Error
PYI030.py:71:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
70 | # Should handle multiple unions with multiple members
71 | field21: Literal[1, 2] | Literal[3, 4] # Error
@@ -207,7 +402,17 @@ PYI030.py:71:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:74:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
68 68 | ] # Error, newline and comment will not be emitted in message
69 69 |
70 70 | # Should handle multiple unions with multiple members
71 |-field21: Literal[1, 2] | Literal[3, 4] # Error
71 |+field21: Literal[1, 2, 3, 4] # Error
72 72 |
73 73 | # Should emit in cases with `typing.Union` instead of `|`
74 74 | field22: typing.Union[Literal[1], Literal[2]] # Error
PYI030.py:74:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
73 | # Should emit in cases with `typing.Union` instead of `|`
74 | field22: typing.Union[Literal[1], Literal[2]] # Error
@@ -217,7 +422,17 @@ PYI030.py:74:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:77:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
71 71 | field21: Literal[1, 2] | Literal[3, 4] # Error
72 72 |
73 73 | # Should emit in cases with `typing.Union` instead of `|`
74 |-field22: typing.Union[Literal[1], Literal[2]] # Error
74 |+field22: Literal[1, 2] # Error
75 75 |
76 76 | # Should emit in cases with `typing_extensions.Literal`
77 77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
PYI030.py:77:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
76 | # Should emit in cases with `typing_extensions.Literal`
77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
@@ -227,7 +442,17 @@ PYI030.py:77:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:80:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
74 74 | field22: typing.Union[Literal[1], Literal[2]] # Error
75 75 |
76 76 | # Should emit in cases with `typing_extensions.Literal`
77 |-field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
77 |+field23: typing_extensions.Literal[1, 2] # Error
78 78 |
79 79 | # Should emit in cases with nested `typing.Union`
80 80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
PYI030.py:80:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
79 | # Should emit in cases with nested `typing.Union`
80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
@@ -237,7 +462,17 @@ PYI030.py:80:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:83:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
77 77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
78 78 |
79 79 | # Should emit in cases with nested `typing.Union`
80 |-field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
80 |+field24: typing.Union[Literal[1, 2], str] # Error
81 81 |
82 82 | # Should emit in cases with mixed `typing.Union` and `|`
83 83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error
PYI030.py:83:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
82 | # Should emit in cases with mixed `typing.Union` and `|`
83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error
@@ -247,7 +482,17 @@ PYI030.py:83:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:86:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
80 80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
81 81 |
82 82 | # Should emit in cases with mixed `typing.Union` and `|`
83 |-field25: typing.Union[Literal[1], Literal[2] | str] # Error
83 |+field25: typing.Union[Literal[1, 2], str] # Error
84 84 |
85 85 | # Should emit only once in cases with multiple nested `typing.Union`
86 86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
PYI030.py:86:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
85 | # Should emit only once in cases with multiple nested `typing.Union`
86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
@@ -257,7 +502,17 @@ PYI030.py:86:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.py:89:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
83 83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error
84 84 |
85 85 | # Should emit only once in cases with multiple nested `typing.Union`
86 |-field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
86 |+field24: Literal[1, 2, 3, 4] # Error
87 87 |
88 88 | # Should use the first literal subscript attribute when fixing
89 89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
PYI030.py:89:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
88 | # Should use the first literal subscript attribute when fixing
89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
@@ -265,4 +520,11 @@ PYI030.py:89:10: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
Safe fix
86 86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
87 87 |
88 88 | # Should use the first literal subscript attribute when fixing
89 |-field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
89 |+field25: typing.Union[typing_extensions.Literal[1, 2, 3, 4], str] # Error

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_pyi/mod.rs
---
PYI030.pyi:9:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
PYI030.pyi:9:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
8 | # Should emit for duplicate field types.
9 | field2: Literal[1] | Literal[2] # Error
@@ -11,7 +11,17 @@ PYI030.pyi:9:9: PYI030 Multiple literal members in a union. Use a single literal
|
= help: Replace with a single `Literal`
PYI030.pyi:12:17: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
6 6 | field1: Literal[1] # OK
7 7 |
8 8 | # Should emit for duplicate field types.
9 |-field2: Literal[1] | Literal[2] # Error
9 |+field2: Literal[1, 2] # Error
10 10 |
11 11 | # Should emit for union types in arguments.
12 12 | def func1(arg1: Literal[1] | Literal[2]): # Error
PYI030.pyi:12:17: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
11 | # Should emit for union types in arguments.
12 | def func1(arg1: Literal[1] | Literal[2]): # Error
@@ -20,7 +30,17 @@ PYI030.pyi:12:17: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:17:16: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
9 9 | field2: Literal[1] | Literal[2] # Error
10 10 |
11 11 | # Should emit for union types in arguments.
12 |-def func1(arg1: Literal[1] | Literal[2]): # Error
12 |+def func1(arg1: Literal[1, 2]): # Error
13 13 | print(arg1)
14 14 |
15 15 |
PYI030.pyi:17:16: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
16 | # Should emit for unions in return types.
17 | def func2() -> Literal[1] | Literal[2]: # Error
@@ -29,7 +49,17 @@ PYI030.pyi:17:16: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:22:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
14 14 |
15 15 |
16 16 | # Should emit for unions in return types.
17 |-def func2() -> Literal[1] | Literal[2]: # Error
17 |+def func2() -> Literal[1, 2]: # Error
18 18 | return "my Literal[1]ing"
19 19 |
20 20 |
PYI030.pyi:22:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
21 | # Should emit in longer unions, even if not directly adjacent.
22 | field3: Literal[1] | Literal[2] | str # Error
@@ -39,7 +69,17 @@ PYI030.pyi:22:9: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.pyi:23:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
19 19 |
20 20 |
21 21 | # Should emit in longer unions, even if not directly adjacent.
22 |-field3: Literal[1] | Literal[2] | str # Error
22 |+field3: Literal[1, 2] | str # Error
23 23 | field4: str | Literal[1] | Literal[2] # Error
24 24 | field5: Literal[1] | str | Literal[2] # Error
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
PYI030.pyi:23:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
21 | # Should emit in longer unions, even if not directly adjacent.
22 | field3: Literal[1] | Literal[2] | str # Error
@@ -50,7 +90,17 @@ PYI030.pyi:23:9: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.pyi:24:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
20 20 |
21 21 | # Should emit in longer unions, even if not directly adjacent.
22 22 | field3: Literal[1] | Literal[2] | str # Error
23 |-field4: str | Literal[1] | Literal[2] # Error
23 |+field4: Literal[1, 2] | str # Error
24 24 | field5: Literal[1] | str | Literal[2] # Error
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
26 26 |
PYI030.pyi:24:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
22 | field3: Literal[1] | Literal[2] | str # Error
23 | field4: str | Literal[1] | Literal[2] # Error
@@ -60,7 +110,17 @@ PYI030.pyi:24:9: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.pyi:25:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
21 21 | # Should emit in longer unions, even if not directly adjacent.
22 22 | field3: Literal[1] | Literal[2] | str # Error
23 23 | field4: str | Literal[1] | Literal[2] # Error
24 |-field5: Literal[1] | str | Literal[2] # Error
24 |+field5: Literal[1, 2] | str # Error
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
26 26 |
27 27 | # Should emit for non-type unions.
PYI030.pyi:25:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
23 | field4: str | Literal[1] | Literal[2] # Error
24 | field5: Literal[1] | str | Literal[2] # Error
@@ -71,7 +131,17 @@ PYI030.pyi:25:9: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.pyi:28:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
22 22 | field3: Literal[1] | Literal[2] | str # Error
23 23 | field4: str | Literal[1] | Literal[2] # Error
24 24 | field5: Literal[1] | str | Literal[2] # Error
25 |-field6: Literal[1] | bool | Literal[2] | str # Error
25 |+field6: Literal[1, 2] | bool | str # Error
26 26 |
27 27 | # Should emit for non-type unions.
28 28 | field7 = Literal[1] | Literal[2] # Error
PYI030.pyi:28:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
27 | # Should emit for non-type unions.
28 | field7 = Literal[1] | Literal[2] # Error
@@ -81,7 +151,17 @@ PYI030.pyi:28:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:31:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
25 25 | field6: Literal[1] | bool | Literal[2] | str # Error
26 26 |
27 27 | # Should emit for non-type unions.
28 |-field7 = Literal[1] | Literal[2] # Error
28 |+field7 = Literal[1, 2] # Error
29 29 |
30 30 | # Should emit for parenthesized unions.
31 31 | field8: Literal[1] | (Literal[2] | str) # Error
PYI030.pyi:31:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
30 | # Should emit for parenthesized unions.
31 | field8: Literal[1] | (Literal[2] | str) # Error
@@ -91,7 +171,17 @@ PYI030.pyi:31:9: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.pyi:34:9: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
28 28 | field7 = Literal[1] | Literal[2] # Error
29 29 |
30 30 | # Should emit for parenthesized unions.
31 |-field8: Literal[1] | (Literal[2] | str) # Error
31 |+field8: Literal[1, 2] | str # Error
32 32 |
33 33 | # Should handle user parentheses when fixing.
34 34 | field9: Literal[1] | (Literal[2] | str) # Error
PYI030.pyi:34:9: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
33 | # Should handle user parentheses when fixing.
34 | field9: Literal[1] | (Literal[2] | str) # Error
@@ -100,7 +190,17 @@ PYI030.pyi:34:9: PYI030 Multiple literal members in a union. Use a single litera
|
= help: Replace with a single `Literal`
PYI030.pyi:35:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
31 31 | field8: Literal[1] | (Literal[2] | str) # Error
32 32 |
33 33 | # Should handle user parentheses when fixing.
34 |-field9: Literal[1] | (Literal[2] | str) # Error
34 |+field9: Literal[1, 2] | str # Error
35 35 | field10: (Literal[1] | str) | Literal[2] # Error
36 36 |
37 37 | # Should emit for union in generic parent type.
PYI030.pyi:35:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
33 | # Should handle user parentheses when fixing.
34 | field9: Literal[1] | (Literal[2] | str) # Error
@@ -111,7 +211,17 @@ PYI030.pyi:35:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:38:15: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
32 32 |
33 33 | # Should handle user parentheses when fixing.
34 34 | field9: Literal[1] | (Literal[2] | str) # Error
35 |-field10: (Literal[1] | str) | Literal[2] # Error
35 |+field10: Literal[1, 2] | str # Error
36 36 |
37 37 | # Should emit for union in generic parent type.
38 38 | field11: dict[Literal[1] | Literal[2], str] # Error
PYI030.pyi:38:15: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
37 | # Should emit for union in generic parent type.
38 | field11: dict[Literal[1] | Literal[2], str] # Error
@@ -121,7 +231,17 @@ PYI030.pyi:38:15: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:41:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
Safe fix
35 35 | field10: (Literal[1] | str) | Literal[2] # Error
36 36 |
37 37 | # Should emit for union in generic parent type.
38 |-field11: dict[Literal[1] | Literal[2], str] # Error
38 |+field11: dict[Literal[1, 2], str] # Error
39 39 |
40 40 | # Should emit for unions with more than two cases
41 41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
PYI030.pyi:41:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
|
40 | # Should emit for unions with more than two cases
41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
@@ -130,7 +250,17 @@ PYI030.pyi:41:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:42:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
38 38 | field11: dict[Literal[1] | Literal[2], str] # Error
39 39 |
40 40 | # Should emit for unions with more than two cases
41 |-field12: Literal[1] | Literal[2] | Literal[3] # Error
41 |+field12: Literal[1, 2, 3] # Error
42 42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error
43 43 |
44 44 | # Should emit for unions with more than two cases, even if not directly adjacent
PYI030.pyi:42:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
40 | # Should emit for unions with more than two cases
41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
@@ -141,7 +271,17 @@ PYI030.pyi:42:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:45:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
Safe fix
39 39 |
40 40 | # Should emit for unions with more than two cases
41 41 | field12: Literal[1] | Literal[2] | Literal[3] # Error
42 |-field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error
42 |+field13: Literal[1, 2, 3, 4] # Error
43 43 |
44 44 | # Should emit for unions with more than two cases, even if not directly adjacent
45 45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error
PYI030.pyi:45:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3]`
|
44 | # Should emit for unions with more than two cases, even if not directly adjacent
45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error
@@ -151,7 +291,17 @@ PYI030.pyi:45:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:48:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, "foo", True]`
Safe fix
42 42 | field13: Literal[1] | Literal[2] | Literal[3] | Literal[4] # Error
43 43 |
44 44 | # Should emit for unions with more than two cases, even if not directly adjacent
45 |-field14: Literal[1] | Literal[2] | str | Literal[3] # Error
45 |+field14: Literal[1, 2, 3] | str # Error
46 46 |
47 47 | # Should emit for unions with mixed literal internal types
48 48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error
PYI030.pyi:48:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, "foo", True]`
|
47 | # Should emit for unions with mixed literal internal types
48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error
@@ -161,7 +311,17 @@ PYI030.pyi:48:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:51:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 1]`
Safe fix
45 45 | field14: Literal[1] | Literal[2] | str | Literal[3] # Error
46 46 |
47 47 | # Should emit for unions with mixed literal internal types
48 |-field15: Literal[1] | Literal["foo"] | Literal[True] # Error
48 |+field15: Literal[1, "foo", True] # Error
49 49 |
50 50 | # Shouldn't emit for duplicate field types with same value; covered by Y016
51 51 | field16: Literal[1] | Literal[1] # OK
PYI030.pyi:51:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 1]`
|
50 | # Shouldn't emit for duplicate field types with same value; covered by Y016
51 | field16: Literal[1] | Literal[1] # OK
@@ -171,7 +331,17 @@ PYI030.pyi:51:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:60:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
48 48 | field15: Literal[1] | Literal["foo"] | Literal[True] # Error
49 49 |
50 50 | # Shouldn't emit for duplicate field types with same value; covered by Y016
51 |-field16: Literal[1] | Literal[1] # OK
51 |+field16: Literal[1, 1] # OK
52 52 |
53 53 | # Shouldn't emit if in new parent type
54 54 | field17: Literal[1] | dict[Literal[2], str] # OK
PYI030.pyi:60:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
59 | # Should respect name of literal type used
60 | field19: typing.Literal[1] | typing.Literal[2] # Error
@@ -181,7 +351,17 @@ PYI030.pyi:60:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:63:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
57 57 | field18: dict[Literal[1], Literal[2]] # OK
58 58 |
59 59 | # Should respect name of literal type used
60 |-field19: typing.Literal[1] | typing.Literal[2] # Error
60 |+field19: typing.Literal[1, 2] # Error
61 61 |
62 62 | # Should emit in cases with newlines
63 63 | field20: typing.Union[
PYI030.pyi:63:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
62 | # Should emit in cases with newlines
63 | field20: typing.Union[
@@ -197,7 +377,22 @@ PYI030.pyi:63:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:71:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
60 60 | field19: typing.Literal[1] | typing.Literal[2] # Error
61 61 |
62 62 | # Should emit in cases with newlines
63 |-field20: typing.Union[
64 |- Literal[
65 |- 1 # test
66 |- ],
67 |- Literal[2],
68 |-] # Error, newline and comment will not be emitted in message
63 |+field20: Literal[1, 2] # Error, newline and comment will not be emitted in message
69 64 |
70 65 | # Should handle multiple unions with multiple members
71 66 | field21: Literal[1, 2] | Literal[3, 4] # Error
PYI030.pyi:71:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
70 | # Should handle multiple unions with multiple members
71 | field21: Literal[1, 2] | Literal[3, 4] # Error
@@ -207,7 +402,17 @@ PYI030.pyi:71:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:74:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
68 68 | ] # Error, newline and comment will not be emitted in message
69 69 |
70 70 | # Should handle multiple unions with multiple members
71 |-field21: Literal[1, 2] | Literal[3, 4] # Error
71 |+field21: Literal[1, 2, 3, 4] # Error
72 72 |
73 73 | # Should emit in cases with `typing.Union` instead of `|`
74 74 | field22: typing.Union[Literal[1], Literal[2]] # Error
PYI030.pyi:74:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
73 | # Should emit in cases with `typing.Union` instead of `|`
74 | field22: typing.Union[Literal[1], Literal[2]] # Error
@@ -217,7 +422,17 @@ PYI030.pyi:74:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:77:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
71 71 | field21: Literal[1, 2] | Literal[3, 4] # Error
72 72 |
73 73 | # Should emit in cases with `typing.Union` instead of `|`
74 |-field22: typing.Union[Literal[1], Literal[2]] # Error
74 |+field22: Literal[1, 2] # Error
75 75 |
76 76 | # Should emit in cases with `typing_extensions.Literal`
77 77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
PYI030.pyi:77:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
76 | # Should emit in cases with `typing_extensions.Literal`
77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
@@ -227,7 +442,17 @@ PYI030.pyi:77:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:80:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
74 74 | field22: typing.Union[Literal[1], Literal[2]] # Error
75 75 |
76 76 | # Should emit in cases with `typing_extensions.Literal`
77 |-field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
77 |+field23: typing_extensions.Literal[1, 2] # Error
78 78 |
79 79 | # Should emit in cases with nested `typing.Union`
80 80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
PYI030.pyi:80:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
79 | # Should emit in cases with nested `typing.Union`
80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
@@ -237,7 +462,17 @@ PYI030.pyi:80:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:83:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
Safe fix
77 77 | field23: typing_extensions.Literal[1] | typing_extensions.Literal[2] # Error
78 78 |
79 79 | # Should emit in cases with nested `typing.Union`
80 |-field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
80 |+field24: typing.Union[Literal[1, 2], str] # Error
81 81 |
82 82 | # Should emit in cases with mixed `typing.Union` and `|`
83 83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error
PYI030.pyi:83:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2]`
|
82 | # Should emit in cases with mixed `typing.Union` and `|`
83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error
@@ -247,7 +482,17 @@ PYI030.pyi:83:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:86:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
80 80 | field24: typing.Union[Literal[1], typing.Union[Literal[2], str]] # Error
81 81 |
82 82 | # Should emit in cases with mixed `typing.Union` and `|`
83 |-field25: typing.Union[Literal[1], Literal[2] | str] # Error
83 |+field25: typing.Union[Literal[1, 2], str] # Error
84 84 |
85 85 | # Should emit only once in cases with multiple nested `typing.Union`
86 86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
PYI030.pyi:86:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
85 | # Should emit only once in cases with multiple nested `typing.Union`
86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
@@ -257,7 +502,17 @@ PYI030.pyi:86:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
PYI030.pyi:89:10: PYI030 Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
Safe fix
83 83 | field25: typing.Union[Literal[1], Literal[2] | str] # Error
84 84 |
85 85 | # Should emit only once in cases with multiple nested `typing.Union`
86 |-field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
86 |+field24: Literal[1, 2, 3, 4] # Error
87 87 |
88 88 | # Should use the first literal subscript attribute when fixing
89 89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
PYI030.pyi:89:10: PYI030 [*] Multiple literal members in a union. Use a single literal, e.g. `Literal[1, 2, 3, 4]`
|
88 | # Should use the first literal subscript attribute when fixing
89 | field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
@@ -265,4 +520,11 @@ PYI030.pyi:89:10: PYI030 Multiple literal members in a union. Use a single liter
|
= help: Replace with a single `Literal`
Safe fix
86 86 | field24: typing.Union[Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]]] # Error
87 87 |
88 88 | # Should use the first literal subscript attribute when fixing
89 |-field25: typing.Union[typing_extensions.Literal[1], typing.Union[Literal[2], typing.Union[Literal[3], Literal[4]]], str] # Error
89 |+field25: typing.Union[typing_extensions.Literal[1, 2, 3, 4], str] # Error

View File

@@ -24,7 +24,7 @@ use super::helpers::{
/// ## What it does
/// Checks for argument-free `@pytest.fixture()` decorators with or without
/// parentheses, depending on the `flake8-pytest-style.fixture-parentheses`
/// parentheses, depending on the [`lint.flake8-pytest-style.fixture-parentheses`]
/// setting.
///
/// ## Why is this bad?
@@ -55,7 +55,7 @@ use super::helpers::{
/// ```
///
/// ## Options
/// - `flake8-pytest-style.fixture-parentheses`
/// - `lint.flake8-pytest-style.fixture-parentheses`
///
/// ## References
/// - [`pytest` documentation: API Reference: Fixtures](https://docs.pytest.org/en/latest/reference/reference.html#fixtures-api)

View File

@@ -11,7 +11,7 @@ use super::helpers::get_mark_decorators;
/// ## What it does
/// Checks for argument-free `@pytest.mark.<marker>()` decorators with or
/// without parentheses, depending on the `flake8-pytest-style.mark-parentheses`
/// without parentheses, depending on the [`lint.flake8-pytest-style.mark-parentheses`]
/// setting.
///
/// ## Why is this bad?
@@ -42,7 +42,7 @@ use super::helpers::get_mark_decorators;
/// ```
///
/// ## Options
/// - `flake8-pytest-style.mark-parentheses`
/// - `lint.flake8-pytest-style.mark-parentheses`
///
/// ## References
/// - [`pytest` documentation: Marks](https://docs.pytest.org/en/latest/reference/reference.html#marks)

View File

@@ -26,7 +26,7 @@ use super::helpers::{is_pytest_parametrize, split_names};
/// The `argnames` argument of `pytest.mark.parametrize` takes a string or
/// a sequence of strings. For a single parameter, it's preferable to use a
/// string. For multiple parameters, it's preferable to use the style
/// configured via the [`flake8-pytest-style.parametrize-names-type`] setting.
/// configured via the [`lint.flake8-pytest-style.parametrize-names-type`] setting.
///
/// ## Example
/// ```python
@@ -67,7 +67,7 @@ use super::helpers::{is_pytest_parametrize, split_names};
/// ```
///
/// ## Options
/// - `flake8-pytest-style.parametrize-names-type`
/// - `lint.flake8-pytest-style.parametrize-names-type`
///
/// ## References
/// - [`pytest` documentation: How to parametrize fixtures and test functions](https://docs.pytest.org/en/latest/how-to/parametrize.html#pytest-mark-parametrize)
@@ -103,17 +103,17 @@ impl Violation for PytestParametrizeNamesWrongType {
/// of values.
///
/// The style for the list of values rows can be configured via the
/// the [`flake8-pytest-style.parametrize-values-type`] setting, while the
/// the [`lint.flake8-pytest-style.parametrize-values-type`] setting, while the
/// style for each row of values can be configured via the
/// the [`flake8-pytest-style.parametrize-values-row-type`] setting.
/// the [`lint.flake8-pytest-style.parametrize-values-row-type`] setting.
///
/// For example, [`flake8-pytest-style.parametrize-values-type`] will lead to
/// For example, [`lint.flake8-pytest-style.parametrize-values-type`] will lead to
/// the following expectations:
///
/// - `tuple`: `@pytest.mark.parametrize("value", ("a", "b", "c"))`
/// - `list`: `@pytest.mark.parametrize("value", ["a", "b", "c"])`
///
/// Similarly, [`flake8-pytest-style.parametrize-values-row-type`] will lead to
/// Similarly, [`lint.flake8-pytest-style.parametrize-values-row-type`] will lead to
/// the following expectations:
///
/// - `tuple`: `@pytest.mark.parametrize(("key", "value"), [("a", "b"), ("c", "d")])`
@@ -170,8 +170,8 @@ impl Violation for PytestParametrizeNamesWrongType {
/// ```
///
/// ## Options
/// - `flake8-pytest-style.parametrize-values-type`
/// - `flake8-pytest-style.parametrize-values-row-type`
/// - `lint.flake8-pytest-style.parametrize-values-type`
/// - `lint.flake8-pytest-style.parametrize-values-row-type`
///
/// ## References
/// - [`pytest` documentation: How to parametrize fixtures and test functions](https://docs.pytest.org/en/latest/how-to/parametrize.html#pytest-mark-parametrize)

View File

@@ -64,8 +64,8 @@ impl Violation for PytestRaisesWithMultipleStatements {
/// unrelated to the code under test. To avoid this, `pytest.raises` should be
/// called with a `match` parameter. The exception names that require a `match`
/// parameter can be configured via the
/// `flake8-pytest-style.raises-require-match-for` and
/// `flake8-pytest-style.raises-extend-require-match-for` settings.
/// [`lint.flake8-pytest-style.raises-require-match-for`] and
/// [`lint.flake8-pytest-style.raises-extend-require-match-for`] settings.
///
/// ## Example
/// ```python
@@ -92,8 +92,8 @@ impl Violation for PytestRaisesWithMultipleStatements {
/// ```
///
/// ## Options
/// - `flake8-pytest-style.raises-require-match-for`
/// - `flake8-pytest-style.raises-extend-require-match-for`
/// - `lint.flake8-pytest-style.raises-require-match-for`
/// - `lint.flake8-pytest-style.raises-extend-require-match-for`
///
/// ## References
/// - [`pytest` documentation: `pytest.raises`](https://docs.pytest.org/en/latest/reference/reference.html#pytest-raises)

View File

@@ -14,7 +14,7 @@ use super::super::settings::Quote;
/// ## What it does
/// Checks for inline strings that use single quotes or double quotes,
/// depending on the value of the [`flake8-quotes.inline-quotes`] option.
/// depending on the value of the [`lint.flake8-quotes.inline-quotes`] option.
///
/// ## Why is this bad?
/// Consistency is good. Use either single or double quotes for inline
@@ -31,7 +31,7 @@ use super::super::settings::Quote;
/// ```
///
/// ## Options
/// - `flake8-quotes.inline-quotes`
/// - `lint.flake8-quotes.inline-quotes`
///
/// ## Formatter compatibility
/// We recommend against using this rule alongside the [formatter]. The
@@ -65,7 +65,7 @@ impl AlwaysFixableViolation for BadQuotesInlineString {
/// ## What it does
/// Checks for multiline strings that use single quotes or double quotes,
/// depending on the value of the [`flake8-quotes.multiline-quotes`]
/// depending on the value of the [`lint.flake8-quotes.multiline-quotes`]
/// setting.
///
/// ## Why is this bad?
@@ -87,7 +87,7 @@ impl AlwaysFixableViolation for BadQuotesInlineString {
/// ```
///
/// ## Options
/// - `flake8-quotes.multiline-quotes`
/// - `lint.flake8-quotes.multiline-quotes`
///
/// ## Formatter compatibility
/// We recommend against using this rule alongside the [formatter]. The
@@ -121,7 +121,7 @@ impl AlwaysFixableViolation for BadQuotesMultilineString {
/// ## What it does
/// Checks for docstrings that use single quotes or double quotes, depending
/// on the value of the [`flake8-quotes.docstring-quotes`] setting.
/// on the value of the [`lint.flake8-quotes.docstring-quotes`] setting.
///
/// ## Why is this bad?
/// Consistency is good. Use either single or double quotes for docstring
@@ -142,7 +142,7 @@ impl AlwaysFixableViolation for BadQuotesMultilineString {
/// ```
///
/// ## Options
/// - `flake8-quotes.docstring-quotes`
/// - `lint.flake8-quotes.docstring-quotes`
///
/// ## Formatter compatibility
/// We recommend against using this rule alongside the [formatter]. The

View File

@@ -43,7 +43,7 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `flake8-self.ignore-names`
/// - `lint.flake8-self.ignore-names`
///
/// ## References
/// - [_What is the meaning of single or double underscores before an object name?_](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-single-and-double-underscore-before-an-object-name)

View File

@@ -56,11 +56,7 @@ mod tests {
Ok(())
}
#[test_case(Rule::InDictKeys, Path::new("SIM118.py"))]
#[test_case(Rule::YodaConditions, Path::new("SIM300.py"))]
#[test_case(Rule::IfElseBlockInsteadOfDictGet, Path::new("SIM401.py"))]
#[test_case(Rule::DictGetWithNoneDefault, Path::new("SIM910.py"))]
#[test_case(Rule::IfWithSameArms, Path::new("SIM114.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(
"preview__{}_{}",

View File

@@ -266,10 +266,6 @@ pub(crate) fn dict_get_with_none_default(checker: &mut Checker, expr: &Expr) {
match value.as_ref() {
Expr::Dict(_) | Expr::DictComp(_) => {}
Expr::Name(name) => {
if checker.settings.preview.is_disabled() {
return;
}
let Some(binding) = checker
.semantic()
.only_binding(name)

View File

@@ -224,10 +224,6 @@ pub(crate) fn if_exp_instead_of_dict_get(
body: &Expr,
orelse: &Expr,
) {
if checker.settings.preview.is_disabled() {
return;
}
let Expr::Compare(ast::ExprCompare {
left: test_key,
ops,

View File

@@ -94,17 +94,15 @@ pub(crate) fn if_with_same_arms(checker: &mut Checker, stmt_if: &ast::StmtIf) {
TextRange::new(current_branch.start(), following_branch.end()),
);
if checker.settings.preview.is_enabled() {
diagnostic.try_set_fix(|| {
merge_branches(
stmt_if,
&current_branch,
following_branch,
checker.locator(),
checker.indexer(),
)
});
}
diagnostic.try_set_fix(|| {
merge_branches(
stmt_if,
&current_branch,
following_branch,
checker.locator(),
checker.indexer(),
)
});
checker.diagnostics.push(diagnostic);
}

View File

@@ -127,7 +127,7 @@ fn key_in_dict(
{
// The fix is only safe if we know the expression is a dictionary, since other types
// can define a `.keys()` method.
let applicability = if checker.settings.preview.is_enabled() {
let applicability = {
let is_dict = value.as_name_expr().is_some_and(|name| {
let Some(binding) = checker
.semantic()
@@ -143,8 +143,6 @@ fn key_in_dict(
} else {
Applicability::Unsafe
}
} else {
Applicability::Unsafe
};
// If the `.keys()` is followed by (e.g.) a keyword, we need to insert a space,

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM114.py:2:1: SIM114 Combine `if` branches using logical `or` operator
SIM114.py:2:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
1 | # Errors
2 | / if a:
@@ -14,7 +14,17 @@ SIM114.py:2:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:7:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
1 1 | # Errors
2 |-if a:
3 |- b
4 |-elif c:
2 |+if a or c:
5 3 | b
6 4 |
7 5 | if a: # we preserve comments, too!
SIM114.py:7:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
5 | b
6 |
@@ -28,7 +38,19 @@ SIM114.py:7:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:12:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
4 4 | elif c:
5 5 | b
6 6 |
7 |-if a: # we preserve comments, too!
8 |- b
9 |-elif c: # but not on the second branch
7 |+if a or c: # we preserve comments, too!
10 8 | b
11 9 |
12 10 | if x == 1:
SIM114.py:12:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
10 | b
11 |
@@ -44,7 +66,20 @@ SIM114.py:12:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:19:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
9 9 | elif c: # but not on the second branch
10 10 | b
11 11 |
12 |-if x == 1:
13 |- for _ in range(20):
14 |- print("hello")
15 |-elif x == 2:
12 |+if x == 1 or x == 2:
16 13 | for _ in range(20):
17 14 | print("hello")
18 15 |
SIM114.py:19:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
17 | print("hello")
18 |
@@ -62,7 +97,21 @@ SIM114.py:19:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:28:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
16 16 | for _ in range(20):
17 17 | print("hello")
18 18 |
19 |-if x == 1:
20 |- if True:
21 |- for _ in range(20):
22 |- print("hello")
23 |-elif x == 2:
19 |+if x == 1 or x == 2:
24 20 | if True:
25 21 | for _ in range(20):
26 22 | print("hello")
SIM114.py:28:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
26 | print("hello")
27 |
@@ -86,7 +135,24 @@ SIM114.py:28:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:29:5: SIM114 Combine `if` branches using logical `or` operator
Safe fix
25 25 | for _ in range(20):
26 26 | print("hello")
27 27 |
28 |-if x == 1:
29 |- if True:
30 |- for _ in range(20):
31 |- print("hello")
32 |- elif False:
33 |- for _ in range(20):
34 |- print("hello")
35 |-elif x == 2:
28 |+if x == 1 or x == 2:
36 29 | if True:
37 30 | for _ in range(20):
38 31 | print("hello")
SIM114.py:29:5: SIM114 [*] Combine `if` branches using logical `or` operator
|
28 | if x == 1:
29 | if True:
@@ -102,7 +168,20 @@ SIM114.py:29:5: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:36:5: SIM114 Combine `if` branches using logical `or` operator
Safe fix
26 26 | print("hello")
27 27 |
28 28 | if x == 1:
29 |- if True:
30 |- for _ in range(20):
31 |- print("hello")
32 |- elif False:
29 |+ if True or False:
33 30 | for _ in range(20):
34 31 | print("hello")
35 32 | elif x == 2:
SIM114.py:36:5: SIM114 [*] Combine `if` branches using logical `or` operator
|
34 | print("hello")
35 | elif x == 2:
@@ -119,7 +198,20 @@ SIM114.py:36:5: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:43:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
33 33 | for _ in range(20):
34 34 | print("hello")
35 35 | elif x == 2:
36 |- if True:
37 |- for _ in range(20):
38 |- print("hello")
39 |- elif False:
36 |+ if True or False:
40 37 | for _ in range(20):
41 38 | print("hello")
42 39 |
SIM114.py:43:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
41 | print("hello")
42 |
@@ -148,7 +240,19 @@ SIM114.py:43:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:67:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
55 55 | and i == 12
56 56 | and j == 13
57 57 | and k == 14
58 |-):
59 |- pass
60 |-elif 1 == 2:
58 |+) or 1 == 2:
61 59 | pass
62 60 |
63 61 | if result.eofs == "O":
SIM114.py:67:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
65 | elif result.eofs == "S":
66 | skipped = 1
@@ -162,7 +266,19 @@ SIM114.py:67:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:69:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
64 64 | pass
65 65 | elif result.eofs == "S":
66 66 | skipped = 1
67 |-elif result.eofs == "F":
68 |- errors = 1
69 |-elif result.eofs == "E":
67 |+elif result.eofs == "F" or result.eofs == "E":
70 68 | errors = 1
71 69 | elif result.eofs == "X":
72 70 | errors = 1
SIM114.py:69:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
67 | elif result.eofs == "F":
68 | errors = 1
@@ -176,7 +292,19 @@ SIM114.py:69:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:71:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
66 66 | skipped = 1
67 67 | elif result.eofs == "F":
68 68 | errors = 1
69 |-elif result.eofs == "E":
70 |- errors = 1
71 |-elif result.eofs == "X":
69 |+elif result.eofs == "E" or result.eofs == "X":
72 70 | errors = 1
73 71 | elif result.eofs == "C":
74 72 | errors = 1
SIM114.py:71:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
69 | elif result.eofs == "E":
70 | errors = 1
@@ -188,7 +316,19 @@ SIM114.py:71:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:118:5: SIM114 Combine `if` branches using logical `or` operator
Safe fix
68 68 | errors = 1
69 69 | elif result.eofs == "E":
70 70 | errors = 1
71 |-elif result.eofs == "X":
72 |- errors = 1
73 |-elif result.eofs == "C":
71 |+elif result.eofs == "X" or result.eofs == "C":
74 72 | errors = 1
75 73 |
76 74 |
SIM114.py:118:5: SIM114 [*] Combine `if` branches using logical `or` operator
|
116 | a = True
117 | b = False
@@ -203,7 +343,19 @@ SIM114.py:118:5: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:122:5: SIM114 Combine `if` branches using logical `or` operator
Safe fix
115 115 | def func():
116 116 | a = True
117 117 | b = False
118 |- if a > b: # end-of-line
119 |- return 3
120 |- elif a == b:
118 |+ if a > b or a == b: # end-of-line
121 119 | return 3
122 120 | elif a < b: # end-of-line
123 121 | return 4
SIM114.py:122:5: SIM114 [*] Combine `if` branches using logical `or` operator
|
120 | elif a == b:
121 | return 3
@@ -216,7 +368,19 @@ SIM114.py:122:5: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:132:5: SIM114 Combine `if` branches using logical `or` operator
Safe fix
119 119 | return 3
120 120 | elif a == b:
121 121 | return 3
122 |- elif a < b: # end-of-line
123 |- return 4
124 |- elif b is None:
122 |+ elif a < b or b is None: # end-of-line
125 123 | return 4
126 124 |
127 125 |
SIM114.py:132:5: SIM114 [*] Combine `if` branches using logical `or` operator
|
130 | a = True
131 | b = False
@@ -229,7 +393,19 @@ SIM114.py:132:5: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:138:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
129 129 | """Ensure that the named expression is parenthesized when merged."""
130 130 | a = True
131 131 | b = False
132 |- if a > b: # end-of-line
133 |- return 3
134 |- elif a := 1:
132 |+ if a > b or (a := 1): # end-of-line
135 133 | return 3
136 134 |
137 135 |
SIM114.py:138:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
138 | / if a: # we preserve comments, too!
139 | | b
@@ -239,7 +415,19 @@ SIM114.py:138:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:144:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
135 135 | return 3
136 136 |
137 137 |
138 |-if a: # we preserve comments, too!
139 |- b
140 |-elif c: # but not on the second branch
138 |+if a or c: # we preserve comments, too!
141 139 | b
142 140 |
143 141 |
SIM114.py:144:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
144 | / if a: b # here's a comment
145 | | elif c: b
@@ -247,7 +435,18 @@ SIM114.py:144:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
SIM114.py:148:1: SIM114 Combine `if` branches using logical `or` operator
Safe fix
141 141 | b
142 142 |
143 143 |
144 |-if a: b # here's a comment
145 |-elif c: b
144 |+if a or c: b # here's a comment
146 145 |
147 146 |
148 147 | if(x > 200): pass
SIM114.py:148:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
148 | / if(x > 200): pass
149 | | elif(100 < x and x < 200 and 300 < y and y < 800):
@@ -256,4 +455,13 @@ SIM114.py:148:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
Safe fix
145 145 | elif c: b
146 146 |
147 147 |
148 |-if(x > 200): pass
149 |-elif(100 < x and x < 200 and 300 < y and y < 800):
150 |- pass
148 |+if(x > 200) or (100 < x and x < 200 and 300 < y and y < 800): pass

View File

@@ -12,7 +12,7 @@ SIM118.py:3:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
1 1 | obj = {}
2 2 |
3 |-key in obj.keys() # SIM118
@@ -32,7 +32,7 @@ SIM118.py:5:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.keys
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
2 2 |
3 3 | key in obj.keys() # SIM118
4 4 |
@@ -53,7 +53,7 @@ SIM118.py:7:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
4 4 |
5 5 | key not in obj.keys() # SIM118
6 6 |
@@ -74,7 +74,7 @@ SIM118.py:9:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.keys
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
6 6 |
7 7 | foo["bar"] in obj.keys() # SIM118
8 8 |
@@ -95,7 +95,7 @@ SIM118.py:11:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
8 8 |
9 9 | foo["bar"] not in obj.keys() # SIM118
10 10 |
@@ -116,7 +116,7 @@ SIM118.py:13:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.key
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
10 10 |
11 11 | foo['bar'] in obj.keys() # SIM118
12 12 |
@@ -137,7 +137,7 @@ SIM118.py:15:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
12 12 |
13 13 | foo['bar'] not in obj.keys() # SIM118
14 14 |
@@ -158,7 +158,7 @@ SIM118.py:17:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.key
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
14 14 |
15 15 | foo() in obj.keys() # SIM118
16 16 |
@@ -178,7 +178,7 @@ SIM118.py:19:5: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
16 16 |
17 17 | foo() not in obj.keys() # SIM118
18 18 |
@@ -199,7 +199,7 @@ SIM118.py:26:8: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
23 23 | if some_property(key):
24 24 | del obj[key]
25 25 |
@@ -220,7 +220,7 @@ SIM118.py:28:8: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
25 25 |
26 26 | [k for k in obj.keys()] # SIM118
27 27 |
@@ -241,7 +241,7 @@ SIM118.py:30:11: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
27 27 |
28 28 | {k for k in obj.keys()} # SIM118
29 29 |
@@ -262,7 +262,7 @@ SIM118.py:32:8: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
29 29 |
30 30 | {k: k for k in obj.keys()} # SIM118
31 31 |
@@ -324,7 +324,7 @@ SIM118.py:50:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
47 47 |
48 48 |
49 49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
@@ -344,7 +344,7 @@ SIM118.py:51:2: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
48 48 |
49 49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 50 | key in obj.keys()and foo
@@ -365,7 +365,7 @@ SIM118.py:52:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
= help: Remove `.keys()`
Unsafe fix
Safe fix
49 49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 50 | key in obj.keys()and foo
51 51 | (key in obj.keys())and foo

View File

@@ -159,4 +159,44 @@ SIM401.py:45:5: SIM401 [*] Use `vars[idx] = a_dict.get(key, "default")` instead
50 47 | ###
51 48 | # Negative cases
SIM401.py:123:7: SIM401 [*] Use `a_dict.get(key, "default3")` instead of an `if` block
|
122 | # SIM401
123 | var = a_dict[key] if key in a_dict else "default3"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM401
124 |
125 | # SIM401
|
= help: Replace with `a_dict.get(key, "default3")`
Unsafe fix
120 120 | ###
121 121 |
122 122 | # SIM401
123 |-var = a_dict[key] if key in a_dict else "default3"
123 |+var = a_dict.get(key, "default3")
124 124 |
125 125 | # SIM401
126 126 | var = "default-1" if key not in a_dict else a_dict[key]
SIM401.py:126:7: SIM401 [*] Use `a_dict.get(key, "default-1")` instead of an `if` block
|
125 | # SIM401
126 | var = "default-1" if key not in a_dict else a_dict[key]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM401
127 |
128 | # OK (default contains effect)
|
= help: Replace with `a_dict.get(key, "default-1")`
Unsafe fix
123 123 | var = a_dict[key] if key in a_dict else "default3"
124 124 |
125 125 | # SIM401
126 |-var = "default-1" if key not in a_dict else a_dict[key]
126 |+var = a_dict.get(key, "default-1")
127 127 |
128 128 | # OK (default contains effect)
129 129 | var = a_dict[key] if key in a_dict else val1 + val2

View File

@@ -98,4 +98,25 @@ SIM910.py:27:1: SIM910 [*] Use `({}).get(key)` instead of `({}).get(key, None)`
29 29 | # SIM910
30 30 | ages = {"Tom": 23, "Maria": 23, "Dog": 11}
SIM910.py:31:7: SIM910 [*] Use `ages.get("Cat")` instead of `ages.get("Cat", None)`
|
29 | # SIM910
30 | ages = {"Tom": 23, "Maria": 23, "Dog": 11}
31 | age = ages.get("Cat", None)
| ^^^^^^^^^^^^^^^^^^^^^ SIM910
32 |
33 | # OK
|
= help: Replace `ages.get("Cat", None)` with `ages.get("Cat")`
Safe fix
28 28 |
29 29 | # SIM910
30 30 | ages = {"Tom": 23, "Maria": 23, "Dog": 11}
31 |-age = ages.get("Cat", None)
31 |+age = ages.get("Cat")
32 32 |
33 33 | # OK
34 34 | ages = ["Tom", "Maria", "Dog"]

View File

@@ -1,401 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM118.py:3:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
1 | obj = {}
2 |
3 | key in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^ SIM118
4 |
5 | key not in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
1 1 | obj = {}
2 2 |
3 |-key in obj.keys() # SIM118
3 |+key in obj # SIM118
4 4 |
5 5 | key not in obj.keys() # SIM118
6 6 |
SIM118.py:5:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.keys()`
|
3 | key in obj.keys() # SIM118
4 |
5 | key not in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^ SIM118
6 |
7 | foo["bar"] in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
2 2 |
3 3 | key in obj.keys() # SIM118
4 4 |
5 |-key not in obj.keys() # SIM118
5 |+key not in obj # SIM118
6 6 |
7 7 | foo["bar"] in obj.keys() # SIM118
8 8 |
SIM118.py:7:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
5 | key not in obj.keys() # SIM118
6 |
7 | foo["bar"] in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^^ SIM118
8 |
9 | foo["bar"] not in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
4 4 |
5 5 | key not in obj.keys() # SIM118
6 6 |
7 |-foo["bar"] in obj.keys() # SIM118
7 |+foo["bar"] in obj # SIM118
8 8 |
9 9 | foo["bar"] not in obj.keys() # SIM118
10 10 |
SIM118.py:9:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.keys()`
|
7 | foo["bar"] in obj.keys() # SIM118
8 |
9 | foo["bar"] not in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM118
10 |
11 | foo['bar'] in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
6 6 |
7 7 | foo["bar"] in obj.keys() # SIM118
8 8 |
9 |-foo["bar"] not in obj.keys() # SIM118
9 |+foo["bar"] not in obj # SIM118
10 10 |
11 11 | foo['bar'] in obj.keys() # SIM118
12 12 |
SIM118.py:11:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
9 | foo["bar"] not in obj.keys() # SIM118
10 |
11 | foo['bar'] in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^^ SIM118
12 |
13 | foo['bar'] not in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
8 8 |
9 9 | foo["bar"] not in obj.keys() # SIM118
10 10 |
11 |-foo['bar'] in obj.keys() # SIM118
11 |+foo['bar'] in obj # SIM118
12 12 |
13 13 | foo['bar'] not in obj.keys() # SIM118
14 14 |
SIM118.py:13:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.keys()`
|
11 | foo['bar'] in obj.keys() # SIM118
12 |
13 | foo['bar'] not in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM118
14 |
15 | foo() in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
10 10 |
11 11 | foo['bar'] in obj.keys() # SIM118
12 12 |
13 |-foo['bar'] not in obj.keys() # SIM118
13 |+foo['bar'] not in obj # SIM118
14 14 |
15 15 | foo() in obj.keys() # SIM118
16 16 |
SIM118.py:15:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
13 | foo['bar'] not in obj.keys() # SIM118
14 |
15 | foo() in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^ SIM118
16 |
17 | foo() not in obj.keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
12 12 |
13 13 | foo['bar'] not in obj.keys() # SIM118
14 14 |
15 |-foo() in obj.keys() # SIM118
15 |+foo() in obj # SIM118
16 16 |
17 17 | foo() not in obj.keys() # SIM118
18 18 |
SIM118.py:17:1: SIM118 [*] Use `key not in dict` instead of `key not in dict.keys()`
|
15 | foo() in obj.keys() # SIM118
16 |
17 | foo() not in obj.keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^ SIM118
18 |
19 | for key in obj.keys(): # SIM118
|
= help: Remove `.keys()`
Safe fix
14 14 |
15 15 | foo() in obj.keys() # SIM118
16 16 |
17 |-foo() not in obj.keys() # SIM118
17 |+foo() not in obj # SIM118
18 18 |
19 19 | for key in obj.keys(): # SIM118
20 20 | pass
SIM118.py:19:5: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
17 | foo() not in obj.keys() # SIM118
18 |
19 | for key in obj.keys(): # SIM118
| ^^^^^^^^^^^^^^^^^ SIM118
20 | pass
|
= help: Remove `.keys()`
Safe fix
16 16 |
17 17 | foo() not in obj.keys() # SIM118
18 18 |
19 |-for key in obj.keys(): # SIM118
19 |+for key in obj: # SIM118
20 20 | pass
21 21 |
22 22 | for key in list(obj.keys()):
SIM118.py:26:8: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
24 | del obj[key]
25 |
26 | [k for k in obj.keys()] # SIM118
| ^^^^^^^^^^^^^^^ SIM118
27 |
28 | {k for k in obj.keys()} # SIM118
|
= help: Remove `.keys()`
Safe fix
23 23 | if some_property(key):
24 24 | del obj[key]
25 25 |
26 |-[k for k in obj.keys()] # SIM118
26 |+[k for k in obj] # SIM118
27 27 |
28 28 | {k for k in obj.keys()} # SIM118
29 29 |
SIM118.py:28:8: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
26 | [k for k in obj.keys()] # SIM118
27 |
28 | {k for k in obj.keys()} # SIM118
| ^^^^^^^^^^^^^^^ SIM118
29 |
30 | {k: k for k in obj.keys()} # SIM118
|
= help: Remove `.keys()`
Safe fix
25 25 |
26 26 | [k for k in obj.keys()] # SIM118
27 27 |
28 |-{k for k in obj.keys()} # SIM118
28 |+{k for k in obj} # SIM118
29 29 |
30 30 | {k: k for k in obj.keys()} # SIM118
31 31 |
SIM118.py:30:11: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
28 | {k for k in obj.keys()} # SIM118
29 |
30 | {k: k for k in obj.keys()} # SIM118
| ^^^^^^^^^^^^^^^ SIM118
31 |
32 | (k for k in obj.keys()) # SIM118
|
= help: Remove `.keys()`
Safe fix
27 27 |
28 28 | {k for k in obj.keys()} # SIM118
29 29 |
30 |-{k: k for k in obj.keys()} # SIM118
30 |+{k: k for k in obj} # SIM118
31 31 |
32 32 | (k for k in obj.keys()) # SIM118
33 33 |
SIM118.py:32:8: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
30 | {k: k for k in obj.keys()} # SIM118
31 |
32 | (k for k in obj.keys()) # SIM118
| ^^^^^^^^^^^^^^^ SIM118
33 |
34 | key in (obj or {}).keys() # SIM118
|
= help: Remove `.keys()`
Safe fix
29 29 |
30 30 | {k: k for k in obj.keys()} # SIM118
31 31 |
32 |-(k for k in obj.keys()) # SIM118
32 |+(k for k in obj) # SIM118
33 33 |
34 34 | key in (obj or {}).keys() # SIM118
35 35 |
SIM118.py:34:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
32 | (k for k in obj.keys()) # SIM118
33 |
34 | key in (obj or {}).keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^^^ SIM118
35 |
36 | (key) in (obj or {}).keys() # SIM118
|
= help: Remove `.keys()`
Unsafe fix
31 31 |
32 32 | (k for k in obj.keys()) # SIM118
33 33 |
34 |-key in (obj or {}).keys() # SIM118
34 |+key in (obj or {}) # SIM118
35 35 |
36 36 | (key) in (obj or {}).keys() # SIM118
37 37 |
SIM118.py:36:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
34 | key in (obj or {}).keys() # SIM118
35 |
36 | (key) in (obj or {}).keys() # SIM118
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM118
37 |
38 | from typing import KeysView
|
= help: Remove `.keys()`
Unsafe fix
33 33 |
34 34 | key in (obj or {}).keys() # SIM118
35 35 |
36 |-(key) in (obj or {}).keys() # SIM118
36 |+(key) in (obj or {}) # SIM118
37 37 |
38 38 | from typing import KeysView
39 39 |
SIM118.py:50:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 | key in obj.keys()and foo
| ^^^^^^^^^^^^^^^^^ SIM118
51 | (key in obj.keys())and foo
52 | key in (obj.keys())and foo
|
= help: Remove `.keys()`
Safe fix
47 47 |
48 48 |
49 49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 |-key in obj.keys()and foo
50 |+key in obj and foo
51 51 | (key in obj.keys())and foo
52 52 | key in (obj.keys())and foo
53 53 |
SIM118.py:51:2: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 | key in obj.keys()and foo
51 | (key in obj.keys())and foo
| ^^^^^^^^^^^^^^^^^ SIM118
52 | key in (obj.keys())and foo
|
= help: Remove `.keys()`
Safe fix
48 48 |
49 49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 50 | key in obj.keys()and foo
51 |-(key in obj.keys())and foo
51 |+(key in obj)and foo
52 52 | key in (obj.keys())and foo
53 53 |
54 54 | # Regression test for: https://github.com/astral-sh/ruff/issues/7200
SIM118.py:52:1: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
50 | key in obj.keys()and foo
51 | (key in obj.keys())and foo
52 | key in (obj.keys())and foo
| ^^^^^^^^^^^^^^^^^^^ SIM118
53 |
54 | # Regression test for: https://github.com/astral-sh/ruff/issues/7200
|
= help: Remove `.keys()`
Safe fix
49 49 | # Regression test for: https://github.com/astral-sh/ruff/issues/7124
50 50 | key in obj.keys()and foo
51 51 | (key in obj.keys())and foo
52 |-key in (obj.keys())and foo
52 |+key in (obj)and foo
53 53 |
54 54 | # Regression test for: https://github.com/astral-sh/ruff/issues/7200
55 55 | for key in (
SIM118.py:55:5: SIM118 [*] Use `key in dict` instead of `key in dict.keys()`
|
54 | # Regression test for: https://github.com/astral-sh/ruff/issues/7200
55 | for key in (
| _____^
56 | | self.experiment.surveys[0]
57 | | .stations[0]
58 | | .keys()
59 | | ):
| |_^ SIM118
60 | continue
|
= help: Remove `.keys()`
Unsafe fix
55 55 | for key in (
56 56 | self.experiment.surveys[0]
57 57 | .stations[0]
58 |- .keys()
58 |+
59 59 | ):
60 60 | continue

View File

@@ -1,202 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM401.py:6:1: SIM401 [*] Use `var = a_dict.get(key, "default1")` instead of an `if` block
|
5 | # SIM401 (pattern-1)
6 | / if key in a_dict:
7 | | var = a_dict[key]
8 | | else:
9 | | var = "default1"
| |____________________^ SIM401
10 |
11 | # SIM401 (pattern-2)
|
= help: Replace with `var = a_dict.get(key, "default1")`
Unsafe fix
3 3 | ###
4 4 |
5 5 | # SIM401 (pattern-1)
6 |-if key in a_dict:
7 |- var = a_dict[key]
8 |-else:
9 |- var = "default1"
6 |+var = a_dict.get(key, "default1")
10 7 |
11 8 | # SIM401 (pattern-2)
12 9 | if key not in a_dict:
SIM401.py:12:1: SIM401 [*] Use `var = a_dict.get(key, "default2")` instead of an `if` block
|
11 | # SIM401 (pattern-2)
12 | / if key not in a_dict:
13 | | var = "default2"
14 | | else:
15 | | var = a_dict[key]
| |_____________________^ SIM401
16 |
17 | # OK (default contains effect)
|
= help: Replace with `var = a_dict.get(key, "default2")`
Unsafe fix
9 9 | var = "default1"
10 10 |
11 11 | # SIM401 (pattern-2)
12 |-if key not in a_dict:
13 |- var = "default2"
14 |-else:
15 |- var = a_dict[key]
12 |+var = a_dict.get(key, "default2")
16 13 |
17 14 | # OK (default contains effect)
18 15 | if key in a_dict:
SIM401.py:24:1: SIM401 [*] Use `var = a_dict.get(keys[idx], "default")` instead of an `if` block
|
23 | # SIM401 (complex expression in key)
24 | / if keys[idx] in a_dict:
25 | | var = a_dict[keys[idx]]
26 | | else:
27 | | var = "default"
| |___________________^ SIM401
28 |
29 | # SIM401 (complex expression in dict)
|
= help: Replace with `var = a_dict.get(keys[idx], "default")`
Unsafe fix
21 21 | var = val1 + val2
22 22 |
23 23 | # SIM401 (complex expression in key)
24 |-if keys[idx] in a_dict:
25 |- var = a_dict[keys[idx]]
26 |-else:
27 |- var = "default"
24 |+var = a_dict.get(keys[idx], "default")
28 25 |
29 26 | # SIM401 (complex expression in dict)
30 27 | if key in dicts[idx]:
SIM401.py:30:1: SIM401 [*] Use `var = dicts[idx].get(key, "default")` instead of an `if` block
|
29 | # SIM401 (complex expression in dict)
30 | / if key in dicts[idx]:
31 | | var = dicts[idx][key]
32 | | else:
33 | | var = "default"
| |___________________^ SIM401
34 |
35 | # SIM401 (complex expression in var)
|
= help: Replace with `var = dicts[idx].get(key, "default")`
Unsafe fix
27 27 | var = "default"
28 28 |
29 29 | # SIM401 (complex expression in dict)
30 |-if key in dicts[idx]:
31 |- var = dicts[idx][key]
32 |-else:
33 |- var = "default"
30 |+var = dicts[idx].get(key, "default")
34 31 |
35 32 | # SIM401 (complex expression in var)
36 33 | if key in a_dict:
SIM401.py:36:1: SIM401 [*] Use `vars[idx] = a_dict.get(key, "defaultß9💣26789ß9💣26789ß9💣26789ß9💣26789ß9💣26789")` instead of an `if` block
|
35 | # SIM401 (complex expression in var)
36 | / if key in a_dict:
37 | | vars[idx] = a_dict[key]
38 | | else:
39 | | vars[idx] = "defaultß9💣26789ß9💣26789ß9💣26789ß9💣26789ß9💣26789"
| |___________________________________________________________________________^ SIM401
40 |
41 | # SIM401
|
= help: Replace with `vars[idx] = a_dict.get(key, "defaultß9💣26789ß9💣26789ß9💣26789ß9💣26789ß9💣26789")`
Unsafe fix
33 33 | var = "default"
34 34 |
35 35 | # SIM401 (complex expression in var)
36 |-if key in a_dict:
37 |- vars[idx] = a_dict[key]
38 |-else:
39 |- vars[idx] = "defaultß9💣26789ß9💣26789ß9💣26789ß9💣26789ß9💣26789"
36 |+vars[idx] = a_dict.get(key, "defaultß9💣26789ß9💣26789ß9💣26789ß9💣26789ß9💣26789")
40 37 |
41 38 | # SIM401
42 39 | if foo():
SIM401.py:45:5: SIM401 [*] Use `vars[idx] = a_dict.get(key, "default")` instead of an `if` block
|
43 | pass
44 | else:
45 | if key in a_dict:
| _____^
46 | | vars[idx] = a_dict[key]
47 | | else:
48 | | vars[idx] = "default"
| |_____________________________^ SIM401
49 |
50 | ###
|
= help: Replace with `vars[idx] = a_dict.get(key, "default")`
Unsafe fix
42 42 | if foo():
43 43 | pass
44 44 | else:
45 |- if key in a_dict:
46 |- vars[idx] = a_dict[key]
47 |- else:
48 |- vars[idx] = "default"
45 |+ vars[idx] = a_dict.get(key, "default")
49 46 |
50 47 | ###
51 48 | # Negative cases
SIM401.py:123:7: SIM401 [*] Use `a_dict.get(key, "default3")` instead of an `if` block
|
122 | # SIM401
123 | var = a_dict[key] if key in a_dict else "default3"
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM401
124 |
125 | # SIM401
|
= help: Replace with `a_dict.get(key, "default3")`
Unsafe fix
120 120 | ###
121 121 |
122 122 | # SIM401
123 |-var = a_dict[key] if key in a_dict else "default3"
123 |+var = a_dict.get(key, "default3")
124 124 |
125 125 | # SIM401
126 126 | var = "default-1" if key not in a_dict else a_dict[key]
SIM401.py:126:7: SIM401 [*] Use `a_dict.get(key, "default-1")` instead of an `if` block
|
125 | # SIM401
126 | var = "default-1" if key not in a_dict else a_dict[key]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ SIM401
127 |
128 | # OK (default contains effect)
|
= help: Replace with `a_dict.get(key, "default-1")`
Unsafe fix
123 123 | var = a_dict[key] if key in a_dict else "default3"
124 124 |
125 125 | # SIM401
126 |-var = "default-1" if key not in a_dict else a_dict[key]
126 |+var = a_dict.get(key, "default-1")
127 127 |
128 128 | # OK (default contains effect)
129 129 | var = a_dict[key] if key in a_dict else val1 + val2

View File

@@ -1,122 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM910.py:2:1: SIM910 [*] Use `{}.get(key)` instead of `{}.get(key, None)`
|
1 | # SIM910
2 | {}.get(key, None)
| ^^^^^^^^^^^^^^^^^ SIM910
3 |
4 | # SIM910
|
= help: Replace `{}.get(key, None)` with `{}.get(key)`
Safe fix
1 1 | # SIM910
2 |-{}.get(key, None)
2 |+{}.get(key)
3 3 |
4 4 | # SIM910
5 5 | {}.get("key", None)
SIM910.py:5:1: SIM910 [*] Use `{}.get("key")` instead of `{}.get("key", None)`
|
4 | # SIM910
5 | {}.get("key", None)
| ^^^^^^^^^^^^^^^^^^^ SIM910
6 |
7 | # OK
|
= help: Replace `{}.get("key", None)` with `{}.get("key")`
Safe fix
2 2 | {}.get(key, None)
3 3 |
4 4 | # SIM910
5 |-{}.get("key", None)
5 |+{}.get("key")
6 6 |
7 7 | # OK
8 8 | {}.get(key)
SIM910.py:20:9: SIM910 [*] Use `{}.get(key)` instead of `{}.get(key, None)`
|
19 | # SIM910
20 | if a := {}.get(key, None):
| ^^^^^^^^^^^^^^^^^ SIM910
21 | pass
|
= help: Replace `{}.get(key, None)` with `{}.get(key)`
Safe fix
17 17 | {}.get("key", False)
18 18 |
19 19 | # SIM910
20 |-if a := {}.get(key, None):
20 |+if a := {}.get(key):
21 21 | pass
22 22 |
23 23 | # SIM910
SIM910.py:24:5: SIM910 [*] Use `{}.get(key)` instead of `{}.get(key, None)`
|
23 | # SIM910
24 | a = {}.get(key, None)
| ^^^^^^^^^^^^^^^^^ SIM910
25 |
26 | # SIM910
|
= help: Replace `{}.get(key, None)` with `{}.get(key)`
Safe fix
21 21 | pass
22 22 |
23 23 | # SIM910
24 |-a = {}.get(key, None)
24 |+a = {}.get(key)
25 25 |
26 26 | # SIM910
27 27 | ({}).get(key, None)
SIM910.py:27:1: SIM910 [*] Use `({}).get(key)` instead of `({}).get(key, None)`
|
26 | # SIM910
27 | ({}).get(key, None)
| ^^^^^^^^^^^^^^^^^^^ SIM910
28 |
29 | # SIM910
|
= help: Replace `({}).get(key, None)` with `({}).get(key)`
Safe fix
24 24 | a = {}.get(key, None)
25 25 |
26 26 | # SIM910
27 |-({}).get(key, None)
27 |+({}).get(key)
28 28 |
29 29 | # SIM910
30 30 | ages = {"Tom": 23, "Maria": 23, "Dog": 11}
SIM910.py:31:7: SIM910 [*] Use `ages.get("Cat")` instead of `ages.get("Cat", None)`
|
29 | # SIM910
30 | ages = {"Tom": 23, "Maria": 23, "Dog": 11}
31 | age = ages.get("Cat", None)
| ^^^^^^^^^^^^^^^^^^^^^ SIM910
32 |
33 | # OK
|
= help: Replace `ages.get("Cat", None)` with `ages.get("Cat")`
Safe fix
28 28 |
29 29 | # SIM910
30 30 | ages = {"Tom": 23, "Maria": 23, "Dog": 11}
31 |-age = ages.get("Cat", None)
31 |+age = ages.get("Cat")
32 32 |
33 33 | # OK
34 34 | ages = ["Tom", "Maria", "Dog"]

View File

@@ -24,7 +24,7 @@ use crate::rules::flake8_tidy_imports::matchers::NameMatchPolicy;
/// automatic way.
///
/// ## Options
/// - `flake8-tidy-imports.banned-api`
/// - `lint.flake8-tidy-imports.banned-api`
#[violation]
pub struct BannedApi {
name: String,

View File

@@ -38,7 +38,7 @@ use crate::rules::flake8_tidy_imports::matchers::NameMatchPolicy;
/// ```
///
/// ## Options
/// - `flake8-tidy-imports.banned-module-level-imports`
/// - `lint.flake8-tidy-imports.banned-module-level-imports`
#[violation]
pub struct BannedModuleLevelImports {
name: String,

View File

@@ -42,7 +42,7 @@ use crate::rules::flake8_tidy_imports::settings::Strictness;
/// ```
///
/// ## Options
/// - `flake8-tidy-imports.ban-relative-imports`
/// - `lint.flake8-tidy-imports.ban-relative-imports`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#imports
#[violation]

View File

@@ -22,7 +22,7 @@ use crate::rules::flake8_type_checking::imports::ImportBinding;
/// The type-checking block is not executed at runtime, so the import will not
/// be available at runtime.
///
/// If [`flake8-type-checking.quote-annotations`] is set to `true`,
/// If [`lint.flake8-type-checking.quote-annotations`] is set to `true`,
/// annotations will be wrapped in quotes if doing so would enable the
/// corresponding import to remain in the type-checking block.
///
@@ -48,7 +48,7 @@ use crate::rules::flake8_type_checking::imports::ImportBinding;
/// ```
///
/// ## Options
/// - `flake8-type-checking.quote-annotations`
/// - `lint.flake8-type-checking.quote-annotations`
///
/// ## References
/// - [PEP 535](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)

View File

@@ -28,14 +28,14 @@ use crate::rules::isort::{categorize, ImportSection, ImportType};
/// instead be imported conditionally under an `if TYPE_CHECKING:` block to
/// minimize runtime overhead.
///
/// If [`flake8-type-checking.quote-annotations`] is set to `true`,
/// If [`lint.flake8-type-checking.quote-annotations`] is set to `true`,
/// annotations will be wrapped in quotes if doing so would enable the
/// corresponding import to be moved into an `if TYPE_CHECKING:` block.
///
/// If a class _requires_ that type annotations be available at runtime (as is
/// the case for Pydantic, SQLAlchemy, and other libraries), consider using
/// the [`flake8-type-checking.runtime-evaluated-base-classes`] and
/// [`flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
/// the [`lint.flake8-type-checking.runtime-evaluated-base-classes`] and
/// [`lint.flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
/// as such.
///
/// ## Example
@@ -64,9 +64,9 @@ use crate::rules::isort::{categorize, ImportSection, ImportType};
/// ```
///
/// ## Options
/// - `flake8-type-checking.quote-annotations`
/// - `flake8-type-checking.runtime-evaluated-base-classes`
/// - `flake8-type-checking.runtime-evaluated-decorators`
/// - `lint.flake8-type-checking.quote-annotations`
/// - `lint.flake8-type-checking.runtime-evaluated-base-classes`
/// - `lint.flake8-type-checking.runtime-evaluated-decorators`
///
/// ## References
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
@@ -101,14 +101,14 @@ impl Violation for TypingOnlyFirstPartyImport {
/// instead be imported conditionally under an `if TYPE_CHECKING:` block to
/// minimize runtime overhead.
///
/// If [`flake8-type-checking.quote-annotations`] is set to `true`,
/// If [`lint.flake8-type-checking.quote-annotations`] is set to `true`,
/// annotations will be wrapped in quotes if doing so would enable the
/// corresponding import to be moved into an `if TYPE_CHECKING:` block.
///
/// If a class _requires_ that type annotations be available at runtime (as is
/// the case for Pydantic, SQLAlchemy, and other libraries), consider using
/// the [`flake8-type-checking.runtime-evaluated-base-classes`] and
/// [`flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
/// the [`lint.flake8-type-checking.runtime-evaluated-base-classes`] and
/// [`lint.flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
/// as such.
///
/// ## Example
@@ -137,9 +137,9 @@ impl Violation for TypingOnlyFirstPartyImport {
/// ```
///
/// ## Options
/// - `flake8-type-checking.quote-annotations`
/// - `flake8-type-checking.runtime-evaluated-base-classes`
/// - `flake8-type-checking.runtime-evaluated-decorators`
/// - `lint.flake8-type-checking.quote-annotations`
/// - `lint.flake8-type-checking.runtime-evaluated-base-classes`
/// - `lint.flake8-type-checking.runtime-evaluated-decorators`
///
/// ## References
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)
@@ -174,14 +174,14 @@ impl Violation for TypingOnlyThirdPartyImport {
/// instead be imported conditionally under an `if TYPE_CHECKING:` block to
/// minimize runtime overhead.
///
/// If [`flake8-type-checking.quote-annotations`] is set to `true`,
/// If [`lint.flake8-type-checking.quote-annotations`] is set to `true`,
/// annotations will be wrapped in quotes if doing so would enable the
/// corresponding import to be moved into an `if TYPE_CHECKING:` block.
///
/// If a class _requires_ that type annotations be available at runtime (as is
/// the case for Pydantic, SQLAlchemy, and other libraries), consider using
/// the [`flake8-type-checking.runtime-evaluated-base-classes`] and
/// [`flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
/// the [`lint.flake8-type-checking.runtime-evaluated-base-classes`] and
/// [`lint.flake8-type-checking.runtime-evaluated-decorators`] settings to mark them
/// as such.
///
/// ## Example
@@ -210,9 +210,9 @@ impl Violation for TypingOnlyThirdPartyImport {
/// ```
///
/// ## Options
/// - `flake8-type-checking.quote-annotations`
/// - `flake8-type-checking.runtime-evaluated-base-classes`
/// - `flake8-type-checking.runtime-evaluated-decorators`
/// - `lint.flake8-type-checking.quote-annotations`
/// - `lint.flake8-type-checking.runtime-evaluated-base-classes`
/// - `lint.flake8-type-checking.runtime-evaluated-decorators`
///
/// ## References
/// - [PEP 536](https://peps.python.org/pep-0563/#runtime-annotation-resolution-and-type-checking)

View File

@@ -44,7 +44,7 @@ use ruff_python_ast::identifier::Identifier;
/// ```
///
/// ## Options
/// - `mccabe.max-complexity`
/// - `lint.mccabe.max-complexity`
#[violation]
pub struct ComplexStructure {
name: String,

View File

@@ -22,10 +22,10 @@ use crate::checkers::ast::Checker;
/// > append a single trailing underscore rather than use an abbreviation or spelling corruption.
/// > Thus `class_` is better than `clss`. (Perhaps better is to avoid such clashes by using a synonym.)
///
/// Names can be excluded from this rule using the [`pep8-naming.ignore-names`]
/// or [`pep8-naming.extend-ignore-names`] configuration options. For example,
/// Names can be excluded from this rule using the [`lint.pep8-naming.ignore-names`]
/// or [`lint.pep8-naming.extend-ignore-names`] configuration options. For example,
/// to allow the use of `klass` as the first argument to class methods, set
/// the [`pep8-naming.extend-ignore-names`] option to `["klass"]`.
/// the [`lint.pep8-naming.extend-ignore-names`] option to `["klass"]`.
///
/// ## Example
/// ```python
@@ -44,10 +44,10 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `pep8-naming.classmethod-decorators`
/// - `pep8-naming.staticmethod-decorators`
/// - `pep8-naming.ignore-names`
/// - `pep8-naming.extend-ignore-names`
/// - `lint.pep8-naming.classmethod-decorators`
/// - `lint.pep8-naming.staticmethod-decorators`
/// - `lint.pep8-naming.ignore-names`
/// - `lint.pep8-naming.extend-ignore-names`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments
#[violation]

View File

@@ -22,10 +22,10 @@ use crate::checkers::ast::Checker;
/// > append a single trailing underscore rather than use an abbreviation or spelling corruption.
/// > Thus `class_` is better than `clss`. (Perhaps better is to avoid such clashes by using a synonym.)
///
/// Names can be excluded from this rule using the [`pep8-naming.ignore-names`]
/// or [`pep8-naming.extend-ignore-names`] configuration options. For example,
/// Names can be excluded from this rule using the [`lint.pep8-naming.ignore-names`]
/// or [`lint.pep8-naming.extend-ignore-names`] configuration options. For example,
/// to allow the use of `this` as the first argument to instance methods, set
/// the [`pep8-naming.extend-ignore-names`] option to `["this"]`.
/// the [`lint.pep8-naming.extend-ignore-names`] option to `["this"]`.
///
/// ## Example
/// ```python
@@ -42,10 +42,10 @@ use crate::checkers::ast::Checker;
/// ```
///
/// ## Options
/// - `pep8-naming.classmethod-decorators`
/// - `pep8-naming.staticmethod-decorators`
/// - `pep8-naming.ignore-names`
/// - `pep8-naming.extend-ignore-names`
/// - `lint.pep8-naming.classmethod-decorators`
/// - `lint.pep8-naming.staticmethod-decorators`
/// - `lint.pep8-naming.ignore-names`
/// - `lint.pep8-naming.extend-ignore-names`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-method-arguments
#[violation]

View File

@@ -20,10 +20,10 @@ use crate::settings::types::IdentifierPattern;
/// > improve readability. mixedCase is allowed only in contexts where thats already the
/// > prevailing style (e.g. threading.py), to retain backwards compatibility.
///
/// Names can be excluded from this rule using the [`pep8-naming.ignore-names`]
/// or [`pep8-naming.extend-ignore-names`] configuration options. For example,
/// Names can be excluded from this rule using the [`lint.pep8-naming.ignore-names`]
/// or [`lint.pep8-naming.extend-ignore-names`] configuration options. For example,
/// to ignore all functions starting with `test_` from this rule, set the
/// [`pep8-naming.extend-ignore-names`] option to `["test_*"]`.
/// [`lint.pep8-naming.extend-ignore-names`] option to `["test_*"]`.
///
/// ## Example
/// ```python
@@ -38,8 +38,8 @@ use crate::settings::types::IdentifierPattern;
/// ```
///
/// ## Options
/// - `pep8-naming.ignore-names`
/// - `pep8-naming.extend-ignore-names`
/// - `lint.pep8-naming.ignore-names`
/// - `lint.pep8-naming.extend-ignore-names`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-variable-names
#[violation]

View File

@@ -34,8 +34,8 @@ use crate::rules::pep8_naming::helpers;
/// ```
///
/// ## Options
/// - `pep8-naming.ignore-names`
/// - `pep8-naming.extend-ignore-names`
/// - `lint.pep8-naming.ignore-names`
/// - `lint.pep8-naming.extend-ignore-names`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#function-and-variable-names
#[violation]

View File

@@ -67,8 +67,6 @@ mod tests {
}
#[test_case(Rule::IsLiteral, Path::new("constant_literals.py"))]
#[test_case(Rule::MultipleImportsOnOneLine, Path::new("E40.py"))]
#[test_case(Rule::ModuleImportNotAtTopOfFile, Path::new("E402_0.py"))]
#[test_case(Rule::TypeComparison, Path::new("E721.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!(

View File

@@ -13,7 +13,7 @@ use crate::settings::LinterSettings;
/// For flowing long blocks of text (docstrings or comments), overlong lines
/// can hurt readability. [PEP 8], for example, recommends that such lines be
/// limited to 72 characters, while this rule enforces the limit specified by
/// the [`pycodestyle.max-doc-length`] setting. (If no value is provided, this
/// the [`lint.pycodestyle.max-doc-length`] setting. (If no value is provided, this
/// rule will be ignored, even if it's added to your `--select` list.)
///
/// In the context of this rule, a "doc line" is defined as a line consisting
@@ -32,8 +32,8 @@ use crate::settings::LinterSettings;
/// overlong if a pragma comment _causes_ it to exceed the line length.
/// (This behavior aligns with that of the Ruff formatter.)
///
/// If [`pycodestyle.ignore-overlong-task-comments`] is `true`, this rule will
/// also ignore comments that start with any of the specified [`task-tags`]
/// If [`lint.pycodestyle.ignore-overlong-task-comments`] is `true`, this rule will
/// also ignore comments that start with any of the specified [`lint.task-tags`]
/// (e.g., `# TODO:`).
///
/// ## Example
@@ -65,9 +65,9 @@ use crate::settings::LinterSettings;
/// ```
///
/// ## Options
/// - `task-tags`
/// - `pycodestyle.max-doc-length`
/// - `pycodestyle.ignore-overlong-task-comments`
/// - `lint.task-tags`
/// - `lint.pycodestyle.max-doc-length`
/// - `lint.pycodestyle.ignore-overlong-task-comments`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length
#[violation]

View File

@@ -28,8 +28,8 @@ use crate::settings::LinterSettings;
/// overlong if a pragma comment _causes_ it to exceed the line length.
/// (This behavior aligns with that of the Ruff formatter.)
///
/// If [`pycodestyle.ignore-overlong-task-comments`] is `true`, this rule will
/// also ignore comments that start with any of the specified [`task-tags`]
/// If [`lint.pycodestyle.ignore-overlong-task-comments`] is `true`, this rule will
/// also ignore comments that start with any of the specified [`lint.task-tags`]
/// (e.g., `# TODO:`).
///
/// ## Example
@@ -60,9 +60,9 @@ use crate::settings::LinterSettings;
///
/// ## Options
/// - `line-length`
/// - `task-tags`
/// - `pycodestyle.ignore-overlong-task-comments`
/// - `pycodestyle.max-line-length`
/// - `lint.task-tags`
/// - `lint.pycodestyle.ignore-overlong-task-comments`
/// - `lint.pycodestyle.max-line-length`
///
/// [PEP 8]: https://peps.python.org/pep-0008/#maximum-line-length
#[violation]

View File

@@ -49,15 +49,13 @@ impl Violation for MultipleImportsOnOneLine {
pub(crate) fn multiple_imports_on_one_line(checker: &mut Checker, stmt: &Stmt, names: &[Alias]) {
if names.len() > 1 {
let mut diagnostic = Diagnostic::new(MultipleImportsOnOneLine, stmt.range());
if checker.settings.preview.is_enabled() {
diagnostic.set_fix(split_imports(
stmt,
names,
checker.locator(),
checker.indexer(),
checker.stylist(),
));
}
diagnostic.set_fix(split_imports(
stmt,
names,
checker.locator(),
checker.indexer(),
checker.stylist(),
));
checker.diagnostics.push(diagnostic);
}
}

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
E40.py:2:1: E401 Multiple imports on one line
E40.py:2:1: E401 [*] Multiple imports on one line
|
1 | #: E401
2 | import os, sys
@@ -11,7 +11,16 @@ E40.py:2:1: E401 Multiple imports on one line
|
= help: Split imports
E40.py:65:1: E401 Multiple imports on one line
Safe fix
1 1 | #: E401
2 |-import os, sys
2 |+import os
3 |+import sys
3 4 |
4 5 | #: Okay
5 6 | import os
E40.py:65:1: E401 [*] Multiple imports on one line
|
64 | #: E401
65 | import re as regex, string # also with a comment!
@@ -20,7 +29,18 @@ E40.py:65:1: E401 Multiple imports on one line
|
= help: Split imports
E40.py:66:1: E401 Multiple imports on one line
Safe fix
62 62 | import bar
63 63 |
64 64 | #: E401
65 |-import re as regex, string # also with a comment!
65 |+import re as regex
66 |+import string # also with a comment!
66 67 | import re as regex, string; x = 1
67 68 |
68 69 | x = 1; import re as regex, string
E40.py:66:1: E401 [*] Multiple imports on one line
|
64 | #: E401
65 | import re as regex, string # also with a comment!
@@ -31,7 +51,17 @@ E40.py:66:1: E401 Multiple imports on one line
|
= help: Split imports
E40.py:68:8: E401 Multiple imports on one line
Safe fix
63 63 |
64 64 | #: E401
65 65 | import re as regex, string # also with a comment!
66 |-import re as regex, string; x = 1
66 |+import re as regex; import string; x = 1
67 67 |
68 68 | x = 1; import re as regex, string
69 69 |
E40.py:68:8: E401 [*] Multiple imports on one line
|
66 | import re as regex, string; x = 1
67 |
@@ -40,7 +70,17 @@ E40.py:68:8: E401 Multiple imports on one line
|
= help: Split imports
E40.py:72:5: E401 Multiple imports on one line
Safe fix
65 65 | import re as regex, string # also with a comment!
66 66 | import re as regex, string; x = 1
67 67 |
68 |-x = 1; import re as regex, string
68 |+x = 1; import re as regex; import string
69 69 |
70 70 |
71 71 | def blah():
E40.py:72:5: E401 [*] Multiple imports on one line
|
71 | def blah():
72 | import datetime as dt, copy
@@ -50,7 +90,18 @@ E40.py:72:5: E401 Multiple imports on one line
|
= help: Split imports
E40.py:75:9: E401 Multiple imports on one line
Safe fix
69 69 |
70 70 |
71 71 | def blah():
72 |- import datetime as dt, copy
72 |+ import datetime as dt
73 |+ import copy
73 74 |
74 75 | def nested_and_tested():
75 76 | import builtins, textwrap as tw
E40.py:75:9: E401 [*] Multiple imports on one line
|
74 | def nested_and_tested():
75 | import builtins, textwrap as tw
@@ -60,7 +111,18 @@ E40.py:75:9: E401 Multiple imports on one line
|
= help: Split imports
E40.py:77:16: E401 Multiple imports on one line
Safe fix
72 72 | import datetime as dt, copy
73 73 |
74 74 | def nested_and_tested():
75 |- import builtins, textwrap as tw
75 |+ import builtins
76 |+ import textwrap as tw
76 77 |
77 78 | x = 1; import re as regex, string
78 79 | import re as regex, string; x = 1
E40.py:77:16: E401 [*] Multiple imports on one line
|
75 | import builtins, textwrap as tw
76 |
@@ -70,7 +132,17 @@ E40.py:77:16: E401 Multiple imports on one line
|
= help: Split imports
E40.py:78:9: E401 Multiple imports on one line
Safe fix
74 74 | def nested_and_tested():
75 75 | import builtins, textwrap as tw
76 76 |
77 |- x = 1; import re as regex, string
77 |+ x = 1; import re as regex; import string
78 78 | import re as regex, string; x = 1
79 79 |
80 80 | if True: import re as regex, string
E40.py:78:9: E401 [*] Multiple imports on one line
|
77 | x = 1; import re as regex, string
78 | import re as regex, string; x = 1
@@ -80,7 +152,16 @@ E40.py:78:9: E401 Multiple imports on one line
|
= help: Split imports
E40.py:80:14: E401 Multiple imports on one line
Safe fix
75 75 | import builtins, textwrap as tw
76 76 |
77 77 | x = 1; import re as regex, string
78 |- import re as regex, string; x = 1
78 |+ import re as regex; import string; x = 1
79 79 |
80 80 | if True: import re as regex, string
E40.py:80:14: E401 [*] Multiple imports on one line
|
78 | import re as regex, string; x = 1
79 |
@@ -89,4 +170,11 @@ E40.py:80:14: E401 Multiple imports on one line
|
= help: Split imports
Safe fix
77 77 | x = 1; import re as regex, string
78 78 | import re as regex, string; x = 1
79 79 |
80 |- if True: import re as regex, string
80 |+ if True: import re as regex; import string

View File

@@ -1,36 +1,6 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
E402_0.py:25:1: E402 Module level import not at top of file
|
23 | sys.path.insert(0, "some/path")
24 |
25 | import f
| ^^^^^^^^ E402
26 |
27 | import matplotlib
|
E402_0.py:27:1: E402 Module level import not at top of file
|
25 | import f
26 |
27 | import matplotlib
| ^^^^^^^^^^^^^^^^^ E402
28 |
29 | matplotlib.use("Agg")
|
E402_0.py:31:1: E402 Module level import not at top of file
|
29 | matplotlib.use("Agg")
30 |
31 | import g
| ^^^^^^^^ E402
32 |
33 | __some__magic = 1
|
E402_0.py:35:1: E402 Module level import not at top of file
|
33 | __some__magic = 1

View File

@@ -1,180 +0,0 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
E40.py:2:1: E401 [*] Multiple imports on one line
|
1 | #: E401
2 | import os, sys
| ^^^^^^^^^^^^^^ E401
3 |
4 | #: Okay
|
= help: Split imports
Safe fix
1 1 | #: E401
2 |-import os, sys
2 |+import os
3 |+import sys
3 4 |
4 5 | #: Okay
5 6 | import os
E40.py:65:1: E401 [*] Multiple imports on one line
|
64 | #: E401
65 | import re as regex, string # also with a comment!
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
66 | import re as regex, string; x = 1
|
= help: Split imports
Safe fix
62 62 | import bar
63 63 |
64 64 | #: E401
65 |-import re as regex, string # also with a comment!
65 |+import re as regex
66 |+import string # also with a comment!
66 67 | import re as regex, string; x = 1
67 68 |
68 69 | x = 1; import re as regex, string
E40.py:66:1: E401 [*] Multiple imports on one line
|
64 | #: E401
65 | import re as regex, string # also with a comment!
66 | import re as regex, string; x = 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
67 |
68 | x = 1; import re as regex, string
|
= help: Split imports
Safe fix
63 63 |
64 64 | #: E401
65 65 | import re as regex, string # also with a comment!
66 |-import re as regex, string; x = 1
66 |+import re as regex; import string; x = 1
67 67 |
68 68 | x = 1; import re as regex, string
69 69 |
E40.py:68:8: E401 [*] Multiple imports on one line
|
66 | import re as regex, string; x = 1
67 |
68 | x = 1; import re as regex, string
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
|
= help: Split imports
Safe fix
65 65 | import re as regex, string # also with a comment!
66 66 | import re as regex, string; x = 1
67 67 |
68 |-x = 1; import re as regex, string
68 |+x = 1; import re as regex; import string
69 69 |
70 70 |
71 71 | def blah():
E40.py:72:5: E401 [*] Multiple imports on one line
|
71 | def blah():
72 | import datetime as dt, copy
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
73 |
74 | def nested_and_tested():
|
= help: Split imports
Safe fix
69 69 |
70 70 |
71 71 | def blah():
72 |- import datetime as dt, copy
72 |+ import datetime as dt
73 |+ import copy
73 74 |
74 75 | def nested_and_tested():
75 76 | import builtins, textwrap as tw
E40.py:75:9: E401 [*] Multiple imports on one line
|
74 | def nested_and_tested():
75 | import builtins, textwrap as tw
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
76 |
77 | x = 1; import re as regex, string
|
= help: Split imports
Safe fix
72 72 | import datetime as dt, copy
73 73 |
74 74 | def nested_and_tested():
75 |- import builtins, textwrap as tw
75 |+ import builtins
76 |+ import textwrap as tw
76 77 |
77 78 | x = 1; import re as regex, string
78 79 | import re as regex, string; x = 1
E40.py:77:16: E401 [*] Multiple imports on one line
|
75 | import builtins, textwrap as tw
76 |
77 | x = 1; import re as regex, string
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
78 | import re as regex, string; x = 1
|
= help: Split imports
Safe fix
74 74 | def nested_and_tested():
75 75 | import builtins, textwrap as tw
76 76 |
77 |- x = 1; import re as regex, string
77 |+ x = 1; import re as regex; import string
78 78 | import re as regex, string; x = 1
79 79 |
80 80 | if True: import re as regex, string
E40.py:78:9: E401 [*] Multiple imports on one line
|
77 | x = 1; import re as regex, string
78 | import re as regex, string; x = 1
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
79 |
80 | if True: import re as regex, string
|
= help: Split imports
Safe fix
75 75 | import builtins, textwrap as tw
76 76 |
77 77 | x = 1; import re as regex, string
78 |- import re as regex, string; x = 1
78 |+ import re as regex; import string; x = 1
79 79 |
80 80 | if True: import re as regex, string
E40.py:80:14: E401 [*] Multiple imports on one line
|
78 | import re as regex, string; x = 1
79 |
80 | if True: import re as regex, string
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ E401
|
= help: Split imports
Safe fix
77 77 | x = 1; import re as regex, string
78 78 | import re as regex, string; x = 1
79 79 |
80 |- if True: import re as regex, string
80 |+ if True: import re as regex; import string

View File

@@ -1,28 +0,0 @@
---
source: crates/ruff_linter/src/rules/pycodestyle/mod.rs
---
E402_0.py:35:1: E402 Module level import not at top of file
|
33 | __some__magic = 1
34 |
35 | import h
| ^^^^^^^^ E402
|
E402_0.py:45:1: E402 Module level import not at top of file
|
43 | import j
44 |
45 | import k; import l
| ^^^^^^^^ E402
|
E402_0.py:45:11: E402 Module level import not at top of file
|
43 | import j
44 |
45 | import k; import l
| ^^^^^^^^ E402
|

View File

@@ -12,7 +12,7 @@ mod tests {
use test_case::test_case;
use crate::registry::Rule;
use crate::settings::types::PreviewMode;
use crate::test::test_path;
use crate::{assert_messages, settings};
@@ -111,33 +111,6 @@ mod tests {
Ok(())
}
#[test_case(Rule::TripleSingleQuotes, Path::new("D.py"))]
#[test_case(Rule::TripleSingleQuotes, Path::new("D300.py"))]
fn preview_rules(rule_code: Rule, path: &Path) -> Result<()> {
// Tests for rules with preview features
let snapshot = format!(
"preview__{}_{}",
rule_code.noqa_code(),
path.to_string_lossy()
);
let diagnostics = test_path(
Path::new("pydocstyle").join(path).as_path(),
&settings::LinterSettings {
pydocstyle: Settings {
convention: None,
ignore_decorators: BTreeSet::from_iter(["functools.wraps".to_string()]),
property_decorators: BTreeSet::from_iter([
"gi.repository.GObject.Property".to_string()
]),
},
preview: PreviewMode::Enabled,
..settings::LinterSettings::for_rule(rule_code)
},
)?;
assert_messages!(snapshot, diagnostics);
Ok(())
}
#[test]
fn bom() -> Result<()> {
let diagnostics = test_path(

View File

@@ -37,7 +37,7 @@ use crate::registry::Rule;
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// [D211]: https://docs.astral.sh/ruff/rules/blank-line-before-class
#[violation]
@@ -84,7 +84,7 @@ impl AlwaysFixableViolation for OneBlankLineBeforeClass {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -134,7 +134,7 @@ impl AlwaysFixableViolation for OneBlankLineAfterClass {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// [D203]: https://docs.astral.sh/ruff/rules/one-blank-line-before-class
#[violation]

View File

@@ -36,7 +36,7 @@ use crate::rules::pydocstyle::helpers::logical_line;
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)

View File

@@ -37,7 +37,7 @@ use crate::rules::pydocstyle::helpers::logical_line;
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)

View File

@@ -32,7 +32,7 @@ use crate::docstrings::Docstring;
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)

View File

@@ -43,7 +43,7 @@ static MOOD: Lazy<Mood> = Lazy::new(Mood::new);
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)

View File

@@ -76,7 +76,7 @@ use crate::rules::pydocstyle::settings::Convention;
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -175,7 +175,7 @@ impl AlwaysFixableViolation for SectionNotOverIndented {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -253,7 +253,7 @@ impl AlwaysFixableViolation for SectionUnderlineNotOverIndented {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -350,7 +350,7 @@ impl AlwaysFixableViolation for CapitalizeSectionName {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -446,7 +446,7 @@ impl AlwaysFixableViolation for NewLineAfterSectionName {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -548,7 +548,7 @@ impl AlwaysFixableViolation for DashedUnderlineAfterSection {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -647,7 +647,7 @@ impl AlwaysFixableViolation for SectionUnderlineAfterName {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -741,7 +741,7 @@ impl AlwaysFixableViolation for SectionUnderlineMatchesSectionLength {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -835,7 +835,7 @@ impl AlwaysFixableViolation for NoBlankLineAfterSection {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -931,7 +931,7 @@ impl AlwaysFixableViolation for NoBlankLineBeforeSection {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -1021,7 +1021,7 @@ impl AlwaysFixableViolation for BlankLineAfterLastSection {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -1098,7 +1098,7 @@ impl Violation for EmptyDocstringSection {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -1180,7 +1180,7 @@ impl AlwaysFixableViolation for SectionNameEndsInColon {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)
@@ -1264,7 +1264,7 @@ impl Violation for UndocumentedParam {
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)

View File

@@ -33,7 +33,7 @@ use crate::rules::pydocstyle::helpers::normalize_word;
/// ```
///
/// ## Options
/// - `pydocstyle.convention`
/// - `lint.pydocstyle.convention`
///
/// ## References
/// - [PEP 257 Docstring Conventions](https://peps.python.org/pep-0257/)

Some files were not shown because too many files have changed in this diff Show More