mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-29 03:02:27 +00:00
[flake8-blind-except] Change BLE001 to correctly parse exception tuples (#19747)
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
Some checks are pending
CI / Determine changes (push) Waiting to run
CI / cargo fmt (push) Waiting to run
CI / cargo clippy (push) Blocked by required conditions
CI / cargo test (linux) (push) Blocked by required conditions
CI / cargo test (linux, release) (push) Blocked by required conditions
CI / cargo test (windows) (push) Blocked by required conditions
CI / cargo test (wasm) (push) Blocked by required conditions
CI / cargo build (release) (push) Waiting to run
CI / cargo build (msrv) (push) Blocked by required conditions
CI / cargo fuzz build (push) Blocked by required conditions
CI / fuzz parser (push) Blocked by required conditions
CI / test scripts (push) Blocked by required conditions
CI / ecosystem (push) Blocked by required conditions
CI / Fuzz for new ty panics (push) Blocked by required conditions
CI / cargo shear (push) Blocked by required conditions
CI / python package (push) Waiting to run
CI / pre-commit (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / formatter instabilities and black similarity (push) Blocked by required conditions
CI / test ruff-lsp (push) Blocked by required conditions
CI / check playground (push) Blocked by required conditions
CI / benchmarks-instrumented (push) Blocked by required conditions
CI / benchmarks-walltime (push) Blocked by required conditions
[ty Playground] Release / publish (push) Waiting to run
## Summary
This PR enhances the `BLE001` rule to correctly detect blind exception
handling in tuple exceptions. Previously, the rule only checked single
exception types, but Python allows catching multiple exceptions using
tuples like `except (Exception, ValueError):`.
## Test Plan
It fails the following (whereas the main branch does not):
```bash
cargo run -p ruff -- check somefile.py --no-cache --select=BLE001
```
```python
# somefile.py
try:
1/0
except (ValueError, Exception) as e:
print(e)
```
```
somefile.py:3:21: BLE001 Do not catch blind exception: `Exception`
|
1 | try:
2 | 1/0
3 | except (ValueError, Exception) as e:
| ^^^^^^^^^ BLE001
4 | print(e)
|
Found 1 error.
```
This commit is contained in:
parent
3a9341f7be
commit
b0f01ba514
3 changed files with 192 additions and 6 deletions
|
|
@ -162,3 +162,86 @@ except Exception:
|
|||
exception("An error occurred")
|
||||
else:
|
||||
exception("An error occurred")
|
||||
|
||||
# Test tuple exceptions
|
||||
try:
|
||||
pass
|
||||
except (Exception,):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception, ValueError):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, Exception):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, Exception) as e:
|
||||
print(e)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (BaseException, TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (TypeError, BaseException):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception, BaseException):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (BaseException, Exception):
|
||||
pass
|
||||
|
||||
# Test nested tuples
|
||||
try:
|
||||
pass
|
||||
except ((Exception, ValueError), TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (ValueError, (BaseException, TypeError)):
|
||||
pass
|
||||
|
||||
# Test valid tuple exceptions (should not trigger)
|
||||
try:
|
||||
pass
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (OSError, FileNotFoundError):
|
||||
pass
|
||||
|
||||
try:
|
||||
pass
|
||||
except (OSError, FileNotFoundError) as e:
|
||||
print(e)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception, ValueError):
|
||||
critical("...", exc_info=True)
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception, ValueError):
|
||||
raise
|
||||
|
||||
try:
|
||||
pass
|
||||
except (Exception, ValueError) as e:
|
||||
raise e
|
||||
|
|
|
|||
|
|
@ -75,6 +75,22 @@ impl Violation for BlindExcept {
|
|||
}
|
||||
}
|
||||
|
||||
fn contains_blind_exception<'a>(
|
||||
semantic: &'a SemanticModel,
|
||||
expr: &'a Expr,
|
||||
) -> Option<(&'a str, ruff_text_size::TextRange)> {
|
||||
match expr {
|
||||
Expr::Tuple(ast::ExprTuple { elts, .. }) => elts
|
||||
.iter()
|
||||
.find_map(|elt| contains_blind_exception(semantic, elt)),
|
||||
_ => {
|
||||
let builtin_exception_type = semantic.resolve_builtin_symbol(expr)?;
|
||||
matches!(builtin_exception_type, "BaseException" | "Exception")
|
||||
.then(|| (builtin_exception_type, expr.range()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// BLE001
|
||||
pub(crate) fn blind_except(
|
||||
checker: &Checker,
|
||||
|
|
@ -87,12 +103,9 @@ pub(crate) fn blind_except(
|
|||
};
|
||||
|
||||
let semantic = checker.semantic();
|
||||
let Some(builtin_exception_type) = semantic.resolve_builtin_symbol(type_) else {
|
||||
let Some((builtin_exception_type, range)) = contains_blind_exception(semantic, type_) else {
|
||||
return;
|
||||
};
|
||||
if !matches!(builtin_exception_type, "BaseException" | "Exception") {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the exception is re-raised, don't flag an error.
|
||||
let mut visitor = ReraiseVisitor::new(name);
|
||||
|
|
@ -110,9 +123,9 @@ pub(crate) fn blind_except(
|
|||
|
||||
checker.report_diagnostic(
|
||||
BlindExcept {
|
||||
name: builtin_exception_type.to_string(),
|
||||
name: builtin_exception_type.into(),
|
||||
},
|
||||
type_.range(),
|
||||
range,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -147,3 +147,93 @@ BLE.py:131:8: BLE001 Do not catch blind exception: `Exception`
|
|||
| ^^^^^^^^^ BLE001
|
||||
132 | critical("...", exc_info=None)
|
||||
|
|
||||
|
||||
BLE.py:169:9: BLE001 Do not catch blind exception: `Exception`
|
||||
|
|
||||
167 | try:
|
||||
168 | pass
|
||||
169 | except (Exception,):
|
||||
| ^^^^^^^^^ BLE001
|
||||
170 | pass
|
||||
|
|
||||
|
||||
BLE.py:174:9: BLE001 Do not catch blind exception: `Exception`
|
||||
|
|
||||
172 | try:
|
||||
173 | pass
|
||||
174 | except (Exception, ValueError):
|
||||
| ^^^^^^^^^ BLE001
|
||||
175 | pass
|
||||
|
|
||||
|
||||
BLE.py:179:21: BLE001 Do not catch blind exception: `Exception`
|
||||
|
|
||||
177 | try:
|
||||
178 | pass
|
||||
179 | except (ValueError, Exception):
|
||||
| ^^^^^^^^^ BLE001
|
||||
180 | pass
|
||||
|
|
||||
|
||||
BLE.py:184:21: BLE001 Do not catch blind exception: `Exception`
|
||||
|
|
||||
182 | try:
|
||||
183 | pass
|
||||
184 | except (ValueError, Exception) as e:
|
||||
| ^^^^^^^^^ BLE001
|
||||
185 | print(e)
|
||||
|
|
||||
|
||||
BLE.py:189:9: BLE001 Do not catch blind exception: `BaseException`
|
||||
|
|
||||
187 | try:
|
||||
188 | pass
|
||||
189 | except (BaseException, TypeError):
|
||||
| ^^^^^^^^^^^^^ BLE001
|
||||
190 | pass
|
||||
|
|
||||
|
||||
BLE.py:194:20: BLE001 Do not catch blind exception: `BaseException`
|
||||
|
|
||||
192 | try:
|
||||
193 | pass
|
||||
194 | except (TypeError, BaseException):
|
||||
| ^^^^^^^^^^^^^ BLE001
|
||||
195 | pass
|
||||
|
|
||||
|
||||
BLE.py:199:9: BLE001 Do not catch blind exception: `Exception`
|
||||
|
|
||||
197 | try:
|
||||
198 | pass
|
||||
199 | except (Exception, BaseException):
|
||||
| ^^^^^^^^^ BLE001
|
||||
200 | pass
|
||||
|
|
||||
|
||||
BLE.py:204:9: BLE001 Do not catch blind exception: `BaseException`
|
||||
|
|
||||
202 | try:
|
||||
203 | pass
|
||||
204 | except (BaseException, Exception):
|
||||
| ^^^^^^^^^^^^^ BLE001
|
||||
205 | pass
|
||||
|
|
||||
|
||||
BLE.py:210:10: BLE001 Do not catch blind exception: `Exception`
|
||||
|
|
||||
208 | try:
|
||||
209 | pass
|
||||
210 | except ((Exception, ValueError), TypeError):
|
||||
| ^^^^^^^^^ BLE001
|
||||
211 | pass
|
||||
|
|
||||
|
||||
BLE.py:215:22: BLE001 Do not catch blind exception: `BaseException`
|
||||
|
|
||||
213 | try:
|
||||
214 | pass
|
||||
215 | except (ValueError, (BaseException, TypeError)):
|
||||
| ^^^^^^^^^^^^^ BLE001
|
||||
216 | pass
|
||||
|
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue