diff --git a/resources/test/src/raise_not_implemented.py b/resources/test/src/raise_not_implemented.py new file mode 100644 index 0000000000..990c5d73af --- /dev/null +++ b/resources/test/src/raise_not_implemented.py @@ -0,0 +1,6 @@ +def f() -> None: + raise NotImplemented() + + +def g() -> None: + raise NotImplemented diff --git a/src/check_ast.rs b/src/check_ast.rs index 8b4ee205f0..eb6baa231f 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -50,6 +50,37 @@ impl Visitor for Checker<'_> { } } } + StmtKind::Raise { exc, .. } => { + if self + .settings + .select + .contains(CheckKind::RaiseNotImplemented.code()) + { + if let Some(expr) = exc { + match &expr.node { + ExprKind::Call { func, .. } => { + if let ExprKind::Name { id, .. } = &func.node { + if id == "NotImplemented" { + self.checks.push(Check { + kind: CheckKind::RaiseNotImplemented, + location: stmt.location, + }); + } + } + } + ExprKind::Name { id, .. } => { + if id == "NotImplemented" { + self.checks.push(Check { + kind: CheckKind::RaiseNotImplemented, + location: stmt.location, + }); + } + } + _ => {} + } + } + } + } _ => {} } diff --git a/src/checks.rs b/src/checks.rs index b5d49ca7e7..5e4191d79b 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -7,6 +7,7 @@ pub enum CheckCode { F541, F634, F403, + F901, E501, } @@ -17,6 +18,7 @@ impl CheckCode { CheckCode::F541 => "F541", CheckCode::F634 => "F634", CheckCode::F403 => "F403", + CheckCode::F901 => "F901", CheckCode::E501 => "E501", } } @@ -34,6 +36,7 @@ pub enum CheckKind { FStringMissingPlaceholders, IfTuple, ImportStarUsage, + RaiseNotImplemented, LineTooLong, } @@ -45,6 +48,7 @@ impl CheckKind { CheckCode::F541 => CheckKind::FStringMissingPlaceholders, CheckCode::F634 => CheckKind::IfTuple, CheckCode::F403 => CheckKind::ImportStarUsage, + CheckCode::F901 => CheckKind::RaiseNotImplemented, CheckCode::E501 => CheckKind::LineTooLong, } } @@ -56,6 +60,7 @@ impl CheckKind { CheckKind::FStringMissingPlaceholders => &CheckCode::F541, CheckKind::IfTuple => &CheckCode::F634, CheckKind::ImportStarUsage => &CheckCode::F403, + CheckKind::RaiseNotImplemented => &CheckCode::F901, CheckKind::LineTooLong => &CheckCode::E501, } } @@ -67,6 +72,9 @@ impl CheckKind { CheckKind::FStringMissingPlaceholders => "f-string without any placeholders", CheckKind::IfTuple => "If test is a tuple, which is always `True`", CheckKind::ImportStarUsage => "Unable to detect undefined names", + CheckKind::RaiseNotImplemented => { + "'raise NotImplemented' should be 'raise NotImplementedError" + } CheckKind::LineTooLong => "Line too long", } } @@ -78,6 +86,7 @@ impl CheckKind { CheckKind::FStringMissingPlaceholders => &LintSource::AST, CheckKind::IfTuple => &LintSource::AST, CheckKind::ImportStarUsage => &LintSource::AST, + CheckKind::RaiseNotImplemented => &LintSource::AST, CheckKind::LineTooLong => &LintSource::Lines, } } diff --git a/src/linter.rs b/src/linter.rs index a5be15f7f6..daa46f4960 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -66,10 +66,7 @@ mod tests { use anyhow::Result; use rustpython_parser::ast::Location; - use crate::checks::CheckCode; - use crate::checks::CheckKind::{ - DuplicateArgumentName, FStringMissingPlaceholders, IfTuple, ImportStarUsage, LineTooLong, - }; + use crate::checks::{CheckCode, CheckKind}; use crate::linter::check_path; use crate::message::Message; use crate::{cache, settings}; @@ -87,17 +84,17 @@ mod tests { )?; let expected = vec![ Message { - kind: DuplicateArgumentName, + kind: CheckKind::DuplicateArgumentName, location: Location::new(1, 25), filename: "./resources/test/src/duplicate_argument_name.py".to_string(), }, Message { - kind: DuplicateArgumentName, + kind: CheckKind::DuplicateArgumentName, location: Location::new(5, 28), filename: "./resources/test/src/duplicate_argument_name.py".to_string(), }, Message { - kind: DuplicateArgumentName, + kind: CheckKind::DuplicateArgumentName, location: Location::new(9, 27), filename: "./resources/test/src/duplicate_argument_name.py".to_string(), }, @@ -123,17 +120,17 @@ mod tests { )?; let expected = vec![ Message { - kind: FStringMissingPlaceholders, + kind: CheckKind::FStringMissingPlaceholders, location: Location::new(4, 7), filename: "./resources/test/src/f_string_missing_placeholders.py".to_string(), }, Message { - kind: FStringMissingPlaceholders, + kind: CheckKind::FStringMissingPlaceholders, location: Location::new(5, 7), filename: "./resources/test/src/f_string_missing_placeholders.py".to_string(), }, Message { - kind: FStringMissingPlaceholders, + kind: CheckKind::FStringMissingPlaceholders, location: Location::new(7, 7), filename: "./resources/test/src/f_string_missing_placeholders.py".to_string(), }, @@ -159,12 +156,12 @@ mod tests { )?; let expected = vec![ Message { - kind: IfTuple, + kind: CheckKind::IfTuple, location: Location::new(1, 1), filename: "./resources/test/src/if_tuple.py".to_string(), }, Message { - kind: IfTuple, + kind: CheckKind::IfTuple, location: Location::new(7, 5), filename: "./resources/test/src/if_tuple.py".to_string(), }, @@ -190,12 +187,12 @@ mod tests { )?; let expected = vec![ Message { - kind: ImportStarUsage, + kind: CheckKind::ImportStarUsage, location: Location::new(1, 1), filename: "./resources/test/src/import_star_usage.py".to_string(), }, Message { - kind: ImportStarUsage, + kind: CheckKind::ImportStarUsage, location: Location::new(2, 1), filename: "./resources/test/src/import_star_usage.py".to_string(), }, @@ -208,6 +205,37 @@ mod tests { Ok(()) } + #[test] + fn raise_not_implemented() -> Result<()> { + let actual = check_path( + &Path::new("./resources/test/src/raise_not_implemented.py"), + &settings::Settings { + line_length: 88, + exclude: vec![], + select: BTreeSet::from([CheckCode::F901]), + }, + &cache::Mode::None, + )?; + let expected = vec![ + Message { + kind: CheckKind::RaiseNotImplemented, + location: Location::new(2, 5), + filename: "./resources/test/src/raise_not_implemented.py".to_string(), + }, + Message { + kind: CheckKind::RaiseNotImplemented, + location: Location::new(6, 5), + filename: "./resources/test/src/raise_not_implemented.py".to_string(), + }, + ]; + assert_eq!(actual.len(), expected.len()); + for i in 0..actual.len() { + assert_eq!(actual[i], expected[i]); + } + + Ok(()) + } + #[test] fn line_too_long() -> Result<()> { let actual = check_path( @@ -220,7 +248,7 @@ mod tests { &cache::Mode::None, )?; let expected = vec![Message { - kind: LineTooLong, + kind: CheckKind::LineTooLong, location: Location::new(5, 89), filename: "./resources/test/src/line_too_long.py".to_string(), }]; diff --git a/src/settings.rs b/src/settings.rs index 232bd8d523..57177c2b94 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -45,6 +45,7 @@ impl Settings { CheckCode::F541, CheckCode::F634, CheckCode::F403, + CheckCode::F901, CheckCode::E501, ]) }),