[`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 self
# also a comment # also a comment
).f() ).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::checkers::ast::Checker;
use crate::preview::is_safe_super_call_with_parameters_fix_enabled; 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 /// ## What it does
/// Checks for `super` calls that pass redundant arguments. /// Checks for `super` calls that pass redundant arguments.
@ -57,14 +57,16 @@ use crate::{AlwaysFixableViolation, Edit, Fix};
#[derive(ViolationMetadata)] #[derive(ViolationMetadata)]
pub(crate) struct SuperCallWithParameters; pub(crate) struct SuperCallWithParameters;
impl AlwaysFixableViolation for SuperCallWithParameters { impl Violation for SuperCallWithParameters {
const FIX_AVAILABILITY: FixAvailability = FixAvailability::Sometimes;
#[derive_message_formats] #[derive_message_formats]
fn message(&self) -> String { fn message(&self) -> String {
"Use `super()` instead of `super(__class__, self)`".to_string() "Use `super()` instead of `super(__class__, self)`".to_string()
} }
fn fix_title(&self) -> String { fn fix_title(&self) -> Option<String> {
"Remove `super()` parameters".to_string() Some("Remove `super()` parameters".to_string())
} }
} }
@ -165,6 +167,10 @@ pub(crate) fn super_call_with_parameters(checker: &Checker, call: &ast::ExprCall
return; return;
} }
let mut diagnostic = checker.report_diagnostic(SuperCallWithParameters, call.arguments.range());
// 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()) let applicability = if !checker.comment_ranges().intersects(call.arguments.range())
&& is_safe_super_call_with_parameters_fix_enabled(checker.settings()) && is_safe_super_call_with_parameters_fix_enabled(checker.settings())
{ {
@ -173,7 +179,6 @@ pub(crate) fn super_call_with_parameters(checker: &Checker, call: &ast::ExprCall
Applicability::Unsafe Applicability::Unsafe
}; };
let mut diagnostic = checker.report_diagnostic(SuperCallWithParameters, call.arguments.range());
diagnostic.set_fix(Fix::applicable_edit( diagnostic.set_fix(Fix::applicable_edit(
Edit::deletion( Edit::deletion(
call.arguments.start() + TextSize::new(1), call.arguments.start() + TextSize::new(1),
@ -182,6 +187,7 @@ pub(crate) fn super_call_with_parameters(checker: &Checker, call: &ast::ExprCall
applicability, applicability,
)); ));
} }
}
/// Returns `true` if a call is an argumented `super` invocation. /// Returns `true` if a call is an argumented `super` invocation.
fn is_super_call_with_arguments(call: &ast::ExprCall, checker: &Checker) -> bool { fn is_super_call_with_arguments(call: &ast::ExprCall, checker: &Checker) -> bool {

View File

@ -249,3 +249,53 @@ UP008.py:123:14: UP008 [*] Use `super()` instead of `super(__class__, self)`
126 |- # also a comment 126 |- # also a comment
127 |- ).f() 127 |- ).f()
123 |+ super().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 126 |- # also a comment
127 |- ).f() 127 |- ).f()
123 |+ super().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