Skip to content

Commit 1288243

Browse files
Exempt unittest context methods for SIM115 rule
co-authored-by: Alex Waygood <Alex.Waygood@Gmail.com>
1 parent 09d0b22 commit 1288243

File tree

2 files changed

+46
-0
lines changed

2 files changed

+46
-0
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_simplify/SIM115.py

+19
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,22 @@ def func(filepath, encoding):
264264
# OK
265265
def func(filepath, encoding):
266266
return f(open(filepath, mode="rt", encoding=encoding))
267+
268+
269+
from unittest import IsolatedAsyncioTestCase, TestCase
270+
271+
# OK
272+
class ExampleClassTests(TestCase):
273+
@classmethod
274+
def setUpClass(cls):
275+
cls.enterClassContext(open("filename"))
276+
277+
# OK
278+
class ExampleAsyncTests(IsolatedAsyncioTestCase):
279+
async def test_something(self):
280+
await self.enterAsyncContext(open("filename"))
281+
282+
# OK
283+
class ExampleTests(TestCase):
284+
def setUp(self):
285+
self.enterContext(open("filename"))

crates/ruff_linter/src/rules/flake8_simplify/rules/open_file_with_context_handler.rs

+27
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,28 @@ fn match_exit_stack(semantic: &SemanticModel) -> bool {
114114
false
115115
}
116116

117+
/// Return `true` if the current expression is nested in a call to one of the
118+
/// unittest context manager methods: `cls.enterClassContext()`,
119+
/// `self.enterContext()`, or `self.enterAsyncContext()`.
120+
fn match_unittest_context_methods(semantic: &SemanticModel) -> bool {
121+
let Some(expr) = semantic.current_expression_parent() else {
122+
return false;
123+
};
124+
let Expr::Call(ast::ExprCall { func, .. }) = expr else {
125+
return false;
126+
};
127+
let Expr::Attribute(ast::ExprAttribute { attr, value, .. }) = func.as_ref() else {
128+
return false;
129+
};
130+
let Expr::Name(ast::ExprName { id, .. }) = value.as_ref() else {
131+
return false;
132+
};
133+
matches!(
134+
(id.as_str(), attr.as_str()),
135+
("cls", "enterClassContext") | ("self", "enterContext" | "enterAsyncContext")
136+
)
137+
}
138+
117139
/// Return `true` if the expression is a call to `open()`,
118140
/// or a call to some other standard-library function that opens a file.
119141
fn is_open_call(semantic: &SemanticModel, call: &ast::ExprCall) -> bool {
@@ -229,6 +251,11 @@ pub(crate) fn open_file_with_context_handler(checker: &Checker, call: &ast::Expr
229251
return;
230252
}
231253

254+
// Ex) `self.enterContext(open("foo.txt"))`
255+
if match_unittest_context_methods(semantic) {
256+
return;
257+
}
258+
232259
// Ex) `def __enter__(self): ...`
233260
if let ScopeKind::Function(ast::StmtFunctionDef { name, .. }) =
234261
&checker.semantic().current_scope().kind

0 commit comments

Comments
 (0)