diff --git a/doc/data/messages/b/bad-super-call/bad.py b/doc/data/messages/b/bad-super-call/bad.py index 1f13df5ede..625a70e6f9 100644 --- a/doc/data/messages/b/bad-super-call/bad.py +++ b/doc/data/messages/b/bad-super-call/bad.py @@ -2,6 +2,11 @@ class Animal: pass +class Tree: + pass + + class Cat(Animal): def __init__(self): - super(Animal, self).__init__() # [bad-super-call] + super(Tree, self).__init__() # [bad-super-call] + super(Animal, self).__init__() diff --git a/doc/data/messages/b/bad-super-call/details.rst b/doc/data/messages/b/bad-super-call/details.rst index 73f41942c1..e5b0ab5c7d 100644 --- a/doc/data/messages/b/bad-super-call/details.rst +++ b/doc/data/messages/b/bad-super-call/details.rst @@ -2,3 +2,6 @@ In Python 2.7, ``super()`` has to be called with its own class and ``self`` as a lead to a mix up of parent and child class in the code. In Python 3 the recommended way is to call ``super()`` without arguments (see also ``super-with-arguments``). + +One exception is calling ``super()`` on a non-direct parent class. This can be used to get a method other than the default +method returned by the ``mro()``. diff --git a/doc/data/messages/b/bad-super-call/good.py b/doc/data/messages/b/bad-super-call/good.py index 720b2eda91..66152bc73e 100644 --- a/doc/data/messages/b/bad-super-call/good.py +++ b/doc/data/messages/b/bad-super-call/good.py @@ -2,6 +2,10 @@ class Animal: pass +class Tree: + pass + + class Cat(Animal): def __init__(self): - super().__init__() + super(Animal, self).__init__() diff --git a/doc/whatsnew/2/2.14/full.rst b/doc/whatsnew/2/2.14/full.rst index 885be244e4..aae6f5a956 100644 --- a/doc/whatsnew/2/2.14/full.rst +++ b/doc/whatsnew/2/2.14/full.rst @@ -5,6 +5,10 @@ What's New in Pylint 2.14.3? ---------------------------- Release date: TBA +* Fixed two false positives for ``bad-super-call`` for calls that refer to a non-direct parent. + + Closes #4922, Closes #2903 + * Fixed a false positive for ``useless-super-delegation`` for subclasses that specify the number of of parameters against a parent that uses a variadic argument. diff --git a/pylint/checkers/newstyle.py b/pylint/checkers/newstyle.py index 6b0aa50956..0aed971836 100644 --- a/pylint/checkers/newstyle.py +++ b/pylint/checkers/newstyle.py @@ -108,7 +108,9 @@ def visit_functiondef(self, node: nodes.FunctionDef) -> None: except astroid.InferenceError: continue - if klass is not supcls: + # If the supcls is in the ancestors of klass super can be used to skip + # a step in the mro() and get a method from a higher parent + if klass is not supcls and all(i != supcls for i in klass.ancestors()): name = None # if supcls is not Uninferable, then supcls was inferred # and use its name. Otherwise, try to look diff --git a/tests/functional/s/super/super_checks.py b/tests/functional/s/super/super_checks.py index 277feae7ee..ca35d52aec 100644 --- a/tests/functional/s/super/super_checks.py +++ b/tests/functional/s/super/super_checks.py @@ -29,7 +29,7 @@ def __init__(self): class Py3kWrongSuper(Py3kAaaa): """new style""" def __init__(self): - super(NewAaaa, self).__init__() # [bad-super-call] + super(NewAaaa, self).__init__() class WrongNameRegression(Py3kAaaa): """ test a regression with the message """ @@ -59,7 +59,7 @@ class FalsePositive(Empty): """The following super is in another scope than `test`.""" def __init__(self, arg): super(FalsePositive, self).__init__(arg) - super(object, 1).__init__() # [bad-super-call] + super(object, 1).__init__() class UnknownBases(Missing): @@ -123,3 +123,34 @@ class SuperWithSelfClass(object): """self.__class__ may lead to recursion loop in derived classes""" def __init__(self): super(self.__class__, self).__init__() # [bad-super-call] + + +# Reported in https://github.com/PyCQA/pylint/issues/2903 +class Parent: + def method(self): + print() + + +class Child(Parent): + def method(self): + print("Child") + super().method() + +class Niece(Parent): + def method(self): + print("Niece") + super().method() + +class GrandChild(Child): + def method(self): + print("Grandchild") + super(GrandChild, self).method() + super(Child, self).method() + super(Niece, self).method() # [bad-super-call] + + +# Reported in https://github.com/PyCQA/pylint/issues/4922 +class AlabamaCousin(Child, Niece): + def method(self): + print("AlabamaCousin") + super(Child, self).method() diff --git a/tests/functional/s/super/super_checks.txt b/tests/functional/s/super/super_checks.txt index d18c28327f..f33d9ec637 100644 --- a/tests/functional/s/super/super_checks.txt +++ b/tests/functional/s/super/super_checks.txt @@ -1,10 +1,8 @@ no-member:10:8:10:29:Aaaa.hop:Super of 'Aaaa' has no 'hop' member:INFERENCE no-member:19:8:19:32:NewAaaa.hop:Super of 'NewAaaa' has no 'hop' member:INFERENCE bad-super-call:22:8:22:25:NewAaaa.__init__:Bad first argument 'Aaaa' given to super():UNDEFINED -bad-super-call:32:8:32:28:Py3kWrongSuper.__init__:Bad first argument 'NewAaaa' given to super():UNDEFINED bad-super-call:37:8:37:28:WrongNameRegression.__init__:Bad first argument 'Missing' given to super():UNDEFINED bad-super-call:46:8:46:33:CrashSuper.__init__:Bad first argument 'NewAaaa' given to super():UNDEFINED -bad-super-call:62:8:62:24:SuperDifferentScope.test:Bad first argument 'object' given to super():UNDEFINED bad-super-call:70:8:70:28:UnknownBases.__init__:Bad first argument 'Missing' given to super():UNDEFINED not-callable:89:8:89:54:InvalidSuperChecks.__init__:super(InvalidSuperChecks, self).not_a_method is not callable:UNDEFINED no-member:90:8:90:55:InvalidSuperChecks.__init__:Super of 'InvalidSuperChecks' has no 'attribute_error' member:INFERENCE @@ -15,3 +13,4 @@ unexpected-keyword-arg:95:8:95:57:InvalidSuperChecks.__init__:Unexpected keyword no-member:98:8:98:55:InvalidSuperChecks.__init__:Super of 'InvalidSuperChecks' has no 'attribute_error' member:INFERENCE bad-super-call:120:8:120:31:SuperWithType.__init__:Bad first argument 'type' given to super():UNDEFINED bad-super-call:125:8:125:35:SuperWithSelfClass.__init__:Bad first argument 'self.__class__' given to super():UNDEFINED +bad-super-call:149:8:149:26:GrandChild.method:Bad first argument 'Niece' given to super():UNDEFINED