Compare commits

...

13 Commits

Author SHA1 Message Date
Jane Lewis
0334133dbd Use a deprecated output format for the ecosystem check 2024-01-30 09:33:57 -08:00
Zanie Blue
b9b44a1b35 Remove the NURSERY selector from the json schema (#9695) 2024-01-30 16:51:31 +00:00
Zanie Blue
9f5a394c34 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 10:44:15 -06:00
Zanie Blue
0d543f0aaa 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 09:27:56 -06:00
Jane Lewis
b244178cd0 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-29 16:57:56 -08:00
Charlie Marsh
2dea20f4e9 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-29 15:01:45 -06:00
Charlie Marsh
88522d245f 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-29 15:01:45 -06:00
Charlie Marsh
9a1aa29a7b 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-29 15:01:45 -06:00
Charlie Marsh
c0e2494b41 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.
2024-01-29 15:01:45 -06:00
Charlie Marsh
826a12c28b 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-29 15:01:45 -06:00
Charlie Marsh
065fa239cd [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-29 15:01:45 -06:00
Micha Reiser
269ac46dfe Add deprecation message for top-level lint settings (#9582) 2024-01-29 15:01:45 -06:00
Micha Reiser
b434285c85 Promote lint. settings over top-level settings (#9476) 2024-01-29 15:01:45 -06:00
196 changed files with 3191 additions and 4762 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.

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

@@ -116,7 +116,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 +142,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 +157,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

@@ -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(

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

@@ -351,6 +351,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),
@@ -916,7 +917,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

@@ -98,5 +98,6 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
("T002", "FIX002"),
("T003", "FIX003"),
("T004", "FIX004"),
("RUF011", "B035"),
])
});

View File

@@ -267,7 +267,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(),

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

@@ -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,4 +435,12 @@ SIM114.py:144:1: SIM114 Combine `if` branches using logical `or` operator
|
= help: Combine `if` branches
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

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,446 +0,0 @@
---
source: crates/ruff_linter/src/rules/flake8_simplify/mod.rs
---
SIM114.py:2:1: SIM114 [*] Combine `if` branches using logical `or` operator
|
1 | # Errors
2 | / if a:
3 | | b
4 | | elif c:
5 | | b
| |_____^ SIM114
6 |
7 | if a: # we preserve comments, too!
|
= help: Combine `if` branches
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 |
7 | / if a: # we preserve comments, too!
8 | | b
9 | | elif c: # but not on the second branch
10 | | b
| |_____^ SIM114
11 |
12 | if x == 1:
|
= help: Combine `if` branches
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 |
12 | / if x == 1:
13 | | for _ in range(20):
14 | | print("hello")
15 | | elif x == 2:
16 | | for _ in range(20):
17 | | print("hello")
| |______________________^ SIM114
18 |
19 | if x == 1:
|
= help: Combine `if` branches
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 |
19 | / if x == 1:
20 | | if True:
21 | | for _ in range(20):
22 | | print("hello")
23 | | elif x == 2:
24 | | if True:
25 | | for _ in range(20):
26 | | print("hello")
| |__________________________^ SIM114
27 |
28 | if x == 1:
|
= help: Combine `if` branches
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 |
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:
36 | | if True:
37 | | for _ in range(20):
38 | | print("hello")
39 | | elif False:
40 | | for _ in range(20):
41 | | print("hello")
| |__________________________^ SIM114
42 |
43 | if (
|
= help: Combine `if` branches
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:
| _____^
30 | | for _ in range(20):
31 | | print("hello")
32 | | elif False:
33 | | for _ in range(20):
34 | | print("hello")
| |__________________________^ SIM114
35 | elif x == 2:
36 | if True:
|
= help: Combine `if` branches
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:
36 | if True:
| _____^
37 | | for _ in range(20):
38 | | print("hello")
39 | | elif False:
40 | | for _ in range(20):
41 | | print("hello")
| |__________________________^ SIM114
42 |
43 | if (
|
= help: Combine `if` branches
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 |
43 | / if (
44 | | x == 1
45 | | and y == 2
46 | | and z == 3
47 | | and a == 4
48 | | and b == 5
49 | | and c == 6
50 | | and d == 7
51 | | and e == 8
52 | | and f == 9
53 | | and g == 10
54 | | and h == 11
55 | | and i == 12
56 | | and j == 13
57 | | and k == 14
58 | | ):
59 | | pass
60 | | elif 1 == 2:
61 | | pass
| |________^ SIM114
62 |
63 | if result.eofs == "O":
|
= help: Combine `if` branches
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
67 | / elif result.eofs == "F":
68 | | errors = 1
69 | | elif result.eofs == "E":
70 | | errors = 1
| |______________^ SIM114
71 | elif result.eofs == "X":
72 | errors = 1
|
= help: Combine `if` branches
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
69 | / elif result.eofs == "E":
70 | | errors = 1
71 | | elif result.eofs == "X":
72 | | errors = 1
| |______________^ SIM114
73 | elif result.eofs == "C":
74 | errors = 1
|
= help: Combine `if` branches
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
71 | / elif result.eofs == "X":
72 | | errors = 1
73 | | elif result.eofs == "C":
74 | | errors = 1
| |______________^ SIM114
|
= help: Combine `if` branches
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
118 | if a > b: # end-of-line
| _____^
119 | | return 3
120 | | elif a == b:
121 | | return 3
| |________________^ SIM114
122 | elif a < b: # end-of-line
123 | return 4
|
= help: Combine `if` branches
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
122 | elif a < b: # end-of-line
| _____^
123 | | return 4
124 | | elif b is None:
125 | | return 4
| |________________^ SIM114
|
= help: Combine `if` branches
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
132 | if a > b: # end-of-line
| _____^
133 | | return 3
134 | | elif a := 1:
135 | | return 3
| |________________^ SIM114
|
= help: Combine `if` branches
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
140 | | elif c: # but not on the second branch
141 | | b
| |_____^ SIM114
|
= help: Combine `if` branches
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
| |_________^ SIM114
|
= help: Combine `if` branches
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

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/)

View File

@@ -80,14 +80,12 @@ pub(crate) fn triple_quotes(checker: &mut Checker, docstring: &Docstring) {
let mut diagnostic =
Diagnostic::new(TripleSingleQuotes { expected_quote }, docstring.range());
if checker.settings.preview.is_enabled() {
let body = docstring.body().as_str();
if !body.ends_with('\'') {
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format!("{prefixes}'''{body}'''"),
docstring.range(),
)));
}
let body = docstring.body().as_str();
if !body.ends_with('\'') {
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format!("{prefixes}'''{body}'''"),
docstring.range(),
)));
}
checker.diagnostics.push(diagnostic);
@@ -98,14 +96,12 @@ pub(crate) fn triple_quotes(checker: &mut Checker, docstring: &Docstring) {
let mut diagnostic =
Diagnostic::new(TripleSingleQuotes { expected_quote }, docstring.range());
if checker.settings.preview.is_enabled() {
let body = docstring.body().as_str();
if !body.ends_with('"') {
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format!("{prefixes}\"\"\"{body}\"\"\""),
docstring.range(),
)));
}
let body = docstring.body().as_str();
if !body.ends_with('"') {
diagnostic.set_fix(Fix::safe_edit(Edit::range_replacement(
format!("{prefixes}\"\"\"{body}\"\"\""),
docstring.range(),
)));
}
checker.diagnostics.push(diagnostic);

View File

@@ -1,7 +1,7 @@
---
source: crates/ruff_linter/src/rules/pydocstyle/mod.rs
---
D.py:307:5: D300 Use triple double quotes `"""`
D.py:307:5: D300 [*] Use triple double quotes `"""`
|
305 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
306 | def triple_single_quotes_raw():
@@ -10,7 +10,17 @@ D.py:307:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:312:5: D300 Use triple double quotes `"""`
Safe fix
304 304 |
305 305 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
306 306 | def triple_single_quotes_raw():
307 |- r'''Summary.'''
307 |+ r"""Summary."""
308 308 |
309 309 |
310 310 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
D.py:312:5: D300 [*] Use triple double quotes `"""`
|
310 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
311 | def triple_single_quotes_raw_uppercase():
@@ -19,7 +29,17 @@ D.py:312:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:317:5: D300 Use triple double quotes `"""`
Safe fix
309 309 |
310 310 | @expect('D300: Use """triple double quotes""" (found \'\'\'-quotes)')
311 311 | def triple_single_quotes_raw_uppercase():
312 |- R'''Summary.'''
312 |+ R"""Summary."""
313 313 |
314 314 |
315 315 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
D.py:317:5: D300 [*] Use triple double quotes `"""`
|
315 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
316 | def single_quotes_raw():
@@ -28,7 +48,17 @@ D.py:317:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:322:5: D300 Use triple double quotes `"""`
Safe fix
314 314 |
315 315 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
316 316 | def single_quotes_raw():
317 |- r'Summary.'
317 |+ r"""Summary."""
318 318 |
319 319 |
320 320 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
D.py:322:5: D300 [*] Use triple double quotes `"""`
|
320 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
321 | def single_quotes_raw_uppercase():
@@ -37,7 +67,17 @@ D.py:322:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:328:5: D300 Use triple double quotes `"""`
Safe fix
319 319 |
320 320 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
321 321 | def single_quotes_raw_uppercase():
322 |- R'Summary.'
322 |+ R"""Summary."""
323 323 |
324 324 |
325 325 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
D.py:328:5: D300 [*] Use triple double quotes `"""`
|
326 | @expect('D301: Use r""" if any backslashes in a docstring')
327 | def single_quotes_raw_uppercase_backslash():
@@ -46,7 +86,17 @@ D.py:328:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:645:5: D300 Use triple double quotes `"""`
Safe fix
325 325 | @expect('D300: Use """triple double quotes""" (found \'-quotes)')
326 326 | @expect('D301: Use r""" if any backslashes in a docstring')
327 327 | def single_quotes_raw_uppercase_backslash():
328 |- R'Sum\mary.'
328 |+ R"""Sum\mary."""
329 329 |
330 330 |
331 331 | @expect('D301: Use r""" if any backslashes in a docstring')
D.py:645:5: D300 [*] Use triple double quotes `"""`
|
644 | def single_line_docstring_with_an_escaped_backslash():
645 | "\
@@ -58,7 +108,19 @@ D.py:645:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:649:5: D300 Use triple double quotes `"""`
Safe fix
642 642 |
643 643 |
644 644 | def single_line_docstring_with_an_escaped_backslash():
645 |- "\
646 |- "
645 |+ """\
646 |+ """
647 647 |
648 648 | class StatementOnSameLineAsDocstring:
649 649 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
D.py:649:5: D300 [*] Use triple double quotes `"""`
|
648 | class StatementOnSameLineAsDocstring:
649 | "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
@@ -68,7 +130,17 @@ D.py:649:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:654:5: D300 Use triple double quotes `"""`
Safe fix
646 646 | "
647 647 |
648 648 | class StatementOnSameLineAsDocstring:
649 |- "After this docstring there's another statement on the same line separated by a semicolon." ; priorities=1
649 |+ """After this docstring there's another statement on the same line separated by a semicolon.""" ; priorities=1
650 650 | def sort_services(self):
651 651 | pass
652 652 |
D.py:654:5: D300 [*] Use triple double quotes `"""`
|
653 | class StatementOnSameLineAsDocstring:
654 | "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
@@ -76,7 +148,17 @@ D.py:654:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:658:5: D300 Use triple double quotes `"""`
Safe fix
651 651 | pass
652 652 |
653 653 | class StatementOnSameLineAsDocstring:
654 |- "After this docstring there's another statement on the same line separated by a semicolon."; priorities=1
654 |+ """After this docstring there's another statement on the same line separated by a semicolon."""; priorities=1
655 655 |
656 656 |
657 657 | class CommentAfterDocstring:
D.py:658:5: D300 [*] Use triple double quotes `"""`
|
657 | class CommentAfterDocstring:
658 | "After this docstring there's a comment." # priorities=1
@@ -86,7 +168,17 @@ D.py:658:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
D.py:664:5: D300 Use triple double quotes `"""`
Safe fix
655 655 |
656 656 |
657 657 | class CommentAfterDocstring:
658 |- "After this docstring there's a comment." # priorities=1
658 |+ """After this docstring there's a comment.""" # priorities=1
659 659 | def sort_services(self):
660 660 | pass
661 661 |
D.py:664:5: D300 [*] Use triple double quotes `"""`
|
663 | def newline_after_closing_quote(self):
664 | "We enforce a newline after the closing quote for a multi-line docstring \
@@ -96,4 +188,16 @@ D.py:664:5: D300 Use triple double quotes `"""`
|
= help: Convert to triple double quotes
Safe fix
661 661 |
662 662 |
663 663 | def newline_after_closing_quote(self):
664 |- "We enforce a newline after the closing quote for a multi-line docstring \
665 |- but continuations shouldn't be considered multi-line"
664 |+ """We enforce a newline after the closing quote for a multi-line docstring \
665 |+ but continuations shouldn't be considered multi-line"""
666 666 |
667 667 |
668 668 |

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