@@ -61,6 +61,76 @@ impl Violation for BlockingPathMethodInAsyncFunction {
6161 }
6262}
6363
64+ /// ASYNC240
65+ pub ( crate ) fn blocking_os_path ( checker : & Checker , call : & ExprCall ) {
66+ let semantic = checker. semantic ( ) ;
67+ if !semantic. in_async_context ( ) {
68+ return ;
69+ }
70+
71+ // Check if an expression is calling I/O related os.path method.
72+ // Just initializing pathlib.Path object is OK, we can return
73+ // early in that scenario.
74+ if let Some ( qualified_name) = semantic. resolve_qualified_name ( call. func . as_ref ( ) ) {
75+ let segments = qualified_name. segments ( ) ;
76+ if !matches ! ( segments, [ "os" , "path" , _] ) {
77+ return ;
78+ }
79+
80+ let Some ( os_path_method) = segments. last ( ) else {
81+ return ;
82+ } ;
83+
84+ if maybe_calling_io_operation ( os_path_method) {
85+ checker. report_diagnostic (
86+ BlockingPathMethodInAsyncFunction {
87+ path_library : "os.path" . to_string ( ) ,
88+ } ,
89+ call. func . range ( ) ,
90+ ) ;
91+ }
92+ return ;
93+ }
94+
95+ let Some ( ast:: ExprAttribute { value, attr, .. } ) = call. func . as_attribute_expr ( ) else {
96+ return ;
97+ } ;
98+
99+ if !maybe_calling_io_operation ( attr. id . as_str ( ) ) {
100+ return ;
101+ }
102+
103+ // Check if an expression is a pathlib.Path constructor that directly
104+ // calls an I/O method.
105+ if PathlibPathChecker :: match_initializer ( value, semantic) {
106+ checker. report_diagnostic (
107+ BlockingPathMethodInAsyncFunction {
108+ path_library : "pathlib.Path" . to_string ( ) ,
109+ } ,
110+ call. func . range ( ) ,
111+ ) ;
112+ return ;
113+ }
114+
115+ // Lastly, check if a variable is a pathlib.Path instance and it's
116+ // calling an I/O method.
117+ let Some ( name) = value. as_name_expr ( ) else {
118+ return ;
119+ } ;
120+
121+ let Some ( binding) = semantic. only_binding ( name) . map ( |id| semantic. binding ( id) ) else {
122+ return ;
123+ } ;
124+
125+ if check_type :: < PathlibPathChecker > ( binding, semantic) {
126+ checker. report_diagnostic (
127+ BlockingPathMethodInAsyncFunction {
128+ path_library : "pathlib.Path" . to_string ( ) ,
129+ } ,
130+ call. func . range ( ) ,
131+ ) ;
132+ }
133+ }
64134struct PathlibPathChecker ;
65135
66136impl PathlibPathChecker {
@@ -174,74 +244,3 @@ fn maybe_calling_io_operation(attr: &str) -> bool {
174244 | "with_suffix"
175245 )
176246}
177-
178- /// ASYNC240
179- pub ( crate ) fn blocking_os_path ( checker : & Checker , call : & ExprCall ) {
180- let semantic = checker. semantic ( ) ;
181- if !semantic. in_async_context ( ) {
182- return ;
183- }
184-
185- // Check if an expression is calling I/O related os.path method.
186- // Just initializing pathlib.Path object is OK, we can return
187- // early in that scenario.
188- if let Some ( qualified_name) = semantic. resolve_qualified_name ( call. func . as_ref ( ) ) {
189- let segments = qualified_name. segments ( ) ;
190- if !matches ! ( segments, [ "os" , "path" , _] ) {
191- return ;
192- }
193-
194- let Some ( os_path_method) = segments. last ( ) else {
195- return ;
196- } ;
197-
198- if maybe_calling_io_operation ( os_path_method) {
199- checker. report_diagnostic (
200- BlockingPathMethodInAsyncFunction {
201- path_library : "os.path" . to_string ( ) ,
202- } ,
203- call. func . range ( ) ,
204- ) ;
205- }
206- return ;
207- }
208-
209- let Some ( ast:: ExprAttribute { value, attr, .. } ) = call. func . as_attribute_expr ( ) else {
210- return ;
211- } ;
212-
213- if !maybe_calling_io_operation ( attr. id . as_str ( ) ) {
214- return ;
215- }
216-
217- // Check if an expression is a pathlib.Path constructor that directly
218- // calls an I/O method.
219- if PathlibPathChecker :: match_initializer ( value, semantic) {
220- checker. report_diagnostic (
221- BlockingPathMethodInAsyncFunction {
222- path_library : "pathlib.Path" . to_string ( ) ,
223- } ,
224- call. func . range ( ) ,
225- ) ;
226- return ;
227- }
228-
229- // Lastly, check if a variable is a pathlib.Path instance and it's
230- // calling an I/O method.
231- let Some ( name) = value. as_name_expr ( ) else {
232- return ;
233- } ;
234-
235- let Some ( binding) = semantic. only_binding ( name) . map ( |id| semantic. binding ( id) ) else {
236- return ;
237- } ;
238-
239- if check_type :: < PathlibPathChecker > ( binding, semantic) {
240- checker. report_diagnostic (
241- BlockingPathMethodInAsyncFunction {
242- path_library : "pathlib.Path" . to_string ( ) ,
243- } ,
244- call. func . range ( ) ,
245- ) ;
246- }
247- }
0 commit comments