mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-28 21:05:08 +00:00
[pylint]
Implement len-test
(PLC1802
) (#14309)
## Summary This PR implements [`use-implicit-booleaness-not-len` / `C1802`](https://pylint.pycqa.org/en/latest/user_guide/messages/convention/use-implicit-booleaness-not-len.html) > For sequences, (strings, lists, tuples), use the fact that empty sequences are false. --------- Co-authored-by: xbrtnik1 <524841@mail.muni.cz> Co-authored-by: xbrtnik1 <xbrtnik1@mail.muni.cz>
This commit is contained in:
parent
9f446faa6c
commit
82c01aa662
8 changed files with 871 additions and 0 deletions
234
crates/ruff_linter/resources/test/fixtures/pylint/len_as_condition.py
vendored
Normal file
234
crates/ruff_linter/resources/test/fixtures/pylint/len_as_condition.py
vendored
Normal file
|
@ -0,0 +1,234 @@
|
|||
if len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
if not len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
z = []
|
||||
if z and len(['T', 'E', 'S', 'T']): # [PLC1802]
|
||||
pass
|
||||
|
||||
if True or len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
if len('TEST') == 0: # Should be fine
|
||||
pass
|
||||
|
||||
if len('TEST') < 1: # Should be fine
|
||||
pass
|
||||
|
||||
if len('TEST') <= 0: # Should be fine
|
||||
pass
|
||||
|
||||
if 1 > len('TEST'): # Should be fine
|
||||
pass
|
||||
|
||||
if 0 >= len('TEST'): # Should be fine
|
||||
pass
|
||||
|
||||
if z and len('TEST') == 0: # Should be fine
|
||||
pass
|
||||
|
||||
if 0 == len('TEST') < 10: # Should be fine
|
||||
pass
|
||||
|
||||
# Should be fine
|
||||
if 0 < 1 <= len('TEST') < 10: # [comparison-of-constants]
|
||||
pass
|
||||
|
||||
if 10 > len('TEST') != 0: # Should be fine
|
||||
pass
|
||||
|
||||
if 10 > len('TEST') > 1 > 0: # Should be fine
|
||||
pass
|
||||
|
||||
if 0 <= len('TEST') < 100: # Should be fine
|
||||
pass
|
||||
|
||||
if z or 10 > len('TEST') != 0: # Should be fine
|
||||
pass
|
||||
|
||||
if z:
|
||||
pass
|
||||
elif len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
if z:
|
||||
pass
|
||||
elif not len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
while len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
while not len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
while z and len('TEST'): # [PLC1802]
|
||||
pass
|
||||
|
||||
while not len('TEST') and z: # [PLC1802]
|
||||
pass
|
||||
|
||||
assert len('TEST') > 0 # Should be fine
|
||||
|
||||
x = 1 if len('TEST') != 0 else 2 # Should be fine
|
||||
|
||||
f_o_o = len('TEST') or 42 # Should be fine
|
||||
|
||||
a = x and len(x) # Should be fine
|
||||
|
||||
def some_func():
|
||||
return len('TEST') > 0 # Should be fine
|
||||
|
||||
def github_issue_1325():
|
||||
l = [1, 2, 3]
|
||||
length = len(l) if l else 0 # Should be fine
|
||||
return length
|
||||
|
||||
def github_issue_1331(*args):
|
||||
assert False, len(args) # Should be fine
|
||||
|
||||
def github_issue_1331_v2(*args):
|
||||
assert len(args), args # [PLC1802]
|
||||
|
||||
def github_issue_1331_v3(*args):
|
||||
assert len(args) or z, args # [PLC1802]
|
||||
|
||||
def github_issue_1331_v4(*args):
|
||||
assert z and len(args), args # [PLC1802]
|
||||
|
||||
def github_issue_1331_v5(**args):
|
||||
assert z and len(args), args # [PLC1802]
|
||||
|
||||
b = bool(len(z)) # [PLC1802]
|
||||
c = bool(len('TEST') or 42) # [PLC1802]
|
||||
|
||||
def github_issue_1879():
|
||||
|
||||
class ClassWithBool(list):
|
||||
def __bool__(self):
|
||||
return True
|
||||
|
||||
class ClassWithoutBool(list):
|
||||
pass
|
||||
|
||||
class ChildClassWithBool(ClassWithBool):
|
||||
pass
|
||||
|
||||
class ChildClassWithoutBool(ClassWithoutBool):
|
||||
pass
|
||||
|
||||
assert len(ClassWithBool())
|
||||
assert len(ChildClassWithBool())
|
||||
assert len(ClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
assert len(ChildClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
assert len(range(0)) # [PLC1802]
|
||||
assert len([t + 1 for t in []]) # [PLC1802]
|
||||
# assert len(u + 1 for u in []) generator has no len
|
||||
assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
assert len(set((w + 1) for w in set())) # [PLC1802]
|
||||
|
||||
|
||||
import numpy
|
||||
numpy_array = numpy.array([0])
|
||||
if len(numpy_array) > 0:
|
||||
print('numpy_array')
|
||||
if len(numpy_array):
|
||||
print('numpy_array')
|
||||
if numpy_array:
|
||||
print('b')
|
||||
|
||||
import pandas as pd
|
||||
pandas_df = pd.DataFrame()
|
||||
if len(pandas_df):
|
||||
print("this works, but pylint tells me not to use len() without comparison")
|
||||
if len(pandas_df) > 0:
|
||||
print("this works and pylint likes it, but it's not the solution intended by PEP-8")
|
||||
if pandas_df:
|
||||
print("this does not work (truth value of dataframe is ambiguous)")
|
||||
|
||||
def function_returning_list(r):
|
||||
if r==1:
|
||||
return [1]
|
||||
return [2]
|
||||
|
||||
def function_returning_int(r):
|
||||
if r==1:
|
||||
return 1
|
||||
return 2
|
||||
|
||||
def function_returning_generator(r):
|
||||
for i in [r, 1, 2, 3]:
|
||||
yield i
|
||||
|
||||
def function_returning_comprehension(r):
|
||||
return [x+1 for x in [r, 1, 2, 3]]
|
||||
|
||||
def function_returning_function(r):
|
||||
return function_returning_generator(r)
|
||||
|
||||
assert len(function_returning_list(z)) # [PLC1802] differs from pylint
|
||||
assert len(function_returning_int(z))
|
||||
# This should raise a PLC1802 once astroid can infer it
|
||||
# See https://github.com/pylint-dev/pylint/pull/3821#issuecomment-743771514
|
||||
assert len(function_returning_generator(z))
|
||||
assert len(function_returning_comprehension(z))
|
||||
assert len(function_returning_function(z))
|
||||
|
||||
|
||||
def github_issue_4215():
|
||||
# Test undefined variables
|
||||
# https://github.com/pylint-dev/pylint/issues/4215
|
||||
if len(undefined_var): # [undefined-variable]
|
||||
pass
|
||||
if len(undefined_var2[0]): # [undefined-variable]
|
||||
pass
|
||||
|
||||
|
||||
def f(cond:bool):
|
||||
x = [1,2,3]
|
||||
if cond:
|
||||
x = [4,5,6]
|
||||
if len(x): # this should be addressed
|
||||
print(x)
|
||||
|
||||
def g(cond:bool):
|
||||
x = [1,2,3]
|
||||
if cond:
|
||||
x = [4,5,6]
|
||||
if len(x): # this should be addressed
|
||||
print(x)
|
||||
del x
|
||||
|
||||
def h(cond:bool):
|
||||
x = [1,2,3]
|
||||
x = 123
|
||||
if len(x): # ok
|
||||
print(x)
|
||||
|
||||
def outer():
|
||||
x = [1,2,3]
|
||||
def inner(x:int):
|
||||
return x+1
|
||||
if len(x): # [PLC1802]
|
||||
print(x)
|
||||
|
||||
def redefined():
|
||||
x = 123
|
||||
x = [1, 2, 3]
|
||||
if len(x): # this should be addressed
|
||||
print(x)
|
||||
|
||||
global_seq = [1, 2, 3]
|
||||
|
||||
def i():
|
||||
global global_seq
|
||||
if len(global_seq): # ok
|
||||
print(global_seq)
|
||||
|
||||
def j():
|
||||
if False:
|
||||
x = [1, 2, 3]
|
||||
if len(x): # [PLC1802] should be fine
|
||||
print(x)
|
|
@ -494,6 +494,9 @@ pub(crate) fn expression(expr: &Expr, checker: &mut Checker) {
|
|||
if checker.enabled(Rule::SuperWithoutBrackets) {
|
||||
pylint::rules::super_without_brackets(checker, func);
|
||||
}
|
||||
if checker.enabled(Rule::LenTest) {
|
||||
pylint::rules::len_test(checker, call);
|
||||
}
|
||||
if checker.enabled(Rule::BitCount) {
|
||||
refurb::rules::bit_count(checker, call);
|
||||
}
|
||||
|
|
|
@ -192,6 +192,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {
|
|||
(Pylint, "C0208") => (RuleGroup::Stable, rules::pylint::rules::IterationOverSet),
|
||||
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
|
||||
(Pylint, "C0415") => (RuleGroup::Preview, rules::pylint::rules::ImportOutsideTopLevel),
|
||||
(Pylint, "C1802") => (RuleGroup::Preview, rules::pylint::rules::LenTest),
|
||||
(Pylint, "C1901") => (RuleGroup::Preview, rules::pylint::rules::CompareToEmptyString),
|
||||
(Pylint, "C2401") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiName),
|
||||
(Pylint, "C2403") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiImportName),
|
||||
|
|
|
@ -220,6 +220,7 @@ mod tests {
|
|||
Rule::BadStaticmethodArgument,
|
||||
Path::new("bad_staticmethod_argument.py")
|
||||
)]
|
||||
#[test_case(Rule::LenTest, Path::new("len_as_condition.py"))]
|
||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||
let diagnostics = test_path(
|
||||
|
|
191
crates/ruff_linter/src/rules/pylint/rules/len_test.rs
Normal file
191
crates/ruff_linter/src/rules/pylint/rules/len_test.rs
Normal file
|
@ -0,0 +1,191 @@
|
|||
use crate::checkers::ast::Checker;
|
||||
use crate::fix::snippet::SourceCodeSnippet;
|
||||
use ruff_diagnostics::{AlwaysFixableViolation, Diagnostic, Edit, Fix};
|
||||
use ruff_macros::{derive_message_formats, violation};
|
||||
use ruff_python_ast::{self as ast, Expr, ExprCall};
|
||||
use ruff_python_semantic::analyze::type_inference::{PythonType, ResolvedPythonType};
|
||||
use ruff_python_semantic::analyze::typing::find_binding_value;
|
||||
use ruff_python_semantic::{BindingId, SemanticModel};
|
||||
use ruff_text_size::Ranged;
|
||||
|
||||
/// ## What it does
|
||||
/// Checks for usage of call of 'len' on sequences
|
||||
/// in boolean test context.
|
||||
///
|
||||
/// ## Why is this bad?
|
||||
/// Empty sequences are considered false in a boolean context.
|
||||
/// You can either remove the call to 'len'
|
||||
/// or compare the length against a scalar.
|
||||
///
|
||||
/// ## Example
|
||||
/// ```python
|
||||
/// fruits = ["orange", "apple"]
|
||||
/// vegetables = []
|
||||
///
|
||||
/// if len(fruits):
|
||||
/// print(fruits)
|
||||
///
|
||||
/// if not len(vegetables):
|
||||
/// print(vegetables)
|
||||
/// ```
|
||||
///
|
||||
/// Use instead:
|
||||
/// ```python
|
||||
/// fruits = ["orange", "apple"]
|
||||
///
|
||||
/// if fruits:
|
||||
/// print(fruits)
|
||||
///
|
||||
/// if not vegetables:
|
||||
/// print(vegetables)
|
||||
/// ```
|
||||
///
|
||||
/// ## References
|
||||
/// [PEP 8: Programming Recommendations](https://peps.python.org/pep-0008/#programming-recommendations)
|
||||
#[violation]
|
||||
pub struct LenTest {
|
||||
expression: SourceCodeSnippet,
|
||||
}
|
||||
|
||||
impl AlwaysFixableViolation for LenTest {
|
||||
#[derive_message_formats]
|
||||
fn message(&self) -> String {
|
||||
if let Some(expression) = self.expression.full_display() {
|
||||
format!("`len({expression})` used as condition without comparison")
|
||||
} else {
|
||||
"`len(SEQUENCE)` used as condition without comparison".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_title(&self) -> String {
|
||||
"Remove `len`".to_string()
|
||||
}
|
||||
}
|
||||
|
||||
/// PLC1802
|
||||
pub(crate) fn len_test(checker: &mut Checker, call: &ExprCall) {
|
||||
let ExprCall {
|
||||
func, arguments, ..
|
||||
} = call;
|
||||
let semantic = checker.semantic();
|
||||
|
||||
if !semantic.in_boolean_test() {
|
||||
return;
|
||||
}
|
||||
|
||||
if !semantic.match_builtin_expr(func, "len") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Single argument and no keyword arguments
|
||||
let [argument] = &*arguments.args else { return };
|
||||
if !arguments.keywords.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// Simple inferred sequence type (e.g., list, set, dict, tuple, string, bytes, varargs, kwargs).
|
||||
if !is_sequence(argument, semantic) && !is_indirect_sequence(argument, semantic) {
|
||||
return;
|
||||
}
|
||||
|
||||
let replacement = checker.locator().slice(argument.range()).to_string();
|
||||
|
||||
checker.diagnostics.push(
|
||||
Diagnostic::new(
|
||||
LenTest {
|
||||
expression: SourceCodeSnippet::new(replacement.clone()),
|
||||
},
|
||||
call.range(),
|
||||
)
|
||||
.with_fix(Fix::safe_edit(Edit::range_replacement(
|
||||
replacement,
|
||||
call.range(),
|
||||
))),
|
||||
);
|
||||
}
|
||||
|
||||
fn is_indirect_sequence(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||
let Expr::Name(ast::ExprName { id: name, .. }) = expr else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let scope = semantic.current_scope();
|
||||
let bindings: Vec<BindingId> = scope.get_all(name).collect();
|
||||
let [binding_id] = bindings.as_slice() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let binding = semantic.binding(*binding_id);
|
||||
|
||||
// Attempt to find the binding's value
|
||||
let Some(binding_value) = find_binding_value(binding, semantic) else {
|
||||
// If the binding is not an argument, return false
|
||||
if !binding.kind.is_argument() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Attempt to retrieve the function definition statement
|
||||
let Some(function) = binding
|
||||
.statement(semantic)
|
||||
.and_then(|statement| statement.as_function_def_stmt())
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// If not find in non-default params, it must be varargs or kwargs
|
||||
return function.parameters.find(name).is_none();
|
||||
};
|
||||
|
||||
// If `binding_value` is found, check if it is a sequence
|
||||
is_sequence(binding_value, semantic)
|
||||
}
|
||||
|
||||
fn is_sequence(expr: &Expr, semantic: &SemanticModel) -> bool {
|
||||
// Check if the expression type is a direct sequence match (dict, list, set, tuple, string or bytes)
|
||||
if matches!(
|
||||
ResolvedPythonType::from(expr),
|
||||
ResolvedPythonType::Atom(
|
||||
PythonType::Dict
|
||||
| PythonType::List
|
||||
| PythonType::Set
|
||||
| PythonType::Tuple
|
||||
| PythonType::String
|
||||
| PythonType::Bytes
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if the expression is a function call to a built-in sequence constructor
|
||||
let Some(ExprCall { func, .. }) = expr.as_call_expr() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// Match against specific built-in constructors that return sequences
|
||||
return semantic.resolve_builtin_symbol(func).is_some_and(|func| {
|
||||
matches!(
|
||||
func,
|
||||
"chr"
|
||||
| "format"
|
||||
| "input"
|
||||
| "repr"
|
||||
| "str"
|
||||
| "list"
|
||||
| "dir"
|
||||
| "locals"
|
||||
| "globals"
|
||||
| "vars"
|
||||
| "dict"
|
||||
| "set"
|
||||
| "frozenset"
|
||||
| "tuple"
|
||||
| "range"
|
||||
| "bin"
|
||||
| "bytes"
|
||||
| "bytearray"
|
||||
| "hex"
|
||||
| "memoryview"
|
||||
| "oct"
|
||||
)
|
||||
});
|
||||
}
|
|
@ -39,6 +39,7 @@ pub(crate) use invalid_length_return::*;
|
|||
pub(crate) use invalid_str_return::*;
|
||||
pub(crate) use invalid_string_characters::*;
|
||||
pub(crate) use iteration_over_set::*;
|
||||
pub(crate) use len_test::*;
|
||||
pub(crate) use literal_membership::*;
|
||||
pub(crate) use load_before_global_declaration::*;
|
||||
pub(crate) use logging::*;
|
||||
|
@ -144,6 +145,7 @@ mod invalid_length_return;
|
|||
mod invalid_str_return;
|
||||
mod invalid_string_characters;
|
||||
mod iteration_over_set;
|
||||
mod len_test;
|
||||
mod literal_membership;
|
||||
mod load_before_global_declaration;
|
||||
mod logging;
|
||||
|
|
|
@ -0,0 +1,436 @@
|
|||
---
|
||||
source: crates/ruff_linter/src/rules/pylint/mod.rs
|
||||
snapshot_kind: text
|
||||
---
|
||||
len_as_condition.py:1:4: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
1 | if len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
2 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
1 |-if len('TEST'): # [PLC1802]
|
||||
1 |+if 'TEST': # [PLC1802]
|
||||
2 2 | pass
|
||||
3 3 |
|
||||
4 4 | if not len('TEST'): # [PLC1802]
|
||||
|
||||
len_as_condition.py:4:8: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
2 | pass
|
||||
3 |
|
||||
4 | if not len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
5 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
1 1 | if len('TEST'): # [PLC1802]
|
||||
2 2 | pass
|
||||
3 3 |
|
||||
4 |-if not len('TEST'): # [PLC1802]
|
||||
4 |+if not 'TEST': # [PLC1802]
|
||||
5 5 | pass
|
||||
6 6 |
|
||||
7 7 | z = []
|
||||
|
||||
len_as_condition.py:8:10: PLC1802 [*] `len(['T', 'E', 'S', 'T'])` used as condition without comparison
|
||||
|
|
||||
7 | z = []
|
||||
8 | if z and len(['T', 'E', 'S', 'T']): # [PLC1802]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ PLC1802
|
||||
9 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
5 5 | pass
|
||||
6 6 |
|
||||
7 7 | z = []
|
||||
8 |-if z and len(['T', 'E', 'S', 'T']): # [PLC1802]
|
||||
8 |+if z and ['T', 'E', 'S', 'T']: # [PLC1802]
|
||||
9 9 | pass
|
||||
10 10 |
|
||||
11 11 | if True or len('TEST'): # [PLC1802]
|
||||
|
||||
len_as_condition.py:11:12: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
9 | pass
|
||||
10 |
|
||||
11 | if True or len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
12 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
8 8 | if z and len(['T', 'E', 'S', 'T']): # [PLC1802]
|
||||
9 9 | pass
|
||||
10 10 |
|
||||
11 |-if True or len('TEST'): # [PLC1802]
|
||||
11 |+if True or 'TEST': # [PLC1802]
|
||||
12 12 | pass
|
||||
13 13 |
|
||||
14 14 | if len('TEST') == 0: # Should be fine
|
||||
|
||||
len_as_condition.py:53:6: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
51 | if z:
|
||||
52 | pass
|
||||
53 | elif len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
54 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
50 50 |
|
||||
51 51 | if z:
|
||||
52 52 | pass
|
||||
53 |-elif len('TEST'): # [PLC1802]
|
||||
53 |+elif 'TEST': # [PLC1802]
|
||||
54 54 | pass
|
||||
55 55 |
|
||||
56 56 | if z:
|
||||
|
||||
len_as_condition.py:58:10: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
56 | if z:
|
||||
57 | pass
|
||||
58 | elif not len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
59 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
55 55 |
|
||||
56 56 | if z:
|
||||
57 57 | pass
|
||||
58 |-elif not len('TEST'): # [PLC1802]
|
||||
58 |+elif not 'TEST': # [PLC1802]
|
||||
59 59 | pass
|
||||
60 60 |
|
||||
61 61 | while len('TEST'): # [PLC1802]
|
||||
|
||||
len_as_condition.py:61:7: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
59 | pass
|
||||
60 |
|
||||
61 | while len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
62 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
58 58 | elif not len('TEST'): # [PLC1802]
|
||||
59 59 | pass
|
||||
60 60 |
|
||||
61 |-while len('TEST'): # [PLC1802]
|
||||
61 |+while 'TEST': # [PLC1802]
|
||||
62 62 | pass
|
||||
63 63 |
|
||||
64 64 | while not len('TEST'): # [PLC1802]
|
||||
|
||||
len_as_condition.py:64:11: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
62 | pass
|
||||
63 |
|
||||
64 | while not len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
65 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
61 61 | while len('TEST'): # [PLC1802]
|
||||
62 62 | pass
|
||||
63 63 |
|
||||
64 |-while not len('TEST'): # [PLC1802]
|
||||
64 |+while not 'TEST': # [PLC1802]
|
||||
65 65 | pass
|
||||
66 66 |
|
||||
67 67 | while z and len('TEST'): # [PLC1802]
|
||||
|
||||
len_as_condition.py:67:13: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
65 | pass
|
||||
66 |
|
||||
67 | while z and len('TEST'): # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
68 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
64 64 | while not len('TEST'): # [PLC1802]
|
||||
65 65 | pass
|
||||
66 66 |
|
||||
67 |-while z and len('TEST'): # [PLC1802]
|
||||
67 |+while z and 'TEST': # [PLC1802]
|
||||
68 68 | pass
|
||||
69 69 |
|
||||
70 70 | while not len('TEST') and z: # [PLC1802]
|
||||
|
||||
len_as_condition.py:70:11: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
68 | pass
|
||||
69 |
|
||||
70 | while not len('TEST') and z: # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
71 | pass
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
67 67 | while z and len('TEST'): # [PLC1802]
|
||||
68 68 | pass
|
||||
69 69 |
|
||||
70 |-while not len('TEST') and z: # [PLC1802]
|
||||
70 |+while not 'TEST' and z: # [PLC1802]
|
||||
71 71 | pass
|
||||
72 72 |
|
||||
73 73 | assert len('TEST') > 0 # Should be fine
|
||||
|
||||
len_as_condition.py:93:12: PLC1802 [*] `len(args)` used as condition without comparison
|
||||
|
|
||||
92 | def github_issue_1331_v2(*args):
|
||||
93 | assert len(args), args # [PLC1802]
|
||||
| ^^^^^^^^^ PLC1802
|
||||
94 |
|
||||
95 | def github_issue_1331_v3(*args):
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
90 90 | assert False, len(args) # Should be fine
|
||||
91 91 |
|
||||
92 92 | def github_issue_1331_v2(*args):
|
||||
93 |- assert len(args), args # [PLC1802]
|
||||
93 |+ assert args, args # [PLC1802]
|
||||
94 94 |
|
||||
95 95 | def github_issue_1331_v3(*args):
|
||||
96 96 | assert len(args) or z, args # [PLC1802]
|
||||
|
||||
len_as_condition.py:96:12: PLC1802 [*] `len(args)` used as condition without comparison
|
||||
|
|
||||
95 | def github_issue_1331_v3(*args):
|
||||
96 | assert len(args) or z, args # [PLC1802]
|
||||
| ^^^^^^^^^ PLC1802
|
||||
97 |
|
||||
98 | def github_issue_1331_v4(*args):
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
93 93 | assert len(args), args # [PLC1802]
|
||||
94 94 |
|
||||
95 95 | def github_issue_1331_v3(*args):
|
||||
96 |- assert len(args) or z, args # [PLC1802]
|
||||
96 |+ assert args or z, args # [PLC1802]
|
||||
97 97 |
|
||||
98 98 | def github_issue_1331_v4(*args):
|
||||
99 99 | assert z and len(args), args # [PLC1802]
|
||||
|
||||
len_as_condition.py:99:18: PLC1802 [*] `len(args)` used as condition without comparison
|
||||
|
|
||||
98 | def github_issue_1331_v4(*args):
|
||||
99 | assert z and len(args), args # [PLC1802]
|
||||
| ^^^^^^^^^ PLC1802
|
||||
100 |
|
||||
101 | def github_issue_1331_v5(**args):
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
96 96 | assert len(args) or z, args # [PLC1802]
|
||||
97 97 |
|
||||
98 98 | def github_issue_1331_v4(*args):
|
||||
99 |- assert z and len(args), args # [PLC1802]
|
||||
99 |+ assert z and args, args # [PLC1802]
|
||||
100 100 |
|
||||
101 101 | def github_issue_1331_v5(**args):
|
||||
102 102 | assert z and len(args), args # [PLC1802]
|
||||
|
||||
len_as_condition.py:102:18: PLC1802 [*] `len(args)` used as condition without comparison
|
||||
|
|
||||
101 | def github_issue_1331_v5(**args):
|
||||
102 | assert z and len(args), args # [PLC1802]
|
||||
| ^^^^^^^^^ PLC1802
|
||||
103 |
|
||||
104 | b = bool(len(z)) # [PLC1802]
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
99 99 | assert z and len(args), args # [PLC1802]
|
||||
100 100 |
|
||||
101 101 | def github_issue_1331_v5(**args):
|
||||
102 |- assert z and len(args), args # [PLC1802]
|
||||
102 |+ assert z and args, args # [PLC1802]
|
||||
103 103 |
|
||||
104 104 | b = bool(len(z)) # [PLC1802]
|
||||
105 105 | c = bool(len('TEST') or 42) # [PLC1802]
|
||||
|
||||
len_as_condition.py:104:10: PLC1802 [*] `len(z)` used as condition without comparison
|
||||
|
|
||||
102 | assert z and len(args), args # [PLC1802]
|
||||
103 |
|
||||
104 | b = bool(len(z)) # [PLC1802]
|
||||
| ^^^^^^ PLC1802
|
||||
105 | c = bool(len('TEST') or 42) # [PLC1802]
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
101 101 | def github_issue_1331_v5(**args):
|
||||
102 102 | assert z and len(args), args # [PLC1802]
|
||||
103 103 |
|
||||
104 |-b = bool(len(z)) # [PLC1802]
|
||||
104 |+b = bool(z) # [PLC1802]
|
||||
105 105 | c = bool(len('TEST') or 42) # [PLC1802]
|
||||
106 106 |
|
||||
107 107 | def github_issue_1879():
|
||||
|
||||
len_as_condition.py:105:10: PLC1802 [*] `len('TEST')` used as condition without comparison
|
||||
|
|
||||
104 | b = bool(len(z)) # [PLC1802]
|
||||
105 | c = bool(len('TEST') or 42) # [PLC1802]
|
||||
| ^^^^^^^^^^^ PLC1802
|
||||
106 |
|
||||
107 | def github_issue_1879():
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
102 102 | assert z and len(args), args # [PLC1802]
|
||||
103 103 |
|
||||
104 104 | b = bool(len(z)) # [PLC1802]
|
||||
105 |-c = bool(len('TEST') or 42) # [PLC1802]
|
||||
105 |+c = bool('TEST' or 42) # [PLC1802]
|
||||
106 106 |
|
||||
107 107 | def github_issue_1879():
|
||||
108 108 |
|
||||
|
||||
len_as_condition.py:126:12: PLC1802 [*] `len(range(0))` used as condition without comparison
|
||||
|
|
||||
124 | assert len(ClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
125 | assert len(ChildClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
126 | assert len(range(0)) # [PLC1802]
|
||||
| ^^^^^^^^^^^^^ PLC1802
|
||||
127 | assert len([t + 1 for t in []]) # [PLC1802]
|
||||
128 | # assert len(u + 1 for u in []) generator has no len
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
123 123 | assert len(ChildClassWithBool())
|
||||
124 124 | assert len(ClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
125 125 | assert len(ChildClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
126 |- assert len(range(0)) # [PLC1802]
|
||||
126 |+ assert range(0) # [PLC1802]
|
||||
127 127 | assert len([t + 1 for t in []]) # [PLC1802]
|
||||
128 128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 129 | assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
|
||||
len_as_condition.py:127:12: PLC1802 [*] `len([t + 1 for t in []])` used as condition without comparison
|
||||
|
|
||||
125 | assert len(ChildClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
126 | assert len(range(0)) # [PLC1802]
|
||||
127 | assert len([t + 1 for t in []]) # [PLC1802]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ PLC1802
|
||||
128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 | assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
124 124 | assert len(ClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
125 125 | assert len(ChildClassWithoutBool()) # unintuitive?, in pylint: [PLC1802]
|
||||
126 126 | assert len(range(0)) # [PLC1802]
|
||||
127 |- assert len([t + 1 for t in []]) # [PLC1802]
|
||||
127 |+ assert [t + 1 for t in []] # [PLC1802]
|
||||
128 128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 129 | assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
130 130 | assert len(set((w + 1) for w in set())) # [PLC1802]
|
||||
|
||||
len_as_condition.py:129:12: PLC1802 [*] `len({"1":(v + 1) for v in {}})` used as condition without comparison
|
||||
|
|
||||
127 | assert len([t + 1 for t in []]) # [PLC1802]
|
||||
128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 | assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLC1802
|
||||
130 | assert len(set((w + 1) for w in set())) # [PLC1802]
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
126 126 | assert len(range(0)) # [PLC1802]
|
||||
127 127 | assert len([t + 1 for t in []]) # [PLC1802]
|
||||
128 128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 |- assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
129 |+ assert {"1":(v + 1) for v in {}} # [PLC1802]
|
||||
130 130 | assert len(set((w + 1) for w in set())) # [PLC1802]
|
||||
131 131 |
|
||||
132 132 |
|
||||
|
||||
len_as_condition.py:130:12: PLC1802 [*] `len(set((w + 1) for w in set()))` used as condition without comparison
|
||||
|
|
||||
128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 | assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
130 | assert len(set((w + 1) for w in set())) # [PLC1802]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ PLC1802
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
127 127 | assert len([t + 1 for t in []]) # [PLC1802]
|
||||
128 128 | # assert len(u + 1 for u in []) generator has no len
|
||||
129 129 | assert len({"1":(v + 1) for v in {}}) # [PLC1802]
|
||||
130 |- assert len(set((w + 1) for w in set())) # [PLC1802]
|
||||
130 |+ assert set((w + 1) for w in set()) # [PLC1802]
|
||||
131 131 |
|
||||
132 132 |
|
||||
133 133 | import numpy
|
||||
|
||||
len_as_condition.py:214:8: PLC1802 [*] `len(x)` used as condition without comparison
|
||||
|
|
||||
212 | def inner(x:int):
|
||||
213 | return x+1
|
||||
214 | if len(x): # [PLC1802]
|
||||
| ^^^^^^ PLC1802
|
||||
215 | print(x)
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
211 211 | x = [1,2,3]
|
||||
212 212 | def inner(x:int):
|
||||
213 213 | return x+1
|
||||
214 |- if len(x): # [PLC1802]
|
||||
214 |+ if x: # [PLC1802]
|
||||
215 215 | print(x)
|
||||
216 216 |
|
||||
217 217 | def redefined():
|
||||
|
||||
len_as_condition.py:233:8: PLC1802 [*] `len(x)` used as condition without comparison
|
||||
|
|
||||
231 | if False:
|
||||
232 | x = [1, 2, 3]
|
||||
233 | if len(x): # [PLC1802] should be fine
|
||||
| ^^^^^^ PLC1802
|
||||
234 | print(x)
|
||||
|
|
||||
= help: Remove `len`
|
||||
|
||||
ℹ Safe fix
|
||||
230 230 | def j():
|
||||
231 231 | if False:
|
||||
232 232 | x = [1, 2, 3]
|
||||
233 |- if len(x): # [PLC1802] should be fine
|
||||
233 |+ if x: # [PLC1802] should be fine
|
||||
234 234 | print(x)
|
3
ruff.schema.json
generated
3
ruff.schema.json
generated
|
@ -3425,6 +3425,9 @@
|
|||
"PLC0414",
|
||||
"PLC0415",
|
||||
"PLC1",
|
||||
"PLC18",
|
||||
"PLC180",
|
||||
"PLC1802",
|
||||
"PLC19",
|
||||
"PLC190",
|
||||
"PLC1901",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue