Skip to content

Commit f213d1a

Browse files
committed
pyupgrade: tighten diagnostic range for UP024 tuples (#19696
1 parent c062aba commit f213d1a

4 files changed

Lines changed: 323 additions & 1 deletion

File tree

crates/ruff_linter/src/preview.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,3 +306,8 @@ pub(crate) const fn is_ble001_exc_info_suppression_enabled(settings: &LinterSett
306306
pub(crate) const fn is_py315_support_enabled(settings: &LinterSettings) -> bool {
307307
settings.preview.is_enabled()
308308
}
309+
310+
// https://github.com/astral-sh/ruff/pull/23013
311+
pub(crate) const fn is_up024_precise_highlighting_enabled(settings: &LinterSettings) -> bool {
312+
settings.preview.is_enabled()
313+
}

crates/ruff_linter/src/rules/pyupgrade/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,4 +466,17 @@ mod tests {
466466
assert_diagnostics!(diagnostics);
467467
Ok(())
468468
}
469+
470+
#[test]
471+
fn preview_up024() -> Result<()> {
472+
let diagnostics = test_path(
473+
Path::new("pyupgrade/UP024_0.py"),
474+
&settings::LinterSettings {
475+
preview: PreviewMode::Enabled,
476+
..settings::LinterSettings::for_rule(Rule::OSErrorAlias)
477+
},
478+
)?;
479+
assert_diagnostics!("UP024_preview", diagnostics);
480+
Ok(())
481+
}
469482
}

crates/ruff_linter/src/rules/pyupgrade/rules/os_error_alias.rs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use ruff_python_semantic::SemanticModel;
77

88
use crate::checkers::ast::Checker;
99
use crate::fix::edits::pad;
10+
use crate::preview::is_up024_precise_highlighting_enabled;
1011
use crate::{AlwaysFixableViolation, Edit, Fix};
1112

1213
/// ## What it does
@@ -93,7 +94,20 @@ fn atom_diagnostic(checker: &Checker, target: &Expr) {
9394

9495
/// Create a [`Diagnostic`] for a tuple of expressions.
9596
fn tuple_diagnostic(checker: &Checker, tuple: &ast::ExprTuple, aliases: &[&Expr]) {
96-
let mut diagnostic = checker.report_diagnostic(OSErrorAlias { name: None }, tuple.range());
97+
let Some(first_alias) = aliases.first() else {
98+
return;
99+
};
100+
let diagnostic_range = if is_up024_precise_highlighting_enabled(checker.settings()) {
101+
first_alias.range()
102+
} else {
103+
tuple.range()
104+
};
105+
let mut diagnostic = checker.report_diagnostic(OSErrorAlias { name: None }, diagnostic_range);
106+
if is_up024_precise_highlighting_enabled(checker.settings()) {
107+
for alias in aliases.iter().skip(1) {
108+
diagnostic.secondary_annotation("Also an OSError alias".to_string(), alias.range());
109+
}
110+
}
97111
let semantic = checker.semantic();
98112
if semantic.has_builtin_binding("OSError") {
99113
// Filter out any `OSErrors` aliases.
Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
---
2+
source: crates/ruff_linter/src/rules/pyupgrade/mod.rs
3+
---
4+
UP024 [*] Replace aliased errors with `OSError`
5+
--> UP024_0.py:6:8
6+
|
7+
4 | try:
8+
5 | pass
9+
6 | except EnvironmentError:
10+
| ^^^^^^^^^^^^^^^^
11+
7 | pass
12+
|
13+
help: Replace `EnvironmentError` with builtin `OSError`
14+
3 | # These should be fixed
15+
4 | try:
16+
5 | pass
17+
- except EnvironmentError:
18+
6 + except OSError:
19+
7 | pass
20+
8 |
21+
9 | try:
22+
23+
UP024 [*] Replace aliased errors with `OSError`
24+
--> UP024_0.py:11:8
25+
|
26+
9 | try:
27+
10 | pass
28+
11 | except IOError:
29+
| ^^^^^^^
30+
12 | pass
31+
|
32+
help: Replace `IOError` with builtin `OSError`
33+
8 |
34+
9 | try:
35+
10 | pass
36+
- except IOError:
37+
11 + except OSError:
38+
12 | pass
39+
13 |
40+
14 | try:
41+
42+
UP024 [*] Replace aliased errors with `OSError`
43+
--> UP024_0.py:16:8
44+
|
45+
14 | try:
46+
15 | pass
47+
16 | except WindowsError:
48+
| ^^^^^^^^^^^^
49+
17 | pass
50+
|
51+
help: Replace `WindowsError` with builtin `OSError`
52+
13 |
53+
14 | try:
54+
15 | pass
55+
- except WindowsError:
56+
16 + except OSError:
57+
17 | pass
58+
18 |
59+
19 | try:
60+
61+
UP024 [*] Replace aliased errors with `OSError`
62+
--> UP024_0.py:21:8
63+
|
64+
19 | try:
65+
20 | pass
66+
21 | except mmap.error:
67+
| ^^^^^^^^^^
68+
22 | pass
69+
|
70+
help: Replace `mmap.error` with builtin `OSError`
71+
18 |
72+
19 | try:
73+
20 | pass
74+
- except mmap.error:
75+
21 + except OSError:
76+
22 | pass
77+
23 |
78+
24 | try:
79+
80+
UP024 [*] Replace aliased errors with `OSError`
81+
--> UP024_0.py:26:8
82+
|
83+
24 | try:
84+
25 | pass
85+
26 | except select.error:
86+
| ^^^^^^^^^^^^
87+
27 | pass
88+
|
89+
help: Replace `select.error` with builtin `OSError`
90+
23 |
91+
24 | try:
92+
25 | pass
93+
- except select.error:
94+
26 + except OSError:
95+
27 | pass
96+
28 |
97+
29 | try:
98+
99+
UP024 [*] Replace aliased errors with `OSError`
100+
--> UP024_0.py:31:8
101+
|
102+
29 | try:
103+
30 | pass
104+
31 | except socket.error:
105+
| ^^^^^^^^^^^^
106+
32 | pass
107+
|
108+
help: Replace `socket.error` with builtin `OSError`
109+
28 |
110+
29 | try:
111+
30 | pass
112+
- except socket.error:
113+
31 + except OSError:
114+
32 | pass
115+
33 |
116+
34 | try:
117+
118+
UP024 [*] Replace aliased errors with `OSError`
119+
--> UP024_0.py:36:8
120+
|
121+
34 | try:
122+
35 | pass
123+
36 | except error:
124+
| ^^^^^
125+
37 | pass
126+
|
127+
help: Replace `error` with builtin `OSError`
128+
33 |
129+
34 | try:
130+
35 | pass
131+
- except error:
132+
36 + except OSError:
133+
37 | pass
134+
38 |
135+
39 | # Should NOT be in parentheses when replaced
136+
137+
UP024 [*] Replace aliased errors with `OSError`
138+
--> UP024_0.py:43:9
139+
|
140+
41 | try:
141+
42 | pass
142+
43 | except (IOError,):
143+
| ^^^^^^^
144+
44 | pass
145+
45 | try:
146+
|
147+
help: Replace with builtin `OSError`
148+
40 |
149+
41 | try:
150+
42 | pass
151+
- except (IOError,):
152+
43 + except OSError:
153+
44 | pass
154+
45 | try:
155+
46 | pass
156+
157+
UP024 [*] Replace aliased errors with `OSError`
158+
--> UP024_0.py:47:9
159+
|
160+
45 | try:
161+
46 | pass
162+
47 | except (mmap.error,):
163+
| ^^^^^^^^^^
164+
48 | pass
165+
49 | try:
166+
|
167+
help: Replace with builtin `OSError`
168+
44 | pass
169+
45 | try:
170+
46 | pass
171+
- except (mmap.error,):
172+
47 + except OSError:
173+
48 | pass
174+
49 | try:
175+
50 | pass
176+
177+
UP024 [*] Replace aliased errors with `OSError`
178+
--> UP024_0.py:51:9
179+
|
180+
49 | try:
181+
50 | pass
182+
51 | except (EnvironmentError, IOError, OSError, select.error):
183+
| ^^^^^^^^^^^^^^^^ ------- ------------ Also an OSError alias
184+
| |
185+
| Also an OSError alias
186+
52 | pass
187+
|
188+
help: Replace with builtin `OSError`
189+
48 | pass
190+
49 | try:
191+
50 | pass
192+
- except (EnvironmentError, IOError, OSError, select.error):
193+
51 + except OSError:
194+
52 | pass
195+
53 |
196+
54 | # Should be kept in parentheses (because multiple)
197+
198+
UP024 [*] Replace aliased errors with `OSError`
199+
--> UP024_0.py:58:9
200+
|
201+
56 | try:
202+
57 | pass
203+
58 | except (IOError, KeyError, OSError):
204+
| ^^^^^^^
205+
59 | pass
206+
|
207+
help: Replace with builtin `OSError`
208+
55 |
209+
56 | try:
210+
57 | pass
211+
- except (IOError, KeyError, OSError):
212+
58 + except (KeyError, OSError):
213+
59 | pass
214+
60 |
215+
61 | # First should change, second should not
216+
217+
UP024 [*] Replace aliased errors with `OSError`
218+
--> UP024_0.py:65:9
219+
|
220+
63 | try:
221+
64 | pass
222+
65 | except (IOError, error):
223+
| ^^^^^^^
224+
66 | pass
225+
67 | # These should not change
226+
|
227+
help: Replace with builtin `OSError`
228+
62 | from .mmap import error
229+
63 | try:
230+
64 | pass
231+
- except (IOError, error):
232+
65 + except (OSError, error):
233+
66 | pass
234+
67 | # These should not change
235+
68 |
236+
237+
UP024 [*] Replace aliased errors with `OSError`
238+
--> UP024_0.py:87:8
239+
|
240+
85 | try:
241+
86 | pass
242+
87 | except (mmap).error:
243+
| ^^^^^^^^^^^^
244+
88 | pass
245+
|
246+
help: Replace `mmap.error` with builtin `OSError`
247+
84 | pass
248+
85 | try:
249+
86 | pass
250+
- except (mmap).error:
251+
87 + except OSError:
252+
88 | pass
253+
89 |
254+
90 | try:
255+
256+
UP024 [*] Replace aliased errors with `OSError`
257+
--> UP024_0.py:105:12
258+
|
259+
103 | try:
260+
104 | mac_address = get_primary_mac_address()
261+
105 | except(IOError, OSError) as ex:
262+
| ^^^^^^^
263+
106 | msg = 'Unable to query URL to get Owner ID: {u}\n{e}'.format(u=owner_id_url, e=ex)
264+
|
265+
help: Replace with builtin `OSError`
266+
102 | def get_owner_id_from_mac_address():
267+
103 | try:
268+
104 | mac_address = get_primary_mac_address()
269+
- except(IOError, OSError) as ex:
270+
105 + except OSError as ex:
271+
106 | msg = 'Unable to query URL to get Owner ID: {u}\n{e}'.format(u=owner_id_url, e=ex)
272+
107 |
273+
108 |
274+
275+
UP024 [*] Replace aliased errors with `OSError`
276+
--> UP024_0.py:114:8
277+
|
278+
112 | try:
279+
113 | pass
280+
114 | except os.error:
281+
| ^^^^^^^^
282+
115 | pass
283+
|
284+
help: Replace `os.error` with builtin `OSError`
285+
111 |
286+
112 | try:
287+
113 | pass
288+
- except os.error:
289+
114 + except OSError:
290+
115 | pass

0 commit comments

Comments
 (0)