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