@@ -114,6 +114,28 @@ fn match_exit_stack(semantic: &SemanticModel) -> bool {
114
114
false
115
115
}
116
116
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
+
117
139
/// Return `true` if the expression is a call to `open()`,
118
140
/// or a call to some other standard-library function that opens a file.
119
141
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
229
251
return ;
230
252
}
231
253
254
+ // Ex) `self.enterContext(open("foo.txt"))`
255
+ if match_unittest_context_methods ( semantic) {
256
+ return ;
257
+ }
258
+
232
259
// Ex) `def __enter__(self): ...`
233
260
if let ScopeKind :: Function ( ast:: StmtFunctionDef { name, .. } ) =
234
261
& checker. semantic ( ) . current_scope ( ) . kind
0 commit comments