Skip to content

Commit da16e00

Browse files
IDrokin117ntBre
andauthored
[pyupgrade] Extend version detection to include sys.version_info.major (UP036) (#18633)
## Summary Resolves #18165 Added pattern `["sys", "version_info", "major"]` to the existing matches for `sys.version_info` to ensure consistent handling of both the base object and its major version attribute. ## Test Plan `cargo nextest run` and `cargo insta test` --------- Co-authored-by: Brent Westbrook <brentrwestbrook@gmail.com>
1 parent 885dc90 commit da16e00

3 files changed

Lines changed: 181 additions & 8 deletions

File tree

crates/ruff_linter/resources/test/fixtures/pyupgrade/UP036_5.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,47 @@ def a():
7171

7272
if sys.version_info <= (3, 14, 15):
7373
print()
74+
75+
# https://github.com/astral-sh/ruff/issues/18165
76+
77+
if sys.version_info.major >= 3:
78+
print("3")
79+
else:
80+
print("2")
81+
82+
if sys.version_info.major > 3:
83+
print("3")
84+
else:
85+
print("2")
86+
87+
if sys.version_info.major <= 3:
88+
print("3")
89+
else:
90+
print("2")
91+
92+
if sys.version_info.major < 3:
93+
print("3")
94+
else:
95+
print("2")
96+
97+
if sys.version_info.major == 3:
98+
print("3")
99+
else:
100+
print("2")
101+
102+
# Semantically incorrect, skip fixing
103+
104+
if sys.version_info.major[1] > 3:
105+
print(3)
106+
else:
107+
print(2)
108+
109+
if sys.version_info.major > (3, 13):
110+
print(3)
111+
else:
112+
print(2)
113+
114+
if sys.version_info.major[:2] > (3, 13):
115+
print(3)
116+
else:
117+
print(2)

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use crate::checkers::ast::Checker;
1414
use crate::fix::edits::{adjust_indentation, delete_stmt};
1515
use crate::{Edit, Fix, FixAvailability, Violation};
1616
use ruff_python_ast::PythonVersion;
17+
use ruff_python_semantic::SemanticModel;
1718

1819
/// ## What it does
1920
/// Checks for conditional blocks gated on `sys.version_info` comparisons
@@ -103,14 +104,7 @@ pub(crate) fn outdated_version_block(checker: &Checker, stmt_if: &StmtIf) {
103104
continue;
104105
};
105106

106-
// Detect `sys.version_info`, along with slices (like `sys.version_info[:2]`).
107-
if !checker
108-
.semantic()
109-
.resolve_qualified_name(map_subscript(left))
110-
.is_some_and(|qualified_name| {
111-
matches!(qualified_name.segments(), ["sys", "version_info"])
112-
})
113-
{
107+
if !is_valid_version_info(checker.semantic(), left) {
114108
continue;
115109
}
116110

@@ -456,6 +450,21 @@ fn extract_version(elts: &[Expr]) -> Option<Vec<Int>> {
456450
Some(version)
457451
}
458452

453+
/// Returns `true` if the expression is related to `sys.version_info`.
454+
///
455+
/// This includes:
456+
/// - Direct access: `sys.version_info`
457+
/// - Subscript access: `sys.version_info[:2]`, `sys.version_info[0]`
458+
/// - Major version attribute: `sys.version_info.major`
459+
fn is_valid_version_info(semantic: &SemanticModel, left: &Expr) -> bool {
460+
semantic
461+
.resolve_qualified_name(map_subscript(left))
462+
.is_some_and(|name| matches!(name.segments(), ["sys", "version_info"]))
463+
|| semantic
464+
.resolve_qualified_name(left)
465+
.is_some_and(|name| matches!(name.segments(), ["sys", "version_info", "major"]))
466+
}
467+
459468
#[cfg(test)]
460469
mod tests {
461470
use test_case::test_case;

crates/ruff_linter/src/rules/pyupgrade/snapshots/ruff_linter__rules__pyupgrade__tests__UP036_5.py.snap

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,123 @@ UP036_5.py:48:24: UP036 Version specifier is invalid
157157
| ^^^^^^^^^^^^^^^ UP036
158158
49 | print()
159159
|
160+
161+
UP036_5.py:77:4: UP036 [*] Version block is outdated for minimum Python version
162+
|
163+
75 | # https://github.com/astral-sh/ruff/issues/18165
164+
76 |
165+
77 | if sys.version_info.major >= 3:
166+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP036
167+
78 | print("3")
168+
79 | else:
169+
|
170+
= help: Remove outdated version block
171+
172+
Unsafe fix
173+
74 74 |
174+
75 75 | # https://github.com/astral-sh/ruff/issues/18165
175+
76 76 |
176+
77 |-if sys.version_info.major >= 3:
177+
78 |- print("3")
178+
79 |-else:
179+
80 |- print("2")
180+
77 |+print("3")
181+
81 78 |
182+
82 79 | if sys.version_info.major > 3:
183+
83 80 | print("3")
184+
185+
UP036_5.py:82:4: UP036 [*] Version block is outdated for minimum Python version
186+
|
187+
80 | print("2")
188+
81 |
189+
82 | if sys.version_info.major > 3:
190+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP036
191+
83 | print("3")
192+
84 | else:
193+
|
194+
= help: Remove outdated version block
195+
196+
Unsafe fix
197+
79 79 | else:
198+
80 80 | print("2")
199+
81 81 |
200+
82 |-if sys.version_info.major > 3:
201+
83 |- print("3")
202+
84 |-else:
203+
85 |- print("2")
204+
82 |+print("2")
205+
86 83 |
206+
87 84 | if sys.version_info.major <= 3:
207+
88 85 | print("3")
208+
209+
UP036_5.py:87:4: UP036 [*] Version block is outdated for minimum Python version
210+
|
211+
85 | print("2")
212+
86 |
213+
87 | if sys.version_info.major <= 3:
214+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP036
215+
88 | print("3")
216+
89 | else:
217+
|
218+
= help: Remove outdated version block
219+
220+
Unsafe fix
221+
84 84 | else:
222+
85 85 | print("2")
223+
86 86 |
224+
87 |-if sys.version_info.major <= 3:
225+
88 |- print("3")
226+
89 |-else:
227+
90 |- print("2")
228+
87 |+print("3")
229+
91 88 |
230+
92 89 | if sys.version_info.major < 3:
231+
93 90 | print("3")
232+
233+
UP036_5.py:92:4: UP036 [*] Version block is outdated for minimum Python version
234+
|
235+
90 | print("2")
236+
91 |
237+
92 | if sys.version_info.major < 3:
238+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ UP036
239+
93 | print("3")
240+
94 | else:
241+
|
242+
= help: Remove outdated version block
243+
244+
Unsafe fix
245+
89 89 | else:
246+
90 90 | print("2")
247+
91 91 |
248+
92 |-if sys.version_info.major < 3:
249+
93 |- print("3")
250+
94 |-else:
251+
95 |- print("2")
252+
92 |+print("2")
253+
96 93 |
254+
97 94 | if sys.version_info.major == 3:
255+
98 95 | print("3")
256+
257+
UP036_5.py:97:4: UP036 [*] Version block is outdated for minimum Python version
258+
|
259+
95 | print("2")
260+
96 |
261+
97 | if sys.version_info.major == 3:
262+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP036
263+
98 | print("3")
264+
99 | else:
265+
|
266+
= help: Remove outdated version block
267+
268+
Unsafe fix
269+
94 94 | else:
270+
95 95 | print("2")
271+
96 96 |
272+
97 |-if sys.version_info.major == 3:
273+
98 |- print("3")
274+
99 |-else:
275+
100 |- print("2")
276+
97 |+print("3")
277+
101 98 |
278+
102 99 | # Semantically incorrect, skip fixing
279+
103 100 |

0 commit comments

Comments
 (0)