mirror of
https://github.com/astral-sh/ruff.git
synced 2025-09-29 05:15:12 +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) {
|
if checker.enabled(Rule::SuperWithoutBrackets) {
|
||||||
pylint::rules::super_without_brackets(checker, func);
|
pylint::rules::super_without_brackets(checker, func);
|
||||||
}
|
}
|
||||||
|
if checker.enabled(Rule::LenTest) {
|
||||||
|
pylint::rules::len_test(checker, call);
|
||||||
|
}
|
||||||
if checker.enabled(Rule::BitCount) {
|
if checker.enabled(Rule::BitCount) {
|
||||||
refurb::rules::bit_count(checker, call);
|
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, "C0208") => (RuleGroup::Stable, rules::pylint::rules::IterationOverSet),
|
||||||
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
|
(Pylint, "C0414") => (RuleGroup::Stable, rules::pylint::rules::UselessImportAlias),
|
||||||
(Pylint, "C0415") => (RuleGroup::Preview, rules::pylint::rules::ImportOutsideTopLevel),
|
(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, "C1901") => (RuleGroup::Preview, rules::pylint::rules::CompareToEmptyString),
|
||||||
(Pylint, "C2401") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiName),
|
(Pylint, "C2401") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiName),
|
||||||
(Pylint, "C2403") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiImportName),
|
(Pylint, "C2403") => (RuleGroup::Stable, rules::pylint::rules::NonAsciiImportName),
|
||||||
|
|
|
@ -220,6 +220,7 @@ mod tests {
|
||||||
Rule::BadStaticmethodArgument,
|
Rule::BadStaticmethodArgument,
|
||||||
Path::new("bad_staticmethod_argument.py")
|
Path::new("bad_staticmethod_argument.py")
|
||||||
)]
|
)]
|
||||||
|
#[test_case(Rule::LenTest, Path::new("len_as_condition.py"))]
|
||||||
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
|
||||||
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
|
||||||
let diagnostics = test_path(
|
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_str_return::*;
|
||||||
pub(crate) use invalid_string_characters::*;
|
pub(crate) use invalid_string_characters::*;
|
||||||
pub(crate) use iteration_over_set::*;
|
pub(crate) use iteration_over_set::*;
|
||||||
|
pub(crate) use len_test::*;
|
||||||
pub(crate) use literal_membership::*;
|
pub(crate) use literal_membership::*;
|
||||||
pub(crate) use load_before_global_declaration::*;
|
pub(crate) use load_before_global_declaration::*;
|
||||||
pub(crate) use logging::*;
|
pub(crate) use logging::*;
|
||||||
|
@ -144,6 +145,7 @@ mod invalid_length_return;
|
||||||
mod invalid_str_return;
|
mod invalid_str_return;
|
||||||
mod invalid_string_characters;
|
mod invalid_string_characters;
|
||||||
mod iteration_over_set;
|
mod iteration_over_set;
|
||||||
|
mod len_test;
|
||||||
mod literal_membership;
|
mod literal_membership;
|
||||||
mod load_before_global_declaration;
|
mod load_before_global_declaration;
|
||||||
mod logging;
|
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",
|
"PLC0414",
|
||||||
"PLC0415",
|
"PLC0415",
|
||||||
"PLC1",
|
"PLC1",
|
||||||
|
"PLC18",
|
||||||
|
"PLC180",
|
||||||
|
"PLC1802",
|
||||||
"PLC19",
|
"PLC19",
|
||||||
"PLC190",
|
"PLC190",
|
||||||
"PLC1901",
|
"PLC1901",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue