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")
|
exception("An error occurred")
|
||||||
else:
|
else:
|
||||||
exception("An error occurred")
|
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
|
/// BLE001
|
||||||
pub(crate) fn blind_except(
|
pub(crate) fn blind_except(
|
||||||
checker: &Checker,
|
checker: &Checker,
|
||||||
|
|
@ -87,12 +103,9 @@ pub(crate) fn blind_except(
|
||||||
};
|
};
|
||||||
|
|
||||||
let semantic = checker.semantic();
|
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;
|
return;
|
||||||
};
|
};
|
||||||
if !matches!(builtin_exception_type, "BaseException" | "Exception") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the exception is re-raised, don't flag an error.
|
// If the exception is re-raised, don't flag an error.
|
||||||
let mut visitor = ReraiseVisitor::new(name);
|
let mut visitor = ReraiseVisitor::new(name);
|
||||||
|
|
@ -110,9 +123,9 @@ pub(crate) fn blind_except(
|
||||||
|
|
||||||
checker.report_diagnostic(
|
checker.report_diagnostic(
|
||||||
BlindExcept {
|
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
|
| ^^^^^^^^^ BLE001
|
||||||
132 | critical("...", exc_info=None)
|
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