diff --git a/crates/ruff/resources/test/fixtures/flake8_bugbear/B029.py b/crates/ruff/resources/test/fixtures/flake8_bugbear/B029.py new file mode 100644 index 0000000000000..beb04a4059392 --- /dev/null +++ b/crates/ruff/resources/test/fixtures/flake8_bugbear/B029.py @@ -0,0 +1,14 @@ +""" +Should emit: +B029 - on lines 8 and 13 +""" + +try: + pass +except (): + pass + +try: + pass +except () as e: + pass \ No newline at end of file diff --git a/crates/ruff/src/checkers/ast.rs b/crates/ruff/src/checkers/ast.rs index 600606187812d..4d7f8a74ffe17 100644 --- a/crates/ruff/src/checkers/ast.rs +++ b/crates/ruff/src/checkers/ast.rs @@ -3708,6 +3708,9 @@ where self.settings.flake8_bandit.check_typed_exception, ); } + if self.settings.rules.enabled(&Rule::ExceptWithEmptyTuple) { + flake8_bugbear::rules::except_with_empty_tuple(self, excepthandler); + } if self.settings.rules.enabled(&Rule::ReraiseNoCause) { tryceratops::rules::reraise_no_cause(self, body); } diff --git a/crates/ruff/src/codes.rs b/crates/ruff/src/codes.rs index 3597979c61182..e80b4accdcd73 100644 --- a/crates/ruff/src/codes.rs +++ b/crates/ruff/src/codes.rs @@ -179,6 +179,7 @@ pub fn code_to_rule(linter: Linter, code: &str) -> Option { (Flake8Bugbear, "025") => Rule::DuplicateTryBlockException, (Flake8Bugbear, "026") => Rule::StarArgUnpackingAfterKeywordArg, (Flake8Bugbear, "027") => Rule::EmptyMethodWithoutAbstractDecorator, + (Flake8Bugbear, "029") => Rule::ExceptWithEmptyTuple, (Flake8Bugbear, "904") => Rule::RaiseWithoutFromInsideExcept, (Flake8Bugbear, "905") => Rule::ZipWithoutExplicitStrict, diff --git a/crates/ruff/src/registry.rs b/crates/ruff/src/registry.rs index 2e03a3e7ae4e5..74c1bf65744eb 100644 --- a/crates/ruff/src/registry.rs +++ b/crates/ruff/src/registry.rs @@ -182,6 +182,7 @@ ruff_macros::register_rules!( rules::flake8_bugbear::rules::EmptyMethodWithoutAbstractDecorator, rules::flake8_bugbear::rules::RaiseWithoutFromInsideExcept, rules::flake8_bugbear::rules::ZipWithoutExplicitStrict, + rules::flake8_bugbear::rules::ExceptWithEmptyTuple, // flake8-blind-except rules::flake8_blind_except::rules::BlindExcept, // flake8-comprehensions diff --git a/crates/ruff/src/rules/flake8_bugbear/mod.rs b/crates/ruff/src/rules/flake8_bugbear/mod.rs index 0765b834c10cd..c91d9757dc6f8 100644 --- a/crates/ruff/src/rules/flake8_bugbear/mod.rs +++ b/crates/ruff/src/rules/flake8_bugbear/mod.rs @@ -41,6 +41,7 @@ mod tests { #[test_case(Rule::StarArgUnpackingAfterKeywordArg, Path::new("B026.py"); "B026")] #[test_case(Rule::EmptyMethodWithoutAbstractDecorator, Path::new("B027.py"); "B027")] #[test_case(Rule::EmptyMethodWithoutAbstractDecorator, Path::new("B027.pyi"); "B027_pyi")] + #[test_case(Rule::ExceptWithEmptyTuple, Path::new("B029.py"); "B029")] #[test_case(Rule::RaiseWithoutFromInsideExcept, Path::new("B904.py"); "B904")] #[test_case(Rule::ZipWithoutExplicitStrict, Path::new("B905.py"); "B905")] fn rules(rule_code: Rule, path: &Path) -> Result<()> { diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/except_with_empty_tuple.rs b/crates/ruff/src/rules/flake8_bugbear/rules/except_with_empty_tuple.rs new file mode 100644 index 0000000000000..c9e4e7f682d61 --- /dev/null +++ b/crates/ruff/src/rules/flake8_bugbear/rules/except_with_empty_tuple.rs @@ -0,0 +1,36 @@ +use ruff_macros::{define_violation, derive_message_formats}; +use rustpython_parser::ast::Excepthandler; + +use crate::ast::types::Range; +use crate::checkers::ast::Checker; +use crate::registry::Diagnostic; +use crate::violation::Violation; + +use rustpython_parser::ast::{ExcepthandlerKind, ExprKind}; + +define_violation!( + pub struct ExceptWithEmptyTuple; +); +impl Violation for ExceptWithEmptyTuple { + #[derive_message_formats] + fn message(&self) -> String { + format!("Using except (): with an empty tuple does not handle/catch anything. Add exceptions to handle.") + } +} + +/// B029 +pub fn except_with_empty_tuple(checker: &mut Checker, excepthandler: &Excepthandler) { + let ExcepthandlerKind::ExceptHandler { type_, .. } = &excepthandler.node; + if type_.is_none() { + return; + } + let ExprKind::Tuple { elts, .. } = &type_.as_ref().unwrap().node else { + return; + }; + if elts.is_empty() { + checker.diagnostics.push(Diagnostic::new( + ExceptWithEmptyTuple, + Range::from_located(excepthandler), + )); + } +} diff --git a/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs b/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs index a9e936115c7bd..73283b204382b 100644 --- a/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs +++ b/crates/ruff/src/rules/flake8_bugbear/rules/mod.rs @@ -10,6 +10,7 @@ pub use cannot_raise_literal::{cannot_raise_literal, CannotRaiseLiteral}; pub use duplicate_exceptions::{ duplicate_exceptions, DuplicateHandlerException, DuplicateTryBlockException, }; +pub use except_with_empty_tuple::{except_with_empty_tuple, ExceptWithEmptyTuple}; pub use f_string_docstring::{f_string_docstring, FStringDocstring}; pub use function_call_argument_default::{ function_call_argument_default, FunctionCallArgumentDefault, @@ -47,6 +48,7 @@ mod assignment_to_os_environ; mod cached_instance_method; mod cannot_raise_literal; mod duplicate_exceptions; +mod except_with_empty_tuple; mod f_string_docstring; mod function_call_argument_default; mod function_uses_loop_variable; diff --git a/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B029_B029.py.snap b/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B029_B029.py.snap new file mode 100644 index 0000000000000..d7949e900e228 --- /dev/null +++ b/crates/ruff/src/rules/flake8_bugbear/snapshots/ruff__rules__flake8_bugbear__tests__B029_B029.py.snap @@ -0,0 +1,25 @@ +--- +source: crates/ruff/src/rules/flake8_bugbear/mod.rs +expression: diagnostics +--- +- kind: + ExceptWithEmptyTuple: ~ + location: + row: 8 + column: 0 + end_location: + row: 9 + column: 8 + fix: ~ + parent: ~ +- kind: + ExceptWithEmptyTuple: ~ + location: + row: 13 + column: 0 + end_location: + row: 14 + column: 8 + fix: ~ + parent: ~ + diff --git a/ruff.schema.json b/ruff.schema.json index c7d899ac3a668..710060c7f0285 100644 --- a/ruff.schema.json +++ b/ruff.schema.json @@ -1429,6 +1429,7 @@ "B025", "B026", "B027", + "B029", "B9", "B90", "B904",