@@ -2,7 +2,7 @@ use ruff_python_ast::{self as ast, Expr, Stmt};
2
2
3
3
use ruff_diagnostics:: { Diagnostic , Violation } ;
4
4
use ruff_macros:: { derive_message_formats, violation} ;
5
- use ruff_python_semantic:: SemanticModel ;
5
+ use ruff_python_semantic:: { ScopeKind , SemanticModel } ;
6
6
use ruff_text_size:: Ranged ;
7
7
8
8
use crate :: checkers:: ast:: Checker ;
@@ -114,24 +114,27 @@ fn match_exit_stack(semantic: &SemanticModel) -> bool {
114
114
115
115
/// Return `true` if `func` is the builtin `open` or `pathlib.Path(...).open`.
116
116
fn is_open ( semantic : & SemanticModel , func : & Expr ) -> bool {
117
- // open(...)
117
+ // Ex) ` open(...)`
118
118
if semantic. match_builtin_expr ( func, "open" ) {
119
119
return true ;
120
120
}
121
121
122
- // pathlib.Path(...).open()
122
+ // Ex) ` pathlib.Path(...).open()`
123
123
let Expr :: Attribute ( ast:: ExprAttribute { attr, value, .. } ) = func else {
124
124
return false ;
125
125
} ;
126
+
126
127
if attr != "open" {
127
128
return false ;
128
129
}
130
+
129
131
let Expr :: Call ( ast:: ExprCall {
130
132
func : value_func, ..
131
133
} ) = & * * value
132
134
else {
133
135
return false ;
134
136
} ;
137
+
135
138
semantic
136
139
. resolve_qualified_name ( value_func)
137
140
. is_some_and ( |qualified_name| matches ! ( qualified_name. segments( ) , [ "pathlib" , "Path" ] ) )
@@ -189,6 +192,15 @@ pub(crate) fn open_file_with_context_handler(checker: &mut Checker, func: &Expr)
189
192
return ;
190
193
}
191
194
195
+ // Ex) `def __enter__(self): ...`
196
+ if let ScopeKind :: Function ( ast:: StmtFunctionDef { name, .. } ) =
197
+ & checker. semantic ( ) . current_scope ( ) . kind
198
+ {
199
+ if name == "__enter__" {
200
+ return ;
201
+ }
202
+ }
203
+
192
204
checker
193
205
. diagnostics
194
206
. push ( Diagnostic :: new ( OpenFileWithContextHandler , func. range ( ) ) ) ;
0 commit comments