diff --git a/README.md b/README.md index 695a1846db..d4ab0ce61d 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ OPTIONS: | F401 | UnusedImport | `...` imported but unused | | F403 | ImportStarUsage | Unable to detect undefined names | | F541 | FStringMissingPlaceholders | f-string without any placeholders | +| F631 | AssertTuple | Assert test is a non-empty tuple, which is always `True` | | F634 | IfTuple | If test is a tuple, which is always `True` | | F704 | YieldOutsideFunction | a `yield` or `yield from` statement outside of a function/method | | F706 | ReturnOutsideFunction | a `return` statement outside of a function/method | diff --git a/resources/test/fixtures/F631.py b/resources/test/fixtures/F631.py new file mode 100644 index 0000000000..47241930ac --- /dev/null +++ b/resources/test/fixtures/F631.py @@ -0,0 +1,4 @@ +assert (False, "x") +assert (False,) +assert () +assert True diff --git a/resources/test/fixtures/pyproject.toml b/resources/test/fixtures/pyproject.toml index 80c93adb39..05d2b29663 100644 --- a/resources/test/fixtures/pyproject.toml +++ b/resources/test/fixtures/pyproject.toml @@ -6,6 +6,7 @@ select = [ "F401", "F403", "F541", + "F631", "F634", "F704", "F706", diff --git a/src/check_ast.rs b/src/check_ast.rs index a5794c930b..5e04f0f3a5 100644 --- a/src/check_ast.rs +++ b/src/check_ast.rs @@ -283,6 +283,18 @@ impl Visitor for Checker<'_> { } } StmtKind::AugAssign { target, .. } => self.handle_node_load(target), + StmtKind::Assert { test, .. } => { + if self.settings.select.contains(CheckKind::AssertTuple.code()) { + if let ExprKind::Tuple { elts, .. } = &test.node { + if !elts.is_empty() { + self.checks.push(Check { + kind: CheckKind::AssertTuple, + location: stmt.location, + }); + } + } + } + } _ => {} } diff --git a/src/checks.rs b/src/checks.rs index 7b4443a722..643682efc8 100644 --- a/src/checks.rs +++ b/src/checks.rs @@ -12,6 +12,7 @@ pub enum CheckCode { F401, F403, F541, + F631, F634, F704, F706, @@ -33,6 +34,7 @@ impl FromStr for CheckCode { "F401" => Ok(CheckCode::F401), "F403" => Ok(CheckCode::F403), "F541" => Ok(CheckCode::F541), + "F631" => Ok(CheckCode::F631), "F634" => Ok(CheckCode::F634), "F704" => Ok(CheckCode::F704), "F706" => Ok(CheckCode::F706), @@ -55,6 +57,7 @@ impl CheckCode { CheckCode::F401 => "F401", CheckCode::F403 => "F403", CheckCode::F541 => "F541", + CheckCode::F631 => "F631", CheckCode::F634 => "F634", CheckCode::F704 => "F704", CheckCode::F706 => "F706", @@ -75,6 +78,7 @@ impl CheckCode { CheckCode::F401 => &LintSource::AST, CheckCode::F403 => &LintSource::AST, CheckCode::F541 => &LintSource::AST, + CheckCode::F631 => &LintSource::AST, CheckCode::F634 => &LintSource::AST, CheckCode::F704 => &LintSource::AST, CheckCode::F706 => &LintSource::AST, @@ -99,6 +103,7 @@ pub enum LintSource { pub enum CheckKind { DuplicateArgumentName, FStringMissingPlaceholders, + AssertTuple, IfTuple, ImportStarUsage, LineTooLong, @@ -119,6 +124,7 @@ impl CheckKind { match self { CheckKind::DuplicateArgumentName => "DuplicateArgumentName", CheckKind::FStringMissingPlaceholders => "FStringMissingPlaceholders", + CheckKind::AssertTuple => "AssertTuple", CheckKind::IfTuple => "IfTuple", CheckKind::ImportStarUsage => "ImportStarUsage", CheckKind::LineTooLong => "LineTooLong", @@ -139,6 +145,7 @@ impl CheckKind { match self { CheckKind::DuplicateArgumentName => &CheckCode::F831, CheckKind::FStringMissingPlaceholders => &CheckCode::F541, + CheckKind::AssertTuple => &CheckCode::F631, CheckKind::IfTuple => &CheckCode::F634, CheckKind::ImportStarUsage => &CheckCode::F403, CheckKind::LineTooLong => &CheckCode::E501, @@ -163,6 +170,9 @@ impl CheckKind { CheckKind::FStringMissingPlaceholders => { "f-string without any placeholders".to_string() } + CheckKind::AssertTuple => { + "Assert test is a non-empty tuple, which is always `True`".to_string() + } CheckKind::IfTuple => "If test is a tuple, which is always `True`".to_string(), CheckKind::ImportStarUsage => "Unable to detect undefined names".to_string(), CheckKind::LineTooLong => "Line too long".to_string(), diff --git a/src/linter.rs b/src/linter.rs index 59c5571c4f..a4a78c7823 100644 --- a/src/linter.rs +++ b/src/linter.rs @@ -191,6 +191,37 @@ mod tests { Ok(()) } + #[test] + fn f631() -> Result<()> { + let actual = check_path( + Path::new("./resources/test/fixtures/F631.py"), + &settings::Settings { + line_length: 88, + exclude: vec![], + select: BTreeSet::from([CheckCode::F631]), + }, + &cache::Mode::None, + )?; + let expected = vec![ + Message { + kind: CheckKind::AssertTuple, + location: Location::new(1, 1), + filename: "./resources/test/fixtures/F631.py".to_string(), + }, + Message { + kind: CheckKind::AssertTuple, + location: Location::new(2, 1), + filename: "./resources/test/fixtures/F631.py".to_string(), + }, + ]; + assert_eq!(actual.len(), expected.len()); + for i in 0..actual.len() { + assert_eq!(actual[i], expected[i]); + } + + Ok(()) + } + #[test] fn f634() -> Result<()> { let actual = check_path( diff --git a/src/pyproject.rs b/src/pyproject.rs index c18fc9be92..87a6537400 100644 --- a/src/pyproject.rs +++ b/src/pyproject.rs @@ -241,6 +241,7 @@ other-attribute = 1 CheckCode::F401, CheckCode::F403, CheckCode::F541, + CheckCode::F631, CheckCode::F634, CheckCode::F704, CheckCode::F706, diff --git a/src/settings.rs b/src/settings.rs index e603b6c16f..7fbd67a872 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -48,6 +48,7 @@ impl Settings { CheckCode::F401, CheckCode::F403, CheckCode::F541, + CheckCode::F631, CheckCode::F634, CheckCode::F706, CheckCode::F831,