Consider with blocks as single-item branches (#12311)

## Summary

Ensures that, e.g., the following is not considered a
redefinition-without-use:

```python
import contextlib

foo = None
with contextlib.suppress(ImportError):
    from some_module import foo
```

Closes https://github.com/astral-sh/ruff/issues/12309.
This commit is contained in:
Charlie Marsh 2024-07-13 15:22:17 -04:00 committed by GitHub
parent 940df67823
commit 456d6a2fb2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 48 additions and 0 deletions

View file

@ -0,0 +1,21 @@
"""Regression test for: https://github.com/astral-sh/ruff/issues/12309"""
import contextlib
foo = None
with contextlib.suppress(ImportError):
from some_module import foo
bar = None
try:
from some_module import bar
except ImportError:
pass
try:
baz = None
from some_module import baz
except ImportError:
pass

View file

@ -928,6 +928,19 @@ impl<'a> Visitor<'a> for Checker<'a> {
self.visit_expr(expr); self.visit_expr(expr);
} }
} }
Stmt::With(ast::StmtWith {
items,
body,
is_async: _,
range: _,
}) => {
for item in items {
self.visit_with_item(item);
}
self.semantic.push_branch();
self.visit_body(body);
self.semantic.pop_branch();
}
Stmt::While(ast::StmtWhile { Stmt::While(ast::StmtWhile {
test, test,
body, body,

View file

@ -126,6 +126,7 @@ mod tests {
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_28.py"))] #[test_case(Rule::RedefinedWhileUnused, Path::new("F811_28.py"))]
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_29.pyi"))] #[test_case(Rule::RedefinedWhileUnused, Path::new("F811_29.pyi"))]
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_30.py"))] #[test_case(Rule::RedefinedWhileUnused, Path::new("F811_30.py"))]
#[test_case(Rule::RedefinedWhileUnused, Path::new("F811_31.py"))]
#[test_case(Rule::UndefinedName, Path::new("F821_0.py"))] #[test_case(Rule::UndefinedName, Path::new("F821_0.py"))]
#[test_case(Rule::UndefinedName, Path::new("F821_1.py"))] #[test_case(Rule::UndefinedName, Path::new("F821_1.py"))]
#[test_case(Rule::UndefinedName, Path::new("F821_2.py"))] #[test_case(Rule::UndefinedName, Path::new("F821_2.py"))]

View file

@ -0,0 +1,13 @@
---
source: crates/ruff_linter/src/rules/pyflakes/mod.rs
---
F811_31.py:19:29: F811 Redefinition of unused `baz` from line 17
|
17 | baz = None
18 |
19 | from some_module import baz
| ^^^ F811
20 | except ImportError:
21 | pass
|
= help: Remove definition: `baz`