Skip to content

Commit a3638b3

Browse files
robsdedudentBre
andauthored
[pyupgrade] Mark UP008 fix safe if no comments in range (#18683)
<!-- Thank you for contributing to Ruff/ty! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? (Please prefix with `[ty]` for ty pull requests.) - Does this pull request include references to any relevant issues? --> ## Summary Mark `UP008`'s fix safe if it won't delete comments. ## Relevant Issues Fixes: #18533 --------- Co-authored-by: Brent Westbrook <36778786+ntBre@users.noreply.github.com>
1 parent f857546 commit a3638b3

File tree

6 files changed

+402
-5
lines changed

6 files changed

+402
-5
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,23 @@ def f(self):
105105
class C:
106106
def f(self):
107107
builtins.super(C, self)
108+
109+
110+
# see: https://github.com/astral-sh/ruff/issues/18533
111+
class ClassForCommentEnthusiasts(BaseClass):
112+
def with_comments(self):
113+
super(
114+
# super helpful comment
115+
ClassForCommentEnthusiasts,
116+
self
117+
).f()
118+
super(
119+
ClassForCommentEnthusiasts,
120+
# even more helpful comment
121+
self
122+
).f()
123+
super(
124+
ClassForCommentEnthusiasts,
125+
self
126+
# also a comment
127+
).f()

crates/ruff_linter/src/preview.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,3 +104,10 @@ pub(crate) const fn is_invalid_async_mock_access_check_enabled(settings: &Linter
104104
pub(crate) const fn is_raise_exception_byte_string_enabled(settings: &LinterSettings) -> bool {
105105
settings.preview.is_enabled()
106106
}
107+
108+
// https://github.com/astral-sh/ruff/pull/18683
109+
pub(crate) const fn is_safe_super_call_with_parameters_fix_enabled(
110+
settings: &LinterSettings,
111+
) -> bool {
112+
settings.preview.is_enabled()
113+
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ mod tests {
1515

1616
use crate::registry::Rule;
1717
use crate::rules::pyupgrade;
18-
18+
use crate::settings::types::PreviewMode;
1919
use crate::test::test_path;
2020
use crate::{assert_diagnostics, settings};
2121

@@ -122,6 +122,20 @@ mod tests {
122122
Ok(())
123123
}
124124

125+
#[test_case(Rule::SuperCallWithParameters, Path::new("UP008.py"))]
126+
fn rules_preview(rule_code: Rule, path: &Path) -> Result<()> {
127+
let snapshot = format!("{}__preview", path.to_string_lossy());
128+
let diagnostics = test_path(
129+
Path::new("pyupgrade").join(path).as_path(),
130+
&settings::LinterSettings {
131+
preview: PreviewMode::Enabled,
132+
..settings::LinterSettings::for_rule(rule_code)
133+
},
134+
)?;
135+
assert_diagnostics!(snapshot, diagnostics);
136+
Ok(())
137+
}
138+
125139
#[test]
126140
fn async_timeout_error_alias_not_applied_py310() -> Result<()> {
127141
let diagnostics = test_path(

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

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
use ruff_diagnostics::Applicability;
12
use ruff_macros::{ViolationMetadata, derive_message_formats};
23
use ruff_python_ast::{self as ast, Expr, Stmt};
34
use ruff_text_size::{Ranged, TextSize};
45

56
use crate::checkers::ast::Checker;
7+
use crate::preview::is_safe_super_call_with_parameters_fix_enabled;
68
use crate::{AlwaysFixableViolation, Edit, Fix};
79

810
/// ## What it does
@@ -45,6 +47,10 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
4547
/// This rule's fix is marked as unsafe because removing the arguments from a call
4648
/// may delete comments that are attached to the arguments.
4749
///
50+
/// In [preview], the fix is marked safe if no comments are present.
51+
///
52+
/// [preview]: https://docs.astral.sh/ruff/preview/
53+
///
4854
/// ## References
4955
/// - [Python documentation: `super`](https://docs.python.org/3/library/functions.html#super)
5056
/// - [super/MRO, Python's most misunderstood feature.](https://www.youtube.com/watch?v=X1PQ7zzltz4)
@@ -159,11 +165,22 @@ pub(crate) fn super_call_with_parameters(checker: &Checker, call: &ast::ExprCall
159165
return;
160166
}
161167

168+
let applicability = if !checker.comment_ranges().intersects(call.arguments.range())
169+
&& is_safe_super_call_with_parameters_fix_enabled(checker.settings())
170+
{
171+
Applicability::Safe
172+
} else {
173+
Applicability::Unsafe
174+
};
175+
162176
let mut diagnostic = checker.report_diagnostic(SuperCallWithParameters, call.arguments.range());
163-
diagnostic.set_fix(Fix::unsafe_edit(Edit::deletion(
164-
call.arguments.start() + TextSize::new(1),
165-
call.arguments.end() - TextSize::new(1),
166-
)));
177+
diagnostic.set_fix(Fix::applicable_edit(
178+
Edit::deletion(
179+
call.arguments.start() + TextSize::new(1),
180+
call.arguments.end() - TextSize::new(1),
181+
),
182+
applicability,
183+
));
167184
}
168185

169186
/// Returns `true` if a call is an argumented `super` invocation.

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

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,91 @@ UP008.py:107:23: UP008 [*] Use `super()` instead of `super(__class__, self)`
161161
106 106 | def f(self):
162162
107 |- builtins.super(C, self)
163163
107 |+ builtins.super()
164+
108 108 |
165+
109 109 |
166+
110 110 | # see: https://github.com/astral-sh/ruff/issues/18533
167+
168+
UP008.py:113:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
169+
|
170+
111 | class ClassForCommentEnthusiasts(BaseClass):
171+
112 | def with_comments(self):
172+
113 | super(
173+
| ______________^
174+
114 | | # super helpful comment
175+
115 | | ClassForCommentEnthusiasts,
176+
116 | | self
177+
117 | | ).f()
178+
| |_________^ UP008
179+
118 | super(
180+
119 | ClassForCommentEnthusiasts,
181+
|
182+
= help: Remove `super()` parameters
183+
184+
Unsafe fix
185+
110 110 | # see: https://github.com/astral-sh/ruff/issues/18533
186+
111 111 | class ClassForCommentEnthusiasts(BaseClass):
187+
112 112 | def with_comments(self):
188+
113 |- super(
189+
114 |- # super helpful comment
190+
115 |- ClassForCommentEnthusiasts,
191+
116 |- self
192+
117 |- ).f()
193+
113 |+ super().f()
194+
118 114 | super(
195+
119 115 | ClassForCommentEnthusiasts,
196+
120 116 | # even more helpful comment
197+
198+
UP008.py:118:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
199+
|
200+
116 | self
201+
117 | ).f()
202+
118 | super(
203+
| ______________^
204+
119 | | ClassForCommentEnthusiasts,
205+
120 | | # even more helpful comment
206+
121 | | self
207+
122 | | ).f()
208+
| |_________^ UP008
209+
123 | super(
210+
124 | ClassForCommentEnthusiasts,
211+
|
212+
= help: Remove `super()` parameters
213+
214+
Unsafe fix
215+
115 115 | ClassForCommentEnthusiasts,
216+
116 116 | self
217+
117 117 | ).f()
218+
118 |- super(
219+
119 |- ClassForCommentEnthusiasts,
220+
120 |- # even more helpful comment
221+
121 |- self
222+
122 |- ).f()
223+
118 |+ super().f()
224+
123 119 | super(
225+
124 120 | ClassForCommentEnthusiasts,
226+
125 121 | self
227+
228+
UP008.py:123:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
229+
|
230+
121 | self
231+
122 | ).f()
232+
123 | super(
233+
| ______________^
234+
124 | | ClassForCommentEnthusiasts,
235+
125 | | self
236+
126 | | # also a comment
237+
127 | | ).f()
238+
| |_________^ UP008
239+
|
240+
= help: Remove `super()` parameters
241+
242+
Unsafe fix
243+
120 120 | # even more helpful comment
244+
121 121 | self
245+
122 122 | ).f()
246+
123 |- super(
247+
124 |- ClassForCommentEnthusiasts,
248+
125 |- self
249+
126 |- # also a comment
250+
127 |- ).f()
251+
123 |+ super().f()

0 commit comments

Comments
 (0)