Skip to content

Commit fc6a4ec

Browse files
committed
Address code reviews.
This commit contains changes addressing some code reviews: - Updated `maybe_calling_io_operation` to have a more complete allow list. - ASYNC230 already handles `path.open()` case, so it is added to the allow list. There is a new test for that. - Fix typo.
1 parent 2fa4dcb commit fc6a4ec

File tree

3 files changed

+92
-110
lines changed

3 files changed

+92
-110
lines changed

crates/ruff_linter/resources/test/fixtures/flake8_async/ASYNC240.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ async def anyio_path_in_foo():
5555
with Path("src/my_text.txt").open() as f: # OK
5656
...
5757

58+
async def path_open_in_foo():
59+
path = Path("src/my_text.txt") # OK
60+
path.open() # OK, covered by ASYNC230
61+
5862
## Invalid cases:
5963

6064
async def os_path_in_foo():
@@ -66,22 +70,16 @@ async def os_path_in_foo():
6670
async def pathlib_path_in_foo():
6771
path = Path("src/my_text.txt")
6872
path.exists() # ASYNC240
69-
with path.open() as f: # ASYNC240
70-
...
7173

7274
async def pathlib_path_in_foo():
7375
import pathlib
7476

7577
path = pathlib.Path("src/my_text.txt")
7678
path.exists() # ASYNC240
77-
with path.open() as f: # ASYNC240
78-
...
7979

8080
async def inline_path_method_call():
81-
Path("src/my_text.txt").open() # ASYNC240
82-
Path("src/my_text.txt").open().flush() # ASYNC240
83-
with Path("src/my_text.txt").open() as f: # ASYNC240
84-
...
81+
Path("src/my_text.txt").exists() # ASYNC240
82+
Path("src/my_text.txt").absolute().exists() # ASYNC240
8583

8684
async def aliased_path_in_foo():
8785
from pathlib import Path as PathAlias

crates/ruff_linter/src/rules/flake8_async/rules/blocking_path_methods.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -119,44 +119,59 @@ impl TypeChecker for PathlibPathChecker {
119119
}
120120

121121
fn maybe_calling_io_operation(attr: &str) -> bool {
122+
// ".open()" is added to the allow list to let ASYNC 230 handle
123+
// that case.
122124
!matches!(
123125
attr,
124-
// Pure path objects provide path-handling operations which don’t actually
125-
// access a filesystem.
126-
// https://docs.python.org/3/library/pathlib.html#pure-paths
127-
// pathlib.PurePath methods and properties:
128-
"anchor"
126+
"ALLOW_MISSING"
127+
| "altsep"
128+
| "anchor"
129129
| "as_posix"
130130
| "as_uri"
131+
| "basename"
132+
| "commonpath"
133+
| "commonprefix"
134+
| "curdir"
135+
| "defpath"
136+
| "devnull"
137+
| "dirname"
131138
| "drive"
139+
| "expandvars"
140+
| "extsep"
141+
| "genericpath"
132142
| "is_absolute"
133143
| "is_relative_to"
134144
| "is_reserved"
145+
| "isabs"
146+
| "join"
135147
| "joinpath"
136148
| "match"
137149
| "name"
150+
| "normcase"
151+
| "os"
152+
| "open"
153+
| "pardir"
138154
| "parent"
139155
| "parents"
140156
| "parts"
157+
| "pathsep"
141158
| "relative_to"
142159
| "root"
160+
| "samestat"
161+
| "sep"
162+
| "split"
163+
| "splitdrive"
164+
| "splitext"
165+
| "splitroot"
143166
| "stem"
144167
| "suffix"
145168
| "suffixes"
169+
| "supports_unicode_filenames"
170+
| "sys"
146171
| "with_name"
147172
| "with_segments"
148173
| "with_stem"
149174
| "with_suffix"
150-
// Non I/O pathlib.Path or os.path methods:
151-
| "join"
152-
| "dirname"
153-
| "basename"
154-
| "splitroot"
155-
| "splitdrive"
156-
| "splitext"
157-
| "split"
158-
| "isabs"
159-
| "normcase"
160175
)
161176
}
162177

@@ -168,7 +183,7 @@ pub(crate) fn blocking_os_path(checker: &Checker, call: &ExprCall) {
168183
}
169184

170185
// Check if an expression is calling I/O related os.path method.
171-
// Just intializing pathlib.Path object is OK, we can return
186+
// Just initializing pathlib.Path object is OK, we can return
172187
// early in that scenario.
173188
if let Some(qualified_name) = semantic.resolve_qualified_name(call.func.as_ref()) {
174189
let segments = qualified_name.segments();

crates/ruff_linter/src/rules/flake8_async/snapshots/ruff_linter__rules__flake8_async__tests__ASYNC240_ASYNC240.py.snap

Lines changed: 55 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -2,141 +2,110 @@
22
source: crates/ruff_linter/src/rules/flake8_async/mod.rs
33
---
44
ASYNC240 Async functions should not use os.path methods, use trio.Path or anyio.path
5-
--> ASYNC240.py:63:5
5+
--> ASYNC240.py:67:5
66
|
7-
61 | file = "file.txt"
8-
62 |
9-
63 | os.path.abspath(file) # ASYNC240
7+
65 | file = "file.txt"
8+
66 |
9+
67 | os.path.abspath(file) # ASYNC240
1010
| ^^^^^^^^^^^^^^^
11-
64 | os.path.exists(file) # ASYNC240
11+
68 | os.path.exists(file) # ASYNC240
1212
|
1313

1414
ASYNC240 Async functions should not use os.path methods, use trio.Path or anyio.path
15-
--> ASYNC240.py:64:5
15+
--> ASYNC240.py:68:5
1616
|
17-
63 | os.path.abspath(file) # ASYNC240
18-
64 | os.path.exists(file) # ASYNC240
17+
67 | os.path.abspath(file) # ASYNC240
18+
68 | os.path.exists(file) # ASYNC240
1919
| ^^^^^^^^^^^^^^
20-
65 |
21-
66 | async def pathlib_path_in_foo():
20+
69 |
21+
70 | async def pathlib_path_in_foo():
2222
|
2323

2424
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
25-
--> ASYNC240.py:68:5
25+
--> ASYNC240.py:72:5
2626
|
27-
66 | async def pathlib_path_in_foo():
28-
67 | path = Path("src/my_text.txt")
29-
68 | path.exists() # ASYNC240
27+
70 | async def pathlib_path_in_foo():
28+
71 | path = Path("src/my_text.txt")
29+
72 | path.exists() # ASYNC240
3030
| ^^^^^^^^^^^
31-
69 | with path.open() as f: # ASYNC240
32-
70 | ...
33-
|
34-
35-
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
36-
--> ASYNC240.py:69:10
37-
|
38-
67 | path = Path("src/my_text.txt")
39-
68 | path.exists() # ASYNC240
40-
69 | with path.open() as f: # ASYNC240
41-
| ^^^^^^^^^
42-
70 | ...
31+
73 |
32+
74 | async def pathlib_path_in_foo():
4333
|
4434

4535
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
46-
--> ASYNC240.py:76:5
36+
--> ASYNC240.py:78:5
4737
|
48-
75 | path = pathlib.Path("src/my_text.txt")
49-
76 | path.exists() # ASYNC240
38+
77 | path = pathlib.Path("src/my_text.txt")
39+
78 | path.exists() # ASYNC240
5040
| ^^^^^^^^^^^
51-
77 | with path.open() as f: # ASYNC240
52-
78 | ...
53-
|
54-
55-
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
56-
--> ASYNC240.py:77:10
57-
|
58-
75 | path = pathlib.Path("src/my_text.txt")
59-
76 | path.exists() # ASYNC240
60-
77 | with path.open() as f: # ASYNC240
61-
| ^^^^^^^^^
62-
78 | ...
41+
79 |
42+
80 | async def inline_path_method_call():
6343
|
6444

6545
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
6646
--> ASYNC240.py:81:5
6747
|
6848
80 | async def inline_path_method_call():
69-
81 | Path("src/my_text.txt").open() # ASYNC240
70-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
71-
82 | Path("src/my_text.txt").open().flush() # ASYNC240
72-
83 | with Path("src/my_text.txt").open() as f: # ASYNC240
49+
81 | Path("src/my_text.txt").exists() # ASYNC240
50+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
51+
82 | Path("src/my_text.txt").absolute().exists() # ASYNC240
7352
|
7453

7554
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
7655
--> ASYNC240.py:82:5
7756
|
7857
80 | async def inline_path_method_call():
79-
81 | Path("src/my_text.txt").open() # ASYNC240
80-
82 | Path("src/my_text.txt").open().flush() # ASYNC240
81-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
82-
83 | with Path("src/my_text.txt").open() as f: # ASYNC240
83-
84 | ...
58+
81 | Path("src/my_text.txt").exists() # ASYNC240
59+
82 | Path("src/my_text.txt").absolute().exists() # ASYNC240
60+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
61+
83 |
62+
84 | async def aliased_path_in_foo():
8463
|
8564

8665
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
87-
--> ASYNC240.py:83:10
66+
--> ASYNC240.py:88:5
8867
|
89-
81 | Path("src/my_text.txt").open() # ASYNC240
90-
82 | Path("src/my_text.txt").open().flush() # ASYNC240
91-
83 | with Path("src/my_text.txt").open() as f: # ASYNC240
92-
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
93-
84 | ...
94-
|
95-
96-
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
97-
--> ASYNC240.py:90:5
98-
|
99-
89 | path = PathAlias("src/my_text.txt")
100-
90 | path.exists() # ASYNC240
68+
87 | path = PathAlias("src/my_text.txt")
69+
88 | path.exists() # ASYNC240
10170
| ^^^^^^^^^^^
102-
91 |
103-
92 | global_path = Path("src/my_text.txt")
71+
89 |
72+
90 | global_path = Path("src/my_text.txt")
10473
|
10574

10675
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
107-
--> ASYNC240.py:95:5
76+
--> ASYNC240.py:93:5
10877
|
109-
94 | async def global_path_in_foo():
110-
95 | global_path.exists() # ASYNC240
78+
92 | async def global_path_in_foo():
79+
93 | global_path.exists() # ASYNC240
11180
| ^^^^^^^^^^^^^^^^^^
112-
96 |
113-
97 | async def path_as_simple_parameter_type(path: Path):
81+
94 |
82+
95 | async def path_as_simple_parameter_type(path: Path):
11483
|
11584

11685
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
117-
--> ASYNC240.py:98:5
118-
|
119-
97 | async def path_as_simple_parameter_type(path: Path):
120-
98 | path.exists() # ASYNC240
121-
| ^^^^^^^^^^^
122-
99 |
123-
100 | async def path_as_union_parameter_type(path: Path | None):
124-
|
86+
--> ASYNC240.py:96:5
87+
|
88+
95 | async def path_as_simple_parameter_type(path: Path):
89+
96 | path.exists() # ASYNC240
90+
| ^^^^^^^^^^^
91+
97 |
92+
98 | async def path_as_union_parameter_type(path: Path | None):
93+
|
12594

12695
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
127-
--> ASYNC240.py:101:5
96+
--> ASYNC240.py:99:5
12897
|
129-
100 | async def path_as_union_parameter_type(path: Path | None):
130-
101 | path.exists() # ASYNC240
98+
98 | async def path_as_union_parameter_type(path: Path | None):
99+
99 | path.exists() # ASYNC240
131100
| ^^^^^^^^^^^
132-
102 |
133-
103 | async def path_as_optional_parameter_type(path: Optional[Path]):
101+
100 |
102+
101 | async def path_as_optional_parameter_type(path: Optional[Path]):
134103
|
135104

136105
ASYNC240 Async functions should not use pathlib.Path methods, use trio.Path or anyio.path
137-
--> ASYNC240.py:104:5
106+
--> ASYNC240.py:102:5
138107
|
139-
103 | async def path_as_optional_parameter_type(path: Optional[Path]):
140-
104 | path.exists() # ASYNC240
108+
101 | async def path_as_optional_parameter_type(path: Optional[Path]):
109+
102 | path.exists() # ASYNC240
141110
| ^^^^^^^^^^^
142111
|

0 commit comments

Comments
 (0)