Implement B017 (no assertRaises(Exception)) (#467)

This commit is contained in:
Charlie Marsh
2022-10-25 20:55:00 -04:00
committed by GitHub
parent 66089052ee
commit bcf7519eb3
9 changed files with 104 additions and 3 deletions

View File

@@ -667,6 +667,11 @@ where
flake8_bugbear::plugins::assert_false(self, stmt, test, msg);
}
}
StmtKind::With { items, .. } | StmtKind::AsyncWith { items, .. } => {
if self.settings.enabled.contains(&CheckCode::B017) {
flake8_bugbear::plugins::assert_raises_exception(self, stmt, items);
}
}
StmtKind::Try { handlers, .. } => {
if self.settings.enabled.contains(&CheckCode::F707) {
if let Some(check) = pyflakes::checks::default_except_not_last(handlers) {

View File

@@ -77,6 +77,7 @@ pub enum CheckCode {
// flake8-bugbear
B011,
B014,
B017,
B025,
// flake8-comprehensions
C400,
@@ -267,6 +268,7 @@ pub enum CheckKind {
// flake8-bugbear
DoNotAssertFalse,
DuplicateHandlerException(Vec<String>),
NoAssertRaisesException,
DuplicateTryBlockException(String),
// flake8-comprehensions
UnnecessaryGeneratorList,
@@ -426,6 +428,7 @@ impl CheckCode {
// flake8-bugbear
CheckCode::B011 => CheckKind::DoNotAssertFalse,
CheckCode::B014 => CheckKind::DuplicateHandlerException(vec!["ValueError".to_string()]),
CheckCode::B017 => CheckKind::NoAssertRaisesException,
CheckCode::B025 => CheckKind::DuplicateTryBlockException("Exception".to_string()),
// flake8-comprehensions
CheckCode::C400 => CheckKind::UnnecessaryGeneratorList,
@@ -600,6 +603,7 @@ impl CheckCode {
CheckCode::A003 => CheckCategory::Flake8Builtins,
CheckCode::B011 => CheckCategory::Flake8Bugbear,
CheckCode::B014 => CheckCategory::Flake8Bugbear,
CheckCode::B017 => CheckCategory::Flake8Bugbear,
CheckCode::B025 => CheckCategory::Flake8Bugbear,
CheckCode::C400 => CheckCategory::Flake8Comprehensions,
CheckCode::C401 => CheckCategory::Flake8Comprehensions,
@@ -743,6 +747,7 @@ impl CheckKind {
// flake8-bugbear
CheckKind::DoNotAssertFalse => &CheckCode::B011,
CheckKind::DuplicateHandlerException(_) => &CheckCode::B014,
CheckKind::NoAssertRaisesException => &CheckCode::B017,
CheckKind::DuplicateTryBlockException(_) => &CheckCode::B025,
// flake8-comprehensions
CheckKind::UnnecessaryGeneratorList => &CheckCode::C400,
@@ -992,6 +997,9 @@ impl CheckKind {
format!("Exception handler with duplicate exceptions: {names}")
}
}
CheckKind::NoAssertRaisesException => {
"`assertRaises(Exception):` should be considered evil. It can lead to your test passing even if the code being tested is never executed due to a typo. Either assert for a more specific exception (builtin or custom), use `assertRaisesRegex`, or use the context manager form of `assertRaises`.".to_string()
}
CheckKind::DuplicateTryBlockException(name) => {
format!("try-except block with duplicate exception `{name}`")
}
@@ -1258,6 +1266,16 @@ impl CheckKind {
}
}
/// The summary text for the check.
pub fn summary(&self) -> String {
match self {
CheckKind::NoAssertRaisesException => {
"`assertRaises(Exception):` should be considered evil.".to_string()
}
_ => self.body(),
}
}
/// Whether the check kind is (potentially) fixable.
pub fn fixable(&self) -> bool {
matches!(

View File

@@ -0,0 +1,25 @@
use rustpython_ast::{ExprKind, Stmt, Withitem};
use crate::ast::helpers::match_name_or_attr;
use crate::ast::types::Range;
use crate::check_ast::Checker;
use crate::checks::{Check, CheckKind};
/// B017
pub fn assert_raises_exception(checker: &mut Checker, stmt: &Stmt, items: &[Withitem]) {
if let Some(item) = items.first() {
let item_context = &item.context_expr;
if let ExprKind::Call { func, args, .. } = &item_context.node {
if match_name_or_attr(func, "assertRaises")
&& args.len() == 1
&& match_name_or_attr(args.first().unwrap(), "Exception")
&& item.optional_vars.is_none()
{
checker.add_check(Check::new(
CheckKind::NoAssertRaisesException,
Range::from_located(stmt),
));
}
}
}
}

View File

@@ -1,6 +1,8 @@
pub use assert_false::assert_false;
pub use assert_raises_exception::assert_raises_exception;
pub use duplicate_exceptions::duplicate_exceptions;
pub use duplicate_exceptions::duplicate_handler_exceptions;
mod assert_false;
mod assert_raises_exception;
mod duplicate_exceptions;

View File

@@ -247,6 +247,7 @@ mod tests {
#[test_case(CheckCode::A003, Path::new("A003.py"); "A003")]
#[test_case(CheckCode::B011, Path::new("B011.py"); "B011")]
#[test_case(CheckCode::B014, Path::new("B014.py"); "B014")]
#[test_case(CheckCode::B017, Path::new("B017.py"); "B017")]
#[test_case(CheckCode::B025, Path::new("B025.py"); "B025")]
#[test_case(CheckCode::C400, Path::new("C400.py"); "C400")]
#[test_case(CheckCode::C401, Path::new("C401.py"); "C401")]

View File

@@ -0,0 +1,13 @@
---
source: src/linter.rs
expression: checks
---
- kind: NoAssertRaisesException
location:
row: 22
column: 9
end_location:
row: 25
column: 5
fix: ~