[`pyupgrade`] Keyword arguments in `super` should suppress the `UP008` fix (#19131)

## Summary

Fixes #19096
This commit is contained in:
Dan Parizher 2025-07-09 15:13:22 -04:00 committed by GitHub
parent beb98dae7c
commit 221edcba5c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 141 additions and 19 deletions

View File

@ -125,3 +125,19 @@ class ClassForCommentEnthusiasts(BaseClass):
self
# also a comment
).f()
# Issue #19096: super calls with keyword arguments should emit diagnostic but not be fixed
class Ord(int):
def __len__(self):
return super(Ord, self, uhoh=True, **{"error": True}).bit_length()
class ExampleWithKeywords:
def method1(self):
super(ExampleWithKeywords, self, invalid=True).some_method() # Should emit diagnostic but NOT be fixed
def method2(self):
super(ExampleWithKeywords, self, **{"kwarg": "value"}).some_method() # Should emit diagnostic but NOT be fixed
def method3(self):
super(ExampleWithKeywords, self).some_method() # Should be fixed - no keywords

View File

@ -5,7 +5,7 @@ use ruff_text_size::{Ranged, TextSize};
use crate::checkers::ast::Checker;
use crate::preview::is_safe_super_call_with_parameters_fix_enabled;
use crate::{AlwaysFixableViolation, Edit, Fix};
use crate::{Edit, Fix, FixAvailability, Violation};
/// ## What it does
/// Checks for `super` calls that pass redundant arguments.
@ -57,14 +57,16 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
#[derive(ViolationMetadata)]
pub(crate) struct SuperCallWithParameters;
impl AlwaysFixableViolation for SuperCallWithParameters {
impl Violation for SuperCallWithParameters {
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
#[derive_message_formats]
fn message(&self) -> String {
"Use `super()` instead of `super(__class__, self)`".to_string()
}
fn fix_title(&self) -> String {
"Remove `super()` parameters".to_string()
fn fix_title(&self) -> Option<String> {
Some("Remove `super()` parameters".to_string())
}
}
@ -165,22 +167,26 @@ pub(crate) fn super_call_with_parameters(checker: &Checker, call: &ast::ExprCall
return;
}
let applicability = if !checker.comment_ranges().intersects(call.arguments.range())
&& is_safe_super_call_with_parameters_fix_enabled(checker.settings())
{
Applicability::Safe
} else {
Applicability::Unsafe
};
let mut diagnostic = checker.report_diagnostic(SuperCallWithParameters, call.arguments.range());
diagnostic.set_fix(Fix::applicable_edit(
Edit::deletion(
call.arguments.start() + TextSize::new(1),
call.arguments.end() - TextSize::new(1),
),
applicability,
));
// Only provide a fix if there are no keyword arguments, since super() doesn't accept keyword arguments
if call.arguments.keywords.is_empty() {
let applicability = if !checker.comment_ranges().intersects(call.arguments.range())
&& is_safe_super_call_with_parameters_fix_enabled(checker.settings())
{
Applicability::Safe
} else {
Applicability::Unsafe
};
diagnostic.set_fix(Fix::applicable_edit(
Edit::deletion(
call.arguments.start() + TextSize::new(1),
call.arguments.end() - TextSize::new(1),
),
applicability,
));
}
}
/// Returns `true` if a call is an argumented `super` invocation.

View File

@ -249,3 +249,53 @@ UP008.py:123:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
126 |- # also a comment
127 |- ).f()
123 |+ super().f()
128 124 |
129 125 |
130 126 | # Issue #19096: super calls with keyword arguments should emit diagnostic but not be fixed
UP008.py:133:21: UP008 Use `super()` instead of `super(__class__, self)`
|
131 | class Ord(int):
132 | def __len__(self):
133 | return super(Ord, self, uhoh=True, **{"error": True}).bit_length()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
134 |
135 | class ExampleWithKeywords:
|
= help: Remove `super()` parameters
UP008.py:137:14: UP008 Use `super()` instead of `super(__class__, self)`
|
135 | class ExampleWithKeywords:
136 | def method1(self):
137 | super(ExampleWithKeywords, self, invalid=True).some_method() # Should emit diagnostic but NOT be fixed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
138 |
139 | def method2(self):
|
= help: Remove `super()` parameters
UP008.py:140:14: UP008 Use `super()` instead of `super(__class__, self)`
|
139 | def method2(self):
140 | super(ExampleWithKeywords, self, **{"kwarg": "value"}).some_method() # Should emit diagnostic but NOT be fixed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
141 |
142 | def method3(self):
|
= help: Remove `super()` parameters
UP008.py:143:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
|
142 | def method3(self):
143 | super(ExampleWithKeywords, self).some_method() # Should be fixed - no keywords
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
|
= help: Remove `super()` parameters
Unsafe fix
140 140 | super(ExampleWithKeywords, self, **{"kwarg": "value"}).some_method() # Should emit diagnostic but NOT be fixed
141 141 |
142 142 | def method3(self):
143 |- super(ExampleWithKeywords, self).some_method() # Should be fixed - no keywords
143 |+ super().some_method() # Should be fixed - no keywords

View File

@ -249,3 +249,53 @@ UP008.py:123:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
126 |- # also a comment
127 |- ).f()
123 |+ super().f()
128 124 |
129 125 |
130 126 | # Issue #19096: super calls with keyword arguments should emit diagnostic but not be fixed
UP008.py:133:21: UP008 Use `super()` instead of `super(__class__, self)`
|
131 | class Ord(int):
132 | def __len__(self):
133 | return super(Ord, self, uhoh=True, **{"error": True}).bit_length()
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
134 |
135 | class ExampleWithKeywords:
|
= help: Remove `super()` parameters
UP008.py:137:14: UP008 Use `super()` instead of `super(__class__, self)`
|
135 | class ExampleWithKeywords:
136 | def method1(self):
137 | super(ExampleWithKeywords, self, invalid=True).some_method() # Should emit diagnostic but NOT be fixed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
138 |
139 | def method2(self):
|
= help: Remove `super()` parameters
UP008.py:140:14: UP008 Use `super()` instead of `super(__class__, self)`
|
139 | def method2(self):
140 | super(ExampleWithKeywords, self, **{"kwarg": "value"}).some_method() # Should emit diagnostic but NOT be fixed
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
141 |
142 | def method3(self):
|
= help: Remove `super()` parameters
UP008.py:143:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
|
142 | def method3(self):
143 | super(ExampleWithKeywords, self).some_method() # Should be fixed - no keywords
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ UP008
|
= help: Remove `super()` parameters
Safe fix
140 140 | super(ExampleWithKeywords, self, **{"kwarg": "value"}).some_method() # Should emit diagnostic but NOT be fixed
141 141 |
142 142 | def method3(self):
143 |- super(ExampleWithKeywords, self).some_method() # Should be fixed - no keywords
143 |+ super().some_method() # Should be fixed - no keywords