Skip to content

Commit

Permalink
Implement PERF203
Browse files Browse the repository at this point in the history
  • Loading branch information
evanrittenhouse committed Jun 17, 2023
1 parent 4b9b682 commit 3f76ac8
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 0 deletions.
11 changes: 11 additions & 0 deletions crates/ruff/resources/test/fixtures/perflint/PERF203.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
for i in range(10):
try:
print(f"{i}") # PERF203
except:
print("error")

try:
for i in range(10):
print(f"{i}")
except:
print("error")
3 changes: 3 additions & 0 deletions crates/ruff/src/checkers/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,9 @@ where
if self.enabled(Rule::InDictKeys) {
flake8_simplify::rules::key_in_dict_for(self, target, iter);
}
if self.enabled(Rule::LoopTryExceptUsage) {
perflint::rules::loop_try_except_usage(self, body);
}
}
if self.enabled(Rule::IncorrectDictIterator) {
perflint::rules::incorrect_dict_iterator(self, target, iter);
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -785,6 +785,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option<(RuleGroup, Rule)> {

// perflint
(Perflint, "102") => (RuleGroup::Unspecified, rules::perflint::rules::IncorrectDictIterator),
(Perflint, "203") => (RuleGroup::Unspecified, rules::perflint::rules::LoopTryExceptUsage),

// flake8-fixme
(Flake8Fixme, "001") => (RuleGroup::Unspecified, rules::flake8_fixme::rules::LineContainsFixme),
Expand Down
1 change: 1 addition & 0 deletions crates/ruff/src/rules/perflint/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ mod tests {
use crate::test::test_path;

#[test_case(Rule::IncorrectDictIterator, Path::new("PERF102.py"))]
#[test_case(Rule::LoopTryExceptUsage, Path::new("PERF203.py"))]
fn rules(rule_code: Rule, path: &Path) -> Result<()> {
let snapshot = format!("{}_{}", rule_code.noqa_code(), path.to_string_lossy());
let diagnostics = test_path(
Expand Down
49 changes: 49 additions & 0 deletions crates/ruff/src/rules/perflint/rules/loop_try_except_usage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use ruff_diagnostics::{Diagnostic, Violation};
use ruff_macros::{derive_message_formats, violation};
use ruff_python_ast::prelude::{Stmt, StmtTry};

use crate::checkers::ast::Checker;

/// ## What it does
/// Checks to see if a for loop contains a try/except block.
///
/// ## Why is this bad?
/// Try/except blocks can be computationally expensive, especially prior to Python 3.10.
/// Instead, you should refactor your code to put the entire loop into the `try` block.
///
/// ## Example
/// ```python
/// for _ in range(10):
/// try:
/// print("something")
/// except:
/// print("error")
/// ```
///
/// Use instead:
/// ```python
/// try:
/// for _ in range(10):
/// print("something")
/// except:
/// print("error")
/// ```

#[violation]
pub(crate) struct LoopTryExceptUsage;

impl Violation for LoopTryExceptUsage {
#[derive_message_formats]
fn message(&self) -> String {
format!("Try..except blocks have a significant overhead. Avoid using them inside a loop.")
}
}

pub(crate) fn loop_try_except_usage(checker: &mut Checker, body: &[Stmt]) {
body.iter()
.filter_map(|el| match el {
Stmt::Try(StmtTry { range, .. }) => Some(Diagnostic::new(LoopTryExceptUsage, *range)),
_ => None,
})
.for_each(|diagnostic| checker.diagnostics.push(diagnostic));
}
2 changes: 2 additions & 0 deletions crates/ruff/src/rules/perflint/rules/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
pub(crate) use incorrect_dict_iterator::{incorrect_dict_iterator, IncorrectDictIterator};
pub(crate) use loop_try_except_usage::{loop_try_except_usage, LoopTryExceptUsage};

mod incorrect_dict_iterator;
mod loop_try_except_usage;
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
source: crates/ruff/src/rules/perflint/mod.rs
---
PERF203.py:2:5: PERF203 Try..except blocks have a significant overhead. Avoid using them inside a loop.
|
1 | for i in range(10):
2 | try:
| _____^
3 | | print(f"{i}") # PERF203
4 | | except:
5 | | print("error")
| |______________________^ PERF203
6 |
7 | try:
|


3 changes: 3 additions & 0 deletions ruff.schema.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3f76ac8

Please sign in to comment.