[ruff] if k in d: del d[k] (RUF051) (#14553)

## Summary

Resolves #7537.

## Test Plan

`cargo nextest run` and `cargo insta test`.

---------

Co-authored-by: Micha Reiser <micha@reiser.io>
This commit is contained in:
InSync 2024-12-11 18:12:23 +07:00 committed by GitHub
parent f30227c436
commit 6f8d8fa36b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 893 additions and 1 deletions

View file

@ -0,0 +1,130 @@
d = {}
l = []
### Errors
if k in d: # Bare name
del d[k]
if '' in d: # String
del d[""] # Different quotes
if b"" in d: # Bytes
del d[ # Multiline slice
b'''''' # Triple quotes
]
if 0 in d: del d[0] # Single-line statement
if 3j in d: # Complex
del d[3j]
if 0.1234 in d: # Float
del d[.1_2_3_4] # Number separators and shorthand syntax
if True in d: # True
del d[True]
if False in d: # False
del d[False]
if None in d: # None
del d[
# Comment in the middle
None
]
if ... in d: # Ellipsis
del d[
# Comment in the middle, indented
...]
if "a" "bc" in d: # String concatenation
del d['abc']
if r"\foo" in d: # Raw string
del d['\\foo']
if b'yt' b'es' in d: # Bytes concatenation
del d[rb"""ytes"""] # Raw bytes
if k in d:
# comment that gets dropped
del d[k]
### Safely fixable
if k in d:
del d[k]
if '' in d:
del d[""]
if b"" in d:
del d[
b''''''
]
if 0 in d: del d[0]
if 3j in d:
del d[3j]
if 0.1234 in d:
del d[.1_2_3_4]
if True in d:
del d[True]
if False in d:
del d[False]
if None in d:
del d[
None
]
if ... in d:
del d[
...]
if "a" "bc" in d:
del d['abc']
if r"\foo" in d:
del d['\\foo']
if b'yt' b'es' in d:
del d[rb"""ytes"""] # This should not make the fix unsafe
### No errors
if k in l: # Not a dict
del l[k]
if d.__contains__(k): # Explicit dunder call
del d[k]
if a.k in d: # Attribute
del d[a.k]
if (a, b) in d: # Tuple
del d[a, b]
if 2 in d: # Different key value (int)
del d[3]
if 2_4j in d: # Different key value (complex)
del d[3.6] # Different key value (float)
if 0.1 + 0.2 in d: # Complex expression
del d[0.3]
if f"0" in d: # f-string
del d[f"0"]
if k in a.d: # Attribute dict
del a.d[k]

View file

@ -1235,6 +1235,9 @@ pub(crate) fn statement(stmt: &Stmt, checker: &mut Checker) {
}
}
}
if checker.enabled(Rule::IfKeyInDictDel) {
ruff::rules::if_key_in_dict_del(checker, if_);
}
}
Stmt::Assert(
assert_stmt @ ast::StmtAssert {

View file

@ -222,7 +222,7 @@ pub(crate) struct Checker<'a> {
analyze: deferred::Analyze,
/// The cumulative set of diagnostics computed across all lint rules.
pub(crate) diagnostics: Vec<Diagnostic>,
/// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations..
/// The list of names already seen by flake8-bugbear diagnostics, to avoid duplicate violations.
pub(crate) flake8_bugbear_seen: Vec<TextRange>,
/// The end offset of the last visited statement.
last_stmt_end: TextSize,

View file

@ -987,6 +987,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
(Ruff, "041") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryNestedLiteral),
(Ruff, "046") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryCastToInt),
(Ruff, "048") => (RuleGroup::Preview, rules::ruff::rules::MapIntVersionParsing),
(Ruff, "051") => (RuleGroup::Preview, rules::ruff::rules::IfKeyInDictDel),
(Ruff, "052") => (RuleGroup::Preview, rules::ruff::rules::UsedDummyVariable),
(Ruff, "055") => (RuleGroup::Preview, rules::ruff::rules::UnnecessaryRegularExpression),
(Ruff, "100") => (RuleGroup::Stable, rules::ruff::rules::UnusedNOQA),

View file

@ -71,6 +71,7 @@ mod tests {
#[test_case(Rule::InvalidAssertMessageLiteralArgument, Path::new("RUF040.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.py"))]
#[test_case(Rule::UnnecessaryNestedLiteral, Path::new("RUF041.pyi"))]
#[test_case(Rule::IfKeyInDictDel, Path::new("RUF051.py"))]
#[test_case(Rule::UsedDummyVariable, Path::new("RUF052.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());

View file

@ -0,0 +1,154 @@
use crate::checkers::ast::Checker;
use ruff_diagnostics::{AlwaysFixableViolation, Applicability, Diagnostic, Edit, Fix};
use ruff_macros::{derive_message_formats, ViolationMetadata};
use ruff_python_ast::{CmpOp, Expr, ExprName, ExprSubscript, Stmt, StmtIf};
use ruff_python_semantic::analyze::typing;
use ruff_python_semantic::SemanticModel;
type Key = Expr;
type Dict = ExprName;
/// ## What it does
/// Checks for `if key in dictionary: del dictionary[key]`.
///
/// ## Why is this bad?
/// To remove a key-value pair from a dictionary, it's more concise to use `.pop(..., None)`.
///
/// ## Example
///
/// ```python
/// if key in dictionary:
/// del dictionary[key]
/// ```
///
/// Use instead:
///
/// ```python
/// dictionary.pop(key, None)
/// ```
///
/// ## Fix safety
/// This rule's fix is marked as safe, unless the if statement contains comments.
#[derive(ViolationMetadata)]
pub(crate) struct IfKeyInDictDel;
impl AlwaysFixableViolation for IfKeyInDictDel {
#[derive_message_formats]
fn message(&self) -> String {
"Use `pop` instead of `key in dict` followed by `delete dict[key]`".to_string()
}
fn fix_title(&self) -> String {
"Replace `if` statement with `.pop(..., None)`".to_string()
}
}
/// RUF051
pub(crate) fn if_key_in_dict_del(checker: &mut Checker, stmt: &StmtIf) {
let [Stmt::Delete(delete)] = &stmt.body[..] else {
return;
};
let Some((test_dict, test_key)) = extract_dict_and_key_from_test(&stmt.test) else {
return;
};
let Some((del_dict, del_key)) = extract_dict_and_key_from_del(&delete.targets) else {
return;
};
if !is_same_key(test_key, del_key) || !is_same_dict(test_dict, del_dict) {
return;
}
if !is_known_to_be_of_type_dict(checker.semantic(), test_dict) {
return;
}
let fix = replace_with_dict_pop_fix(checker, stmt, test_dict, test_key);
let diagnostic = Diagnostic::new(IfKeyInDictDel, delete.range);
checker.diagnostics.push(diagnostic.with_fix(fix));
}
fn extract_dict_and_key_from_test(test: &Expr) -> Option<(&Dict, &Key)> {
let Expr::Compare(comp) = test else {
return None;
};
let [Expr::Name(dict)] = comp.comparators.as_ref() else {
return None;
};
if !matches!(comp.ops.as_ref(), [CmpOp::In]) {
return None;
}
Some((dict, &comp.left))
}
fn extract_dict_and_key_from_del(targets: &[Expr]) -> Option<(&Dict, &Key)> {
let [Expr::Subscript(ExprSubscript { value, slice, .. })] = targets else {
return None;
};
let Expr::Name(dict) = value.as_ref() else {
return None;
};
Some((dict, slice))
}
fn is_same_key(test: &Key, del: &Key) -> bool {
match (test, del) {
(Expr::Name(ExprName { id: test, .. }), Expr::Name(ExprName { id: del, .. })) => {
test.as_str() == del.as_str()
}
(Expr::NoneLiteral(..), Expr::NoneLiteral(..)) => true,
(Expr::EllipsisLiteral(..), Expr::EllipsisLiteral(..)) => true,
(Expr::BooleanLiteral(test), Expr::BooleanLiteral(del)) => test.value == del.value,
(Expr::NumberLiteral(test), Expr::NumberLiteral(del)) => test.value == del.value,
(Expr::BytesLiteral(test), Expr::BytesLiteral(del)) => {
Iterator::eq(test.value.bytes(), del.value.bytes())
}
(Expr::StringLiteral(test), Expr::StringLiteral(del)) => {
Iterator::eq(test.value.chars(), del.value.chars())
}
_ => false,
}
}
fn is_same_dict(test: &Dict, del: &Dict) -> bool {
test.id.as_str() == del.id.as_str()
}
fn is_known_to_be_of_type_dict(semantic: &SemanticModel, dict: &Dict) -> bool {
let Some(binding) = semantic.only_binding(dict).map(|id| semantic.binding(id)) else {
return false;
};
typing::is_dict(binding, semantic)
}
fn replace_with_dict_pop_fix(checker: &Checker, stmt: &StmtIf, dict: &Dict, key: &Key) -> Fix {
let locator = checker.locator();
let dict_expr = locator.slice(dict);
let key_expr = locator.slice(key);
let replacement = format!("{dict_expr}.pop({key_expr}, None)");
let edit = Edit::range_replacement(replacement, stmt.range);
let comment_ranges = checker.comment_ranges();
let applicability = if comment_ranges.intersects(stmt.range) {
Applicability::Unsafe
} else {
Applicability::Safe
};
Fix::applicable_edit(edit, applicability)
}

View file

@ -7,6 +7,7 @@ pub(crate) use decimal_from_float_literal::*;
pub(crate) use default_factory_kwarg::*;
pub(crate) use explicit_f_string_type_conversion::*;
pub(crate) use function_call_in_dataclass_default::*;
pub(crate) use if_key_in_dict_del::*;
pub(crate) use implicit_optional::*;
pub(crate) use incorrectly_parenthesized_tuple_in_subscript::*;
pub(crate) use invalid_assert_message_literal_argument::*;
@ -54,6 +55,7 @@ mod default_factory_kwarg;
mod explicit_f_string_type_conversion;
mod function_call_in_dataclass_default;
mod helpers;
mod if_key_in_dict_del;
mod implicit_optional;
mod incorrectly_parenthesized_tuple_in_subscript;
mod invalid_assert_message_literal_argument;

View file

@ -0,0 +1,600 @@
---
source: crates/ruff_linter/src/rules/ruff/mod.rs
snapshot_kind: text
---
RUF051.py:8:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
7 | if k in d: # Bare name
8 | del d[k]
| ^^^^^^^^ RUF051
9 |
10 | if '' in d: # String
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
4 4 |
5 5 | ### Errors
6 6 |
7 |-if k in d: # Bare name
8 |- del d[k]
7 |+d.pop(k, None)
9 8 |
10 9 | if '' in d: # String
11 10 | del d[""] # Different quotes
RUF051.py:11:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
10 | if '' in d: # String
11 | del d[""] # Different quotes
| ^^^^^^^^^ RUF051
12 |
13 | if b"" in d: # Bytes
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
7 7 | if k in d: # Bare name
8 8 | del d[k]
9 9 |
10 |-if '' in d: # String
11 |- del d[""] # Different quotes
10 |+d.pop('', None) # Different quotes
12 11 |
13 12 | if b"" in d: # Bytes
14 13 | del d[ # Multiline slice
RUF051.py:14:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
13 | if b"" in d: # Bytes
14 | del d[ # Multiline slice
| _____^
15 | | b'''''' # Triple quotes
16 | | ]
| |_____^ RUF051
17 |
18 | if 0 in d: del d[0] # Single-line statement
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
10 10 | if '' in d: # String
11 11 | del d[""] # Different quotes
12 12 |
13 |-if b"" in d: # Bytes
14 |- del d[ # Multiline slice
15 |- b'''''' # Triple quotes
16 |- ]
13 |+d.pop(b"", None)
17 14 |
18 15 | if 0 in d: del d[0] # Single-line statement
19 16 |
RUF051.py:18:12: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
16 | ]
17 |
18 | if 0 in d: del d[0] # Single-line statement
| ^^^^^^^^ RUF051
19 |
20 | if 3j in d: # Complex
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
15 15 | b'''''' # Triple quotes
16 16 | ]
17 17 |
18 |-if 0 in d: del d[0] # Single-line statement
18 |+d.pop(0, None) # Single-line statement
19 19 |
20 20 | if 3j in d: # Complex
21 21 | del d[3j]
RUF051.py:21:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
20 | if 3j in d: # Complex
21 | del d[3j]
| ^^^^^^^^^ RUF051
22 |
23 | if 0.1234 in d: # Float
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
17 17 |
18 18 | if 0 in d: del d[0] # Single-line statement
19 19 |
20 |-if 3j in d: # Complex
21 |- del d[3j]
20 |+d.pop(3j, None)
22 21 |
23 22 | if 0.1234 in d: # Float
24 23 | del d[.1_2_3_4] # Number separators and shorthand syntax
RUF051.py:24:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
23 | if 0.1234 in d: # Float
24 | del d[.1_2_3_4] # Number separators and shorthand syntax
| ^^^^^^^^^^^^^^^ RUF051
25 |
26 | if True in d: # True
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
20 20 | if 3j in d: # Complex
21 21 | del d[3j]
22 22 |
23 |-if 0.1234 in d: # Float
24 |- del d[.1_2_3_4] # Number separators and shorthand syntax
23 |+d.pop(0.1234, None) # Number separators and shorthand syntax
25 24 |
26 25 | if True in d: # True
27 26 | del d[True]
RUF051.py:27:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
26 | if True in d: # True
27 | del d[True]
| ^^^^^^^^^^^ RUF051
28 |
29 | if False in d: # False
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
23 23 | if 0.1234 in d: # Float
24 24 | del d[.1_2_3_4] # Number separators and shorthand syntax
25 25 |
26 |-if True in d: # True
27 |- del d[True]
26 |+d.pop(True, None)
28 27 |
29 28 | if False in d: # False
30 29 | del d[False]
RUF051.py:30:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
29 | if False in d: # False
30 | del d[False]
| ^^^^^^^^^^^^ RUF051
31 |
32 | if None in d: # None
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
26 26 | if True in d: # True
27 27 | del d[True]
28 28 |
29 |-if False in d: # False
30 |- del d[False]
29 |+d.pop(False, None)
31 30 |
32 31 | if None in d: # None
33 32 | del d[
RUF051.py:33:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
32 | if None in d: # None
33 | del d[
| _____^
34 | | # Comment in the middle
35 | | None
36 | | ]
| |_____^ RUF051
37 |
38 | if ... in d: # Ellipsis
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
29 29 | if False in d: # False
30 30 | del d[False]
31 31 |
32 |-if None in d: # None
33 |- del d[
34 |- # Comment in the middle
35 |- None
36 |- ]
32 |+d.pop(None, None)
37 33 |
38 34 | if ... in d: # Ellipsis
39 35 | del d[
RUF051.py:39:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
38 | if ... in d: # Ellipsis
39 | del d[
| _____^
40 | | # Comment in the middle, indented
41 | | ...]
| |____________^ RUF051
42 |
43 | if "a" "bc" in d: # String concatenation
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
35 35 | None
36 36 | ]
37 37 |
38 |-if ... in d: # Ellipsis
39 |- del d[
40 |- # Comment in the middle, indented
41 |- ...]
38 |+d.pop(..., None)
42 39 |
43 40 | if "a" "bc" in d: # String concatenation
44 41 | del d['abc']
RUF051.py:44:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
43 | if "a" "bc" in d: # String concatenation
44 | del d['abc']
| ^^^^^^^^^^^^ RUF051
45 |
46 | if r"\foo" in d: # Raw string
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
40 40 | # Comment in the middle, indented
41 41 | ...]
42 42 |
43 |-if "a" "bc" in d: # String concatenation
44 |- del d['abc']
43 |+d.pop("a" "bc", None)
45 44 |
46 45 | if r"\foo" in d: # Raw string
47 46 | del d['\\foo']
RUF051.py:47:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
46 | if r"\foo" in d: # Raw string
47 | del d['\\foo']
| ^^^^^^^^^^^^^^ RUF051
48 |
49 | if b'yt' b'es' in d: # Bytes concatenation
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
43 43 | if "a" "bc" in d: # String concatenation
44 44 | del d['abc']
45 45 |
46 |-if r"\foo" in d: # Raw string
47 |- del d['\\foo']
46 |+d.pop(r"\foo", None)
48 47 |
49 48 | if b'yt' b'es' in d: # Bytes concatenation
50 49 | del d[rb"""ytes"""] # Raw bytes
RUF051.py:50:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
49 | if b'yt' b'es' in d: # Bytes concatenation
50 | del d[rb"""ytes"""] # Raw bytes
| ^^^^^^^^^^^^^^^^^^^ RUF051
51 |
52 | if k in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
46 46 | if r"\foo" in d: # Raw string
47 47 | del d['\\foo']
48 48 |
49 |-if b'yt' b'es' in d: # Bytes concatenation
50 |- del d[rb"""ytes"""] # Raw bytes
49 |+d.pop(b'yt' b'es', None) # Raw bytes
51 50 |
52 51 | if k in d:
53 52 | # comment that gets dropped
RUF051.py:54:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
52 | if k in d:
53 | # comment that gets dropped
54 | del d[k]
| ^^^^^^^^ RUF051
55 |
56 | ### Safely fixable
|
= help: Replace `if` statement with `.pop(..., None)`
Unsafe fix
49 49 | if b'yt' b'es' in d: # Bytes concatenation
50 50 | del d[rb"""ytes"""] # Raw bytes
51 51 |
52 |-if k in d:
53 |- # comment that gets dropped
54 |- del d[k]
52 |+d.pop(k, None)
55 53 |
56 54 | ### Safely fixable
57 55 |
RUF051.py:59:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
58 | if k in d:
59 | del d[k]
| ^^^^^^^^ RUF051
60 |
61 | if '' in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
55 55 |
56 56 | ### Safely fixable
57 57 |
58 |-if k in d:
59 |- del d[k]
58 |+d.pop(k, None)
60 59 |
61 60 | if '' in d:
62 61 | del d[""]
RUF051.py:62:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
61 | if '' in d:
62 | del d[""]
| ^^^^^^^^^ RUF051
63 |
64 | if b"" in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
58 58 | if k in d:
59 59 | del d[k]
60 60 |
61 |-if '' in d:
62 |- del d[""]
61 |+d.pop('', None)
63 62 |
64 63 | if b"" in d:
65 64 | del d[
RUF051.py:65:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
64 | if b"" in d:
65 | del d[
| _____^
66 | | b''''''
67 | | ]
| |_____^ RUF051
68 |
69 | if 0 in d: del d[0]
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
61 61 | if '' in d:
62 62 | del d[""]
63 63 |
64 |-if b"" in d:
65 |- del d[
66 |- b''''''
67 |- ]
64 |+d.pop(b"", None)
68 65 |
69 66 | if 0 in d: del d[0]
70 67 |
RUF051.py:69:12: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
67 | ]
68 |
69 | if 0 in d: del d[0]
| ^^^^^^^^ RUF051
70 |
71 | if 3j in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
66 66 | b''''''
67 67 | ]
68 68 |
69 |-if 0 in d: del d[0]
69 |+d.pop(0, None)
70 70 |
71 71 | if 3j in d:
72 72 | del d[3j]
RUF051.py:72:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
71 | if 3j in d:
72 | del d[3j]
| ^^^^^^^^^ RUF051
73 |
74 | if 0.1234 in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
68 68 |
69 69 | if 0 in d: del d[0]
70 70 |
71 |-if 3j in d:
72 |- del d[3j]
71 |+d.pop(3j, None)
73 72 |
74 73 | if 0.1234 in d:
75 74 | del d[.1_2_3_4]
RUF051.py:75:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
74 | if 0.1234 in d:
75 | del d[.1_2_3_4]
| ^^^^^^^^^^^^^^^ RUF051
76 |
77 | if True in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
71 71 | if 3j in d:
72 72 | del d[3j]
73 73 |
74 |-if 0.1234 in d:
75 |- del d[.1_2_3_4]
74 |+d.pop(0.1234, None)
76 75 |
77 76 | if True in d:
78 77 | del d[True]
RUF051.py:78:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
77 | if True in d:
78 | del d[True]
| ^^^^^^^^^^^ RUF051
79 |
80 | if False in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
74 74 | if 0.1234 in d:
75 75 | del d[.1_2_3_4]
76 76 |
77 |-if True in d:
78 |- del d[True]
77 |+d.pop(True, None)
79 78 |
80 79 | if False in d:
81 80 | del d[False]
RUF051.py:81:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
80 | if False in d:
81 | del d[False]
| ^^^^^^^^^^^^ RUF051
82 |
83 | if None in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
77 77 | if True in d:
78 78 | del d[True]
79 79 |
80 |-if False in d:
81 |- del d[False]
80 |+d.pop(False, None)
82 81 |
83 82 | if None in d:
84 83 | del d[
RUF051.py:84:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
83 | if None in d:
84 | del d[
| _____^
85 | | None
86 | | ]
| |_____^ RUF051
87 |
88 | if ... in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
80 80 | if False in d:
81 81 | del d[False]
82 82 |
83 |-if None in d:
84 |- del d[
85 |- None
86 |- ]
83 |+d.pop(None, None)
87 84 |
88 85 | if ... in d:
89 86 | del d[
RUF051.py:89:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
88 | if ... in d:
89 | del d[
| _____^
90 | | ...]
| |____________^ RUF051
91 |
92 | if "a" "bc" in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
85 85 | None
86 86 | ]
87 87 |
88 |-if ... in d:
89 |- del d[
90 |- ...]
88 |+d.pop(..., None)
91 89 |
92 90 | if "a" "bc" in d:
93 91 | del d['abc']
RUF051.py:93:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
92 | if "a" "bc" in d:
93 | del d['abc']
| ^^^^^^^^^^^^ RUF051
94 |
95 | if r"\foo" in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
89 89 | del d[
90 90 | ...]
91 91 |
92 |-if "a" "bc" in d:
93 |- del d['abc']
92 |+d.pop("a" "bc", None)
94 93 |
95 94 | if r"\foo" in d:
96 95 | del d['\\foo']
RUF051.py:96:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
95 | if r"\foo" in d:
96 | del d['\\foo']
| ^^^^^^^^^^^^^^ RUF051
97 |
98 | if b'yt' b'es' in d:
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
92 92 | if "a" "bc" in d:
93 93 | del d['abc']
94 94 |
95 |-if r"\foo" in d:
96 |- del d['\\foo']
95 |+d.pop(r"\foo", None)
97 96 |
98 97 | if b'yt' b'es' in d:
99 98 | del d[rb"""ytes"""] # This should not make the fix unsafe
RUF051.py:99:5: RUF051 [*] Use `pop` instead of `key in dict` followed by `delete dict[key]`
|
98 | if b'yt' b'es' in d:
99 | del d[rb"""ytes"""] # This should not make the fix unsafe
| ^^^^^^^^^^^^^^^^^^^ RUF051
|
= help: Replace `if` statement with `.pop(..., None)`
Safe fix
95 95 | if r"\foo" in d:
96 96 | del d['\\foo']
97 97 |
98 |-if b'yt' b'es' in d:
99 |- del d[rb"""ytes"""] # This should not make the fix unsafe
98 |+d.pop(b'yt' b'es', None) # This should not make the fix unsafe
100 99 |
101 100 |
102 101 |

1
ruff.schema.json generated
View file

@ -3850,6 +3850,7 @@
"RUF046",
"RUF048",
"RUF05",
"RUF051",
"RUF052",
"RUF055",
"RUF1",