mirror of https://github.com/astral-sh/ruff
Redirect `PIE802` to `C419` (#3971)
This commit is contained in:
parent
289289bfd3
commit
c457752f36
|
|
@ -1,4 +1,3 @@
|
||||||
# PIE802
|
|
||||||
any([x.id for x in bar])
|
any([x.id for x in bar])
|
||||||
all([x.id for x in bar])
|
all([x.id for x in bar])
|
||||||
any( # first comment
|
any( # first comment
|
||||||
|
|
@ -15,5 +14,6 @@ all(x.id for x in bar)
|
||||||
any(x.id for x in bar)
|
any(x.id for x in bar)
|
||||||
all((x.id for x in bar))
|
all((x.id for x in bar))
|
||||||
|
|
||||||
|
|
||||||
async def f() -> bool:
|
async def f() -> bool:
|
||||||
return all([await use_greeting(greeting) for greeting in await greetings()])
|
return all([await use_greeting(greeting) for greeting in await greetings()])
|
||||||
|
|
@ -2585,13 +2585,6 @@ where
|
||||||
if self.settings.rules.enabled(Rule::UnnecessaryDictKwargs) {
|
if self.settings.rules.enabled(Rule::UnnecessaryDictKwargs) {
|
||||||
flake8_pie::rules::unnecessary_dict_kwargs(self, expr, keywords);
|
flake8_pie::rules::unnecessary_dict_kwargs(self, expr, keywords);
|
||||||
}
|
}
|
||||||
if self
|
|
||||||
.settings
|
|
||||||
.rules
|
|
||||||
.enabled(Rule::UnnecessaryComprehensionAnyAll)
|
|
||||||
{
|
|
||||||
flake8_pie::rules::unnecessary_comprehension_any_all(self, expr, func, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// flake8-bandit
|
// flake8-bandit
|
||||||
if self.settings.rules.enabled(Rule::ExecBuiltin) {
|
if self.settings.rules.enabled(Rule::ExecBuiltin) {
|
||||||
|
|
@ -2792,6 +2785,15 @@ where
|
||||||
args,
|
args,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if self
|
||||||
|
.settings
|
||||||
|
.rules
|
||||||
|
.enabled(Rule::UnnecessaryComprehensionAnyAll)
|
||||||
|
{
|
||||||
|
flake8_comprehensions::rules::unnecessary_comprehension_any_all(
|
||||||
|
self, expr, func, args, keywords,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// flake8-boolean-trap
|
// flake8-boolean-trap
|
||||||
if self
|
if self
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||||
(Flake8Comprehensions, "16") => Rule::UnnecessaryComprehension,
|
(Flake8Comprehensions, "16") => Rule::UnnecessaryComprehension,
|
||||||
(Flake8Comprehensions, "17") => Rule::UnnecessaryMap,
|
(Flake8Comprehensions, "17") => Rule::UnnecessaryMap,
|
||||||
(Flake8Comprehensions, "18") => Rule::UnnecessaryLiteralWithinDictCall,
|
(Flake8Comprehensions, "18") => Rule::UnnecessaryLiteralWithinDictCall,
|
||||||
|
(Flake8Comprehensions, "19") => Rule::UnnecessaryComprehensionAnyAll,
|
||||||
|
|
||||||
// flake8-debugger
|
// flake8-debugger
|
||||||
(Flake8Debugger, "0") => Rule::Debugger,
|
(Flake8Debugger, "0") => Rule::Debugger,
|
||||||
|
|
@ -617,7 +618,6 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<Rule> {
|
||||||
(Flake8Pie, "794") => Rule::DuplicateClassFieldDefinition,
|
(Flake8Pie, "794") => Rule::DuplicateClassFieldDefinition,
|
||||||
(Flake8Pie, "796") => Rule::NonUniqueEnums,
|
(Flake8Pie, "796") => Rule::NonUniqueEnums,
|
||||||
(Flake8Pie, "800") => Rule::UnnecessarySpread,
|
(Flake8Pie, "800") => Rule::UnnecessarySpread,
|
||||||
(Flake8Pie, "802") => Rule::UnnecessaryComprehensionAnyAll,
|
|
||||||
(Flake8Pie, "804") => Rule::UnnecessaryDictKwargs,
|
(Flake8Pie, "804") => Rule::UnnecessaryDictKwargs,
|
||||||
(Flake8Pie, "807") => Rule::ReimplementedListBuiltin,
|
(Flake8Pie, "807") => Rule::ReimplementedListBuiltin,
|
||||||
(Flake8Pie, "810") => Rule::MultipleStartsEndsWith,
|
(Flake8Pie, "810") => Rule::MultipleStartsEndsWith,
|
||||||
|
|
|
||||||
|
|
@ -228,23 +228,24 @@ ruff_macros::register_rules!(
|
||||||
// flake8-blind-except
|
// flake8-blind-except
|
||||||
rules::flake8_blind_except::rules::BlindExcept,
|
rules::flake8_blind_except::rules::BlindExcept,
|
||||||
// flake8-comprehensions
|
// flake8-comprehensions
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryCallAroundSorted,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryCollectionCall,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryComprehension,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryComprehensionAnyAll,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryDoubleCastOrProcess,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryGeneratorDict,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryGeneratorList,
|
rules::flake8_comprehensions::rules::UnnecessaryGeneratorList,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryGeneratorSet,
|
rules::flake8_comprehensions::rules::UnnecessaryGeneratorSet,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryGeneratorDict,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryListComprehensionSet,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryListComprehensionDict,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryLiteralSet,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryLiteralDict,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryCollectionCall,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinTupleCall,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinListCall,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryListCall,
|
rules::flake8_comprehensions::rules::UnnecessaryListCall,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryCallAroundSorted,
|
rules::flake8_comprehensions::rules::UnnecessaryListComprehensionDict,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryDoubleCastOrProcess,
|
rules::flake8_comprehensions::rules::UnnecessaryListComprehensionSet,
|
||||||
rules::flake8_comprehensions::rules::UnnecessarySubscriptReversal,
|
rules::flake8_comprehensions::rules::UnnecessaryLiteralDict,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryComprehension,
|
rules::flake8_comprehensions::rules::UnnecessaryLiteralSet,
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryMap,
|
|
||||||
rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinDictCall,
|
rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinDictCall,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinListCall,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryLiteralWithinTupleCall,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessaryMap,
|
||||||
|
rules::flake8_comprehensions::rules::UnnecessarySubscriptReversal,
|
||||||
// flake8-debugger
|
// flake8-debugger
|
||||||
rules::flake8_debugger::rules::Debugger,
|
rules::flake8_debugger::rules::Debugger,
|
||||||
// mccabe
|
// mccabe
|
||||||
|
|
@ -570,7 +571,6 @@ ruff_macros::register_rules!(
|
||||||
rules::flake8_pie::rules::UnnecessaryDictKwargs,
|
rules::flake8_pie::rules::UnnecessaryDictKwargs,
|
||||||
rules::flake8_pie::rules::ReimplementedListBuiltin,
|
rules::flake8_pie::rules::ReimplementedListBuiltin,
|
||||||
rules::flake8_pie::rules::MultipleStartsEndsWith,
|
rules::flake8_pie::rules::MultipleStartsEndsWith,
|
||||||
rules::flake8_pie::rules::UnnecessaryComprehensionAnyAll,
|
|
||||||
// flake8-commas
|
// flake8-commas
|
||||||
rules::flake8_commas::rules::MissingTrailingComma,
|
rules::flake8_commas::rules::MissingTrailingComma,
|
||||||
rules::flake8_commas::rules::TrailingCommaOnBareTuple,
|
rules::flake8_commas::rules::TrailingCommaOnBareTuple,
|
||||||
|
|
|
||||||
|
|
@ -92,5 +92,6 @@ static REDIRECTS: Lazy<HashMap<&'static str, &'static str>> = Lazy::new(|| {
|
||||||
("TYP001", "TCH001"),
|
("TYP001", "TCH001"),
|
||||||
// TODO(charlie): Remove by 2023-06-01.
|
// TODO(charlie): Remove by 2023-06-01.
|
||||||
("RUF004", "B026"),
|
("RUF004", "B026"),
|
||||||
|
("PIE802", "C419"),
|
||||||
])
|
])
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1201,3 +1201,47 @@ pub fn fix_unnecessary_literal_within_dict_call(
|
||||||
expr.end_location.unwrap(),
|
expr.end_location.unwrap(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// (C419) Convert `[i for i in a]` into `i for i in a`
|
||||||
|
pub fn fix_unnecessary_comprehension_any_all(
|
||||||
|
locator: &Locator,
|
||||||
|
stylist: &Stylist,
|
||||||
|
expr: &rustpython_parser::ast::Expr,
|
||||||
|
) -> Result<Edit> {
|
||||||
|
// Expr(ListComp) -> Expr(GeneratorExp)
|
||||||
|
let module_text = locator.slice(expr);
|
||||||
|
let mut tree = match_module(module_text)?;
|
||||||
|
let body = match_expr(&mut tree)?;
|
||||||
|
let call = match_call(body)?;
|
||||||
|
|
||||||
|
let Expression::ListComp(list_comp) = &call.args[0].value else {
|
||||||
|
bail!(
|
||||||
|
"Expected Expression::ListComp"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
call.args[0].value = Expression::GeneratorExp(Box::new(GeneratorExp {
|
||||||
|
elt: list_comp.elt.clone(),
|
||||||
|
for_in: list_comp.for_in.clone(),
|
||||||
|
lpar: list_comp.lpar.clone(),
|
||||||
|
rpar: list_comp.rpar.clone(),
|
||||||
|
}));
|
||||||
|
|
||||||
|
if let Some(comma) = &call.args[0].comma {
|
||||||
|
call.args[0].whitespace_after_arg = comma.whitespace_after.clone();
|
||||||
|
call.args[0].comma = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut state = CodegenState {
|
||||||
|
default_newline: &stylist.line_ending(),
|
||||||
|
default_indent: stylist.indentation(),
|
||||||
|
..CodegenState::default()
|
||||||
|
};
|
||||||
|
tree.codegen(&mut state);
|
||||||
|
|
||||||
|
Ok(Edit::replacement(
|
||||||
|
state.to_string(),
|
||||||
|
expr.location,
|
||||||
|
expr.end_location.unwrap(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,23 +16,24 @@ mod tests {
|
||||||
use crate::settings::Settings;
|
use crate::settings::Settings;
|
||||||
use crate::test::test_path;
|
use crate::test::test_path;
|
||||||
|
|
||||||
|
#[test_case(Rule::UnnecessaryCallAroundSorted, Path::new("C413.py"); "C413")]
|
||||||
|
#[test_case(Rule::UnnecessaryCollectionCall, Path::new("C408.py"); "C408")]
|
||||||
|
#[test_case(Rule::UnnecessaryComprehension, Path::new("C416.py"); "C416")]
|
||||||
|
#[test_case(Rule::UnnecessaryComprehensionAnyAll, Path::new("C419.py"); "C419")]
|
||||||
|
#[test_case(Rule::UnnecessaryDoubleCastOrProcess, Path::new("C414.py"); "C414")]
|
||||||
|
#[test_case(Rule::UnnecessaryGeneratorDict, Path::new("C402.py"); "C402")]
|
||||||
#[test_case(Rule::UnnecessaryGeneratorList, Path::new("C400.py"); "C400")]
|
#[test_case(Rule::UnnecessaryGeneratorList, Path::new("C400.py"); "C400")]
|
||||||
#[test_case(Rule::UnnecessaryGeneratorSet, Path::new("C401.py"); "C401")]
|
#[test_case(Rule::UnnecessaryGeneratorSet, Path::new("C401.py"); "C401")]
|
||||||
#[test_case(Rule::UnnecessaryGeneratorDict, Path::new("C402.py"); "C402")]
|
|
||||||
#[test_case(Rule::UnnecessaryListComprehensionSet, Path::new("C403.py"); "C403")]
|
|
||||||
#[test_case(Rule::UnnecessaryListComprehensionDict, Path::new("C404.py"); "C404")]
|
|
||||||
#[test_case(Rule::UnnecessaryLiteralSet, Path::new("C405.py"); "C405")]
|
|
||||||
#[test_case(Rule::UnnecessaryLiteralDict, Path::new("C406.py"); "C406")]
|
|
||||||
#[test_case(Rule::UnnecessaryCollectionCall, Path::new("C408.py"); "C408")]
|
|
||||||
#[test_case(Rule::UnnecessaryLiteralWithinTupleCall, Path::new("C409.py"); "C409")]
|
|
||||||
#[test_case(Rule::UnnecessaryLiteralWithinListCall, Path::new("C410.py"); "C410")]
|
|
||||||
#[test_case(Rule::UnnecessaryListCall, Path::new("C411.py"); "C411")]
|
#[test_case(Rule::UnnecessaryListCall, Path::new("C411.py"); "C411")]
|
||||||
#[test_case(Rule::UnnecessaryCallAroundSorted, Path::new("C413.py"); "C413")]
|
#[test_case(Rule::UnnecessaryListComprehensionDict, Path::new("C404.py"); "C404")]
|
||||||
#[test_case(Rule::UnnecessaryDoubleCastOrProcess, Path::new("C414.py"); "C414")]
|
#[test_case(Rule::UnnecessaryListComprehensionSet, Path::new("C403.py"); "C403")]
|
||||||
#[test_case(Rule::UnnecessarySubscriptReversal, Path::new("C415.py"); "C415")]
|
#[test_case(Rule::UnnecessaryLiteralDict, Path::new("C406.py"); "C406")]
|
||||||
#[test_case(Rule::UnnecessaryComprehension, Path::new("C416.py"); "C416")]
|
#[test_case(Rule::UnnecessaryLiteralSet, Path::new("C405.py"); "C405")]
|
||||||
#[test_case(Rule::UnnecessaryMap, Path::new("C417.py"); "C417")]
|
|
||||||
#[test_case(Rule::UnnecessaryLiteralWithinDictCall, Path::new("C418.py"); "C418")]
|
#[test_case(Rule::UnnecessaryLiteralWithinDictCall, Path::new("C418.py"); "C418")]
|
||||||
|
#[test_case(Rule::UnnecessaryLiteralWithinListCall, Path::new("C410.py"); "C410")]
|
||||||
|
#[test_case(Rule::UnnecessaryLiteralWithinTupleCall, Path::new("C409.py"); "C409")]
|
||||||
|
#[test_case(Rule::UnnecessaryMap, Path::new("C417.py"); "C417")]
|
||||||
|
#[test_case(Rule::UnnecessarySubscriptReversal, Path::new("C415.py"); "C415")]
|
||||||
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(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,9 @@ pub use unnecessary_collection_call::{unnecessary_collection_call, UnnecessaryCo
|
||||||
pub use unnecessary_comprehension::{
|
pub use unnecessary_comprehension::{
|
||||||
unnecessary_dict_comprehension, unnecessary_list_set_comprehension, UnnecessaryComprehension,
|
unnecessary_dict_comprehension, unnecessary_list_set_comprehension, UnnecessaryComprehension,
|
||||||
};
|
};
|
||||||
|
pub use unnecessary_comprehension_any_all::{
|
||||||
|
unnecessary_comprehension_any_all, UnnecessaryComprehensionAnyAll,
|
||||||
|
};
|
||||||
pub use unnecessary_double_cast_or_process::{
|
pub use unnecessary_double_cast_or_process::{
|
||||||
unnecessary_double_cast_or_process, UnnecessaryDoubleCastOrProcess,
|
unnecessary_double_cast_or_process, UnnecessaryDoubleCastOrProcess,
|
||||||
};
|
};
|
||||||
|
|
@ -38,6 +41,7 @@ mod helpers;
|
||||||
mod unnecessary_call_around_sorted;
|
mod unnecessary_call_around_sorted;
|
||||||
mod unnecessary_collection_call;
|
mod unnecessary_collection_call;
|
||||||
mod unnecessary_comprehension;
|
mod unnecessary_comprehension;
|
||||||
|
mod unnecessary_comprehension_any_all;
|
||||||
mod unnecessary_double_cast_or_process;
|
mod unnecessary_double_cast_or_process;
|
||||||
mod unnecessary_generator_dict;
|
mod unnecessary_generator_dict;
|
||||||
mod unnecessary_generator_list;
|
mod unnecessary_generator_list;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
use rustpython_parser::ast::{Expr, ExprKind, Keyword};
|
||||||
|
|
||||||
|
use ruff_diagnostics::AlwaysAutofixableViolation;
|
||||||
|
use ruff_diagnostics::Diagnostic;
|
||||||
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
|
use ruff_python_ast::helpers::any_over_expr;
|
||||||
|
use ruff_python_ast::types::Range;
|
||||||
|
|
||||||
|
use crate::checkers::ast::Checker;
|
||||||
|
use crate::registry::AsRule;
|
||||||
|
use crate::rules::flake8_comprehensions::fixes;
|
||||||
|
|
||||||
|
/// ## What it does
|
||||||
|
/// Checks for unnecessary list comprehensions passed to `any` and `all`.
|
||||||
|
///
|
||||||
|
/// ## Why is this bad?
|
||||||
|
/// `any` and `all` take any iterators, including generators. Converting a generator to a list
|
||||||
|
/// by way of a list comprehension is unnecessary and reduces performance due to the
|
||||||
|
/// overhead of creating the list.
|
||||||
|
///
|
||||||
|
/// For example, compare the performance of `all` with a list comprehension against that
|
||||||
|
/// of a generator (~40x faster here):
|
||||||
|
///
|
||||||
|
/// ```console
|
||||||
|
/// In [1]: %timeit all([i for i in range(1000)])
|
||||||
|
/// 8.14 µs ± 25.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
|
||||||
|
///
|
||||||
|
/// In [2]: %timeit all(i for i in range(1000))
|
||||||
|
/// 212 ns ± 0.892 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// ## Examples
|
||||||
|
/// ```python
|
||||||
|
/// any([x.id for x in bar])
|
||||||
|
/// all([x.id for x in bar])
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// Use instead:
|
||||||
|
/// ```python
|
||||||
|
/// any(x.id for x in bar)
|
||||||
|
/// all(x.id for x in bar)
|
||||||
|
/// ```
|
||||||
|
#[violation]
|
||||||
|
pub struct UnnecessaryComprehensionAnyAll;
|
||||||
|
|
||||||
|
impl AlwaysAutofixableViolation for UnnecessaryComprehensionAnyAll {
|
||||||
|
#[derive_message_formats]
|
||||||
|
fn message(&self) -> String {
|
||||||
|
format!("Unnecessary list comprehension.")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn autofix_title(&self) -> String {
|
||||||
|
"Remove unnecessary list comprehension".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// C419
|
||||||
|
pub fn unnecessary_comprehension_any_all(
|
||||||
|
checker: &mut Checker,
|
||||||
|
expr: &Expr,
|
||||||
|
func: &Expr,
|
||||||
|
args: &[Expr],
|
||||||
|
keywords: &[Keyword],
|
||||||
|
) {
|
||||||
|
if !keywords.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let ExprKind::Name { id, .. } = &func.node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if (matches!(id.as_str(), "all" | "any")) && args.len() == 1 {
|
||||||
|
let (ExprKind::ListComp { elt, .. } | ExprKind::SetComp { elt, .. }) = &args[0].node else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if is_async_generator(elt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if !checker.ctx.is_builtin(id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, Range::from(&args[0]));
|
||||||
|
if checker.patch(diagnostic.kind.rule()) {
|
||||||
|
diagnostic.try_set_fix(|| {
|
||||||
|
fixes::fix_unnecessary_comprehension_any_all(checker.locator, checker.stylist, expr)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checker.diagnostics.push(diagnostic);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return `true` if the `Expr` contains an `await` expression.
|
||||||
|
fn is_async_generator(expr: &Expr) -> bool {
|
||||||
|
any_over_expr(expr, &|expr| matches!(expr.node, ExprKind::Await { .. }))
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,91 @@
|
||||||
|
---
|
||||||
|
source: crates/ruff/src/rules/flake8_comprehensions/mod.rs
|
||||||
|
---
|
||||||
|
C419.py:1:5: C419 [*] Unnecessary list comprehension.
|
||||||
|
|
|
||||||
|
1 | any([x.id for x in bar])
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ C419
|
||||||
|
2 | all([x.id for x in bar])
|
||||||
|
3 | any( # first comment
|
||||||
|
|
|
||||||
|
= help: Remove unnecessary list comprehension
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 |-any([x.id for x in bar])
|
||||||
|
1 |+any(x.id for x in bar)
|
||||||
|
2 2 | all([x.id for x in bar])
|
||||||
|
3 3 | any( # first comment
|
||||||
|
4 4 | [x.id for x in bar], # second comment
|
||||||
|
|
||||||
|
C419.py:2:5: C419 [*] Unnecessary list comprehension.
|
||||||
|
|
|
||||||
|
2 | any([x.id for x in bar])
|
||||||
|
3 | all([x.id for x in bar])
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ C419
|
||||||
|
4 | any( # first comment
|
||||||
|
5 | [x.id for x in bar], # second comment
|
||||||
|
|
|
||||||
|
= help: Remove unnecessary list comprehension
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 | any([x.id for x in bar])
|
||||||
|
2 |-all([x.id for x in bar])
|
||||||
|
2 |+all(x.id for x in bar)
|
||||||
|
3 3 | any( # first comment
|
||||||
|
4 4 | [x.id for x in bar], # second comment
|
||||||
|
5 5 | ) # third comment
|
||||||
|
|
||||||
|
C419.py:4:5: C419 [*] Unnecessary list comprehension.
|
||||||
|
|
|
||||||
|
4 | all([x.id for x in bar])
|
||||||
|
5 | any( # first comment
|
||||||
|
6 | [x.id for x in bar], # second comment
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ C419
|
||||||
|
7 | ) # third comment
|
||||||
|
8 | all( # first comment
|
||||||
|
|
|
||||||
|
= help: Remove unnecessary list comprehension
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
1 1 | any([x.id for x in bar])
|
||||||
|
2 2 | all([x.id for x in bar])
|
||||||
|
3 3 | any( # first comment
|
||||||
|
4 |- [x.id for x in bar], # second comment
|
||||||
|
4 |+ x.id for x in bar # second comment
|
||||||
|
5 5 | ) # third comment
|
||||||
|
6 6 | all( # first comment
|
||||||
|
7 7 | [x.id for x in bar], # second comment
|
||||||
|
|
||||||
|
C419.py:7:5: C419 [*] Unnecessary list comprehension.
|
||||||
|
|
|
||||||
|
7 | ) # third comment
|
||||||
|
8 | all( # first comment
|
||||||
|
9 | [x.id for x in bar], # second comment
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ C419
|
||||||
|
10 | ) # third comment
|
||||||
|
11 | any({x.id for x in bar})
|
||||||
|
|
|
||||||
|
= help: Remove unnecessary list comprehension
|
||||||
|
|
||||||
|
ℹ Suggested fix
|
||||||
|
4 4 | [x.id for x in bar], # second comment
|
||||||
|
5 5 | ) # third comment
|
||||||
|
6 6 | all( # first comment
|
||||||
|
7 |- [x.id for x in bar], # second comment
|
||||||
|
7 |+ x.id for x in bar # second comment
|
||||||
|
8 8 | ) # third comment
|
||||||
|
9 9 | any({x.id for x in bar})
|
||||||
|
10 10 |
|
||||||
|
|
||||||
|
C419.py:9:5: C419 [*] Unnecessary list comprehension.
|
||||||
|
|
|
||||||
|
9 | [x.id for x in bar], # second comment
|
||||||
|
10 | ) # third comment
|
||||||
|
11 | any({x.id for x in bar})
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^ C419
|
||||||
|
12 |
|
||||||
|
13 | # OK
|
||||||
|
|
|
||||||
|
= help: Remove unnecessary list comprehension
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,50 +0,0 @@
|
||||||
use anyhow::{bail, Result};
|
|
||||||
use libcst_native::{Codegen, CodegenState, Expression, GeneratorExp};
|
|
||||||
|
|
||||||
use ruff_diagnostics::Edit;
|
|
||||||
use ruff_python_ast::source_code::{Locator, Stylist};
|
|
||||||
|
|
||||||
use crate::cst::matchers::{match_call, match_expression};
|
|
||||||
|
|
||||||
/// (PIE802) Convert `[i for i in a]` into `i for i in a`
|
|
||||||
pub fn fix_unnecessary_comprehension_any_all(
|
|
||||||
locator: &Locator,
|
|
||||||
stylist: &Stylist,
|
|
||||||
expr: &rustpython_parser::ast::Expr,
|
|
||||||
) -> Result<Edit> {
|
|
||||||
// Expr(ListComp) -> Expr(GeneratorExp)
|
|
||||||
let expression_text = locator.slice(expr);
|
|
||||||
let mut tree = match_expression(expression_text)?;
|
|
||||||
let call = match_call(&mut tree)?;
|
|
||||||
|
|
||||||
let Expression::ListComp(list_comp) = &call.args[0].value else {
|
|
||||||
bail!(
|
|
||||||
"Expected Expression::ListComp"
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
call.args[0].value = Expression::GeneratorExp(Box::new(GeneratorExp {
|
|
||||||
elt: list_comp.elt.clone(),
|
|
||||||
for_in: list_comp.for_in.clone(),
|
|
||||||
lpar: list_comp.lpar.clone(),
|
|
||||||
rpar: list_comp.rpar.clone(),
|
|
||||||
}));
|
|
||||||
|
|
||||||
if let Some(comma) = &call.args[0].comma {
|
|
||||||
call.args[0].whitespace_after_arg = comma.whitespace_after.clone();
|
|
||||||
call.args[0].comma = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut state = CodegenState {
|
|
||||||
default_newline: &stylist.line_ending(),
|
|
||||||
default_indent: stylist.indentation(),
|
|
||||||
..CodegenState::default()
|
|
||||||
};
|
|
||||||
tree.codegen(&mut state);
|
|
||||||
|
|
||||||
Ok(Edit::replacement(
|
|
||||||
state.to_string(),
|
|
||||||
expr.location,
|
|
||||||
expr.end_location.unwrap(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
//! Rules from [flake8-pie](https://pypi.org/project/flake8-pie/).
|
//! Rules from [flake8-pie](https://pypi.org/project/flake8-pie/).
|
||||||
mod fixes;
|
|
||||||
pub(crate) mod rules;
|
pub(crate) mod rules;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -21,7 +20,6 @@ mod tests {
|
||||||
#[test_case(Rule::UnnecessarySpread, Path::new("PIE800.py"); "PIE800")]
|
#[test_case(Rule::UnnecessarySpread, Path::new("PIE800.py"); "PIE800")]
|
||||||
#[test_case(Rule::ReimplementedListBuiltin, Path::new("PIE807.py"); "PIE807")]
|
#[test_case(Rule::ReimplementedListBuiltin, Path::new("PIE807.py"); "PIE807")]
|
||||||
#[test_case(Rule::NonUniqueEnums, Path::new("PIE796.py"); "PIE796")]
|
#[test_case(Rule::NonUniqueEnums, Path::new("PIE796.py"); "PIE796")]
|
||||||
#[test_case(Rule::UnnecessaryComprehensionAnyAll, Path::new("PIE802.py"); "PIE802")]
|
|
||||||
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(
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use ruff_diagnostics::{AlwaysAutofixableViolation, Violation};
|
||||||
use ruff_diagnostics::{Diagnostic, Edit};
|
use ruff_diagnostics::{Diagnostic, Edit};
|
||||||
use ruff_macros::{derive_message_formats, violation};
|
use ruff_macros::{derive_message_formats, violation};
|
||||||
use ruff_python_ast::comparable::ComparableExpr;
|
use ruff_python_ast::comparable::ComparableExpr;
|
||||||
use ruff_python_ast::helpers::{any_over_expr, create_expr, match_trailing_comment, unparse_expr};
|
use ruff_python_ast::helpers::{create_expr, match_trailing_comment, unparse_expr};
|
||||||
use ruff_python_ast::types::{Range, RefEquality};
|
use ruff_python_ast::types::{Range, RefEquality};
|
||||||
use ruff_python_stdlib::identifiers::is_identifier;
|
use ruff_python_stdlib::identifiers::is_identifier;
|
||||||
|
|
||||||
|
|
@ -21,8 +21,6 @@ use crate::checkers::ast::Checker;
|
||||||
use crate::message::Location;
|
use crate::message::Location;
|
||||||
use crate::registry::AsRule;
|
use crate::registry::AsRule;
|
||||||
|
|
||||||
use super::fixes;
|
|
||||||
|
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct UnnecessaryPass;
|
pub struct UnnecessaryPass;
|
||||||
|
|
||||||
|
|
@ -66,50 +64,6 @@ impl Violation for NonUniqueEnums {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## What it does
|
|
||||||
/// Checks for unnecessary list comprehensions passed to `any` and `all`.
|
|
||||||
///
|
|
||||||
/// ## Why is this bad?
|
|
||||||
/// `any` and `all` take any iterators, including generators. Converting a generator to a list
|
|
||||||
/// by way of a list comprehension is unnecessary and reduces performance due to the
|
|
||||||
/// overhead of creating the list.
|
|
||||||
///
|
|
||||||
/// For example, compare the performance of `all` with a list comprehension against that
|
|
||||||
/// of a generator (~40x faster here):
|
|
||||||
///
|
|
||||||
/// ```console
|
|
||||||
/// In [1]: %timeit all([i for i in range(1000)])
|
|
||||||
/// 8.14 µs ± 25.4 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)
|
|
||||||
///
|
|
||||||
/// In [2]: %timeit all(i for i in range(1000))
|
|
||||||
/// 212 ns ± 0.892 ns per loop (mean ± std. dev. of 7 runs, 1,000,000 loops each)
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// ## Examples
|
|
||||||
/// ```python
|
|
||||||
/// any([x.id for x in bar])
|
|
||||||
/// all([x.id for x in bar])
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Use instead:
|
|
||||||
/// ```python
|
|
||||||
/// any(x.id for x in bar)
|
|
||||||
/// all(x.id for x in bar)
|
|
||||||
/// ```
|
|
||||||
#[violation]
|
|
||||||
pub struct UnnecessaryComprehensionAnyAll;
|
|
||||||
|
|
||||||
impl AlwaysAutofixableViolation for UnnecessaryComprehensionAnyAll {
|
|
||||||
#[derive_message_formats]
|
|
||||||
fn message(&self) -> String {
|
|
||||||
format!("Unnecessary list comprehension.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn autofix_title(&self) -> String {
|
|
||||||
"Remove unnecessary list comprehension".to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[violation]
|
#[violation]
|
||||||
pub struct UnnecessarySpread;
|
pub struct UnnecessarySpread;
|
||||||
|
|
||||||
|
|
@ -331,41 +285,6 @@ pub fn unnecessary_spread(checker: &mut Checker, keys: &[Option<Expr>], values:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return `true` if the `Expr` contains an `await` expression.
|
|
||||||
fn is_async_generator(expr: &Expr) -> bool {
|
|
||||||
any_over_expr(expr, &|expr| matches!(expr.node, ExprKind::Await { .. }))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PIE802
|
|
||||||
pub fn unnecessary_comprehension_any_all(
|
|
||||||
checker: &mut Checker,
|
|
||||||
expr: &Expr,
|
|
||||||
func: &Expr,
|
|
||||||
args: &[Expr],
|
|
||||||
) {
|
|
||||||
let ExprKind::Name { id, .. } = &func.node else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if (matches!(id.as_str(), "all" | "any")) && args.len() == 1 {
|
|
||||||
let (ExprKind::ListComp { elt, .. } | ExprKind::SetComp { elt, .. }) = &args[0].node else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
if is_async_generator(elt) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if !checker.ctx.is_builtin(id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let mut diagnostic = Diagnostic::new(UnnecessaryComprehensionAnyAll, Range::from(&args[0]));
|
|
||||||
if checker.patch(diagnostic.kind.rule()) {
|
|
||||||
diagnostic.try_set_fix(|| {
|
|
||||||
fixes::fix_unnecessary_comprehension_any_all(checker.locator, checker.stylist, expr)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
checker.diagnostics.push(diagnostic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return `true` if a key is a valid keyword argument name.
|
/// Return `true` if a key is a valid keyword argument name.
|
||||||
fn is_valid_kwarg_name(key: &Expr) -> bool {
|
fn is_valid_kwarg_name(key: &Expr) -> bool {
|
||||||
if let ExprKind::Constant {
|
if let ExprKind::Constant {
|
||||||
|
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
---
|
|
||||||
source: crates/ruff/src/rules/flake8_pie/mod.rs
|
|
||||||
---
|
|
||||||
PIE802.py:2:5: PIE802 [*] Unnecessary list comprehension.
|
|
||||||
|
|
|
||||||
2 | # PIE802
|
|
||||||
3 | any([x.id for x in bar])
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ PIE802
|
|
||||||
4 | all([x.id for x in bar])
|
|
||||||
5 | any( # first comment
|
|
||||||
|
|
|
||||||
= help: Remove unnecessary list comprehension
|
|
||||||
|
|
||||||
ℹ Suggested fix
|
|
||||||
1 1 | # PIE802
|
|
||||||
2 |-any([x.id for x in bar])
|
|
||||||
2 |+any(x.id for x in bar)
|
|
||||||
3 3 | all([x.id for x in bar])
|
|
||||||
4 4 | any( # first comment
|
|
||||||
5 5 | [x.id for x in bar], # second comment
|
|
||||||
|
|
||||||
PIE802.py:3:5: PIE802 [*] Unnecessary list comprehension.
|
|
||||||
|
|
|
||||||
3 | # PIE802
|
|
||||||
4 | any([x.id for x in bar])
|
|
||||||
5 | all([x.id for x in bar])
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ PIE802
|
|
||||||
6 | any( # first comment
|
|
||||||
7 | [x.id for x in bar], # second comment
|
|
||||||
|
|
|
||||||
= help: Remove unnecessary list comprehension
|
|
||||||
|
|
||||||
ℹ Suggested fix
|
|
||||||
1 1 | # PIE802
|
|
||||||
2 2 | any([x.id for x in bar])
|
|
||||||
3 |-all([x.id for x in bar])
|
|
||||||
3 |+all(x.id for x in bar)
|
|
||||||
4 4 | any( # first comment
|
|
||||||
5 5 | [x.id for x in bar], # second comment
|
|
||||||
6 6 | ) # third comment
|
|
||||||
|
|
||||||
PIE802.py:5:5: PIE802 [*] Unnecessary list comprehension.
|
|
||||||
|
|
|
||||||
5 | all([x.id for x in bar])
|
|
||||||
6 | any( # first comment
|
|
||||||
7 | [x.id for x in bar], # second comment
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ PIE802
|
|
||||||
8 | ) # third comment
|
|
||||||
9 | all( # first comment
|
|
||||||
|
|
|
||||||
= help: Remove unnecessary list comprehension
|
|
||||||
|
|
||||||
ℹ Suggested fix
|
|
||||||
2 2 | any([x.id for x in bar])
|
|
||||||
3 3 | all([x.id for x in bar])
|
|
||||||
4 4 | any( # first comment
|
|
||||||
5 |- [x.id for x in bar], # second comment
|
|
||||||
5 |+ x.id for x in bar # second comment
|
|
||||||
6 6 | ) # third comment
|
|
||||||
7 7 | all( # first comment
|
|
||||||
8 8 | [x.id for x in bar], # second comment
|
|
||||||
|
|
||||||
PIE802.py:8:5: PIE802 [*] Unnecessary list comprehension.
|
|
||||||
|
|
|
||||||
8 | ) # third comment
|
|
||||||
9 | all( # first comment
|
|
||||||
10 | [x.id for x in bar], # second comment
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ PIE802
|
|
||||||
11 | ) # third comment
|
|
||||||
12 | any({x.id for x in bar})
|
|
||||||
|
|
|
||||||
= help: Remove unnecessary list comprehension
|
|
||||||
|
|
||||||
ℹ Suggested fix
|
|
||||||
5 5 | [x.id for x in bar], # second comment
|
|
||||||
6 6 | ) # third comment
|
|
||||||
7 7 | all( # first comment
|
|
||||||
8 |- [x.id for x in bar], # second comment
|
|
||||||
8 |+ x.id for x in bar # second comment
|
|
||||||
9 9 | ) # third comment
|
|
||||||
10 10 | any({x.id for x in bar})
|
|
||||||
11 11 |
|
|
||||||
|
|
||||||
PIE802.py:10:5: PIE802 [*] Unnecessary list comprehension.
|
|
||||||
|
|
|
||||||
10 | [x.id for x in bar], # second comment
|
|
||||||
11 | ) # third comment
|
|
||||||
12 | any({x.id for x in bar})
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^ PIE802
|
|
||||||
13 |
|
|
||||||
14 | # OK
|
|
||||||
|
|
|
||||||
= help: Remove unnecessary list comprehension
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1605,6 +1605,7 @@
|
||||||
"C416",
|
"C416",
|
||||||
"C417",
|
"C417",
|
||||||
"C418",
|
"C418",
|
||||||
|
"C419",
|
||||||
"C9",
|
"C9",
|
||||||
"C90",
|
"C90",
|
||||||
"C901",
|
"C901",
|
||||||
|
|
@ -1920,7 +1921,6 @@
|
||||||
"PIE8",
|
"PIE8",
|
||||||
"PIE80",
|
"PIE80",
|
||||||
"PIE800",
|
"PIE800",
|
||||||
"PIE802",
|
|
||||||
"PIE804",
|
"PIE804",
|
||||||
"PIE807",
|
"PIE807",
|
||||||
"PIE81",
|
"PIE81",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue