-
Notifications
You must be signed in to change notification settings - Fork 2k
UP008 false positive in nested class when the first super arg is not a full class path #24001
Description
Summary
This is a follow-up to issue #22597. I'd like to thank @leandrobbraga for the initial implementation of the PR #22677 that fixed the bug and @charliermarsh for finishing it!
I'm glad to see that my review comments on that PR have been incorporated. However, after reviewing this part in the final version of the PR, I realized that there is still one edge case that isn't handled correctly:
class Base:
def __init__(self, foo):
print(f"Base.__init__({foo}) called")
self.foo = foo
class Inner(Base):
def __init__(self, foo):
print(f"Inner.__init__({foo}) called")
super().__init__(foo)
class Outer:
class Inner(Inner):
def __init__(self, foo):
super(Inner, self).__init__(foo) # Should NOT trigger UP008
i = Outer.Inner(5)Playground link: https://play.ruff.rs/b19c84be-2da6-46e9-93f7-87f5ee770f54
As you can see in the playground, super(Inner, self) in Outer.Inner.__init__() triggers the UP008 rule, which is incorrect. UP008 should only be triggered if it were super(Outer.Inner, self) instead - only then would super() be equivalent.
Let me demonstrate that super(Inner, self) cannot be changed to super() (as the incorrectly triggered UP008 rule claims), because doing so would alter the program's runtime behavior:
$ python3 --version
Python 3.14.3
$ cat test.py
class Base:
def __init__(self, foo):
print(f"Base.__init__({foo}) called")
self.foo = foo
class Inner(Base):
def __init__(self, foo):
print(f"Inner.__init__({foo}) called")
super().__init__(foo)
class Outer:
class Inner(Inner):
def __init__(self, foo):
super(Inner, self).__init__(foo) # Should NOT trigger UP008
i = Outer.Inner(5)
$ python3 test.py
Base.__init__(5) called
$ ruff --version
ruff 0.15.6
$ ruff check --select UP --isolated --no-cache test.py
UP008 [*] Use `super()` instead of `super(__class__, self)`
--> test.py:16:18
|
14 | class Inner(Inner):
15 | def __init__(self, foo):
16 | super(Inner, self).__init__(foo) # Should NOT trigger UP008
| ^^^^^^^^^^^^^
|
help: Remove `super()` parameters
Found 1 error.
[*] 1 fixable with the `--fix` option.
$ ruff check --select UP --isolated --no-cache test.py --diff
--- test.py
+++ test.py
@@ -13,7 +13,7 @@
class Outer:
class Inner(Inner):
def __init__(self, foo):
- super(Inner, self).__init__(foo) # Should NOT trigger UP008
+ super().__init__(foo) # Should NOT trigger UP008
i = Outer.Inner(5)
Would fix 1 error.
$ ruff check --select UP --isolated --no-cache test.py --fix
Found 1 error (1 fixed, 0 remaining).
$ python3 test.py
Inner.__init__(5) called
Base.__init__(5) calledNote that the Inner.__init__(5) called message was not printed by the original code, but is printed after applying the safe fix offered by Ruff for the mistakenly reported violation of rule UP008.
Version
ruff 0.15.6