Skip to content

Commit 03dd537

Browse files
committed
Don't emit super-init-not-called for abstract __init__ methods
1 parent 5d5f5f7 commit 03dd537

File tree

9 files changed

+61
-14
lines changed

9 files changed

+61
-14
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Don't report ``super-init-not-called`` for abstract ``__init__`` methods.
2+
3+
Closes #3975

pylint/checkers/classes/class_checker.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -2034,7 +2034,7 @@ def _check_init(self, node: nodes.FunctionDef, klass_node: nodes.ClassDef) -> No
20342034
# Record that the class' init has been called
20352035
parents_with_called_inits.add(node_frame_class(method))
20362036
except KeyError:
2037-
if klass not in to_call:
2037+
if klass not in klass_node.ancestors(recurs=False):
20382038
self.add_message(
20392039
"non-parent-init-called", node=expr, args=klass.name
20402040
)
@@ -2061,9 +2061,6 @@ def _check_init(self, node: nodes.FunctionDef, klass_node: nodes.ClassDef) -> No
20612061

20622062
if decorated_with(node, ["typing.overload"]):
20632063
continue
2064-
cls = node_frame_class(method)
2065-
if klass.name == "object" or (cls and cls.name == "object"):
2066-
continue
20672064
self.add_message(
20682065
"super-init-not-called",
20692066
args=klass.name,
@@ -2196,7 +2193,10 @@ def _ancestors_to_call(
21962193
to_call: dict[nodes.ClassDef, bases.UnboundMethod] = {}
21972194
for base_node in klass_node.ancestors(recurs=False):
21982195
try:
2199-
to_call[base_node] = next(base_node.igetattr(method))
2196+
init_node: bases.UnboundMethod = next(base_node.igetattr(method))
2197+
if init_node.is_abstract():
2198+
continue
2199+
to_call[base_node] = init_node
22002200
except astroid.InferenceError:
22012201
continue
22022202
return to_call

tests/functional/i/init_not_called.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ def xx_init(self):
5959

6060

6161
class AssignedInit(NewStyleC):
62-
"""No init called."""
62+
"""No init called, but abstract so that is fine."""
6363

64-
def __init__(self): # [super-init-not-called]
64+
def __init__(self):
6565
self.arg = 0
6666

6767

-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
super-init-not-called:32:4:32:16:ZZZZ.__init__:__init__ method from base class 'BBBB' is not called:INFERENCE
2-
super-init-not-called:64:4:64:16:AssignedInit.__init__:__init__ method from base class 'NewStyleC' is not called:INFERENCE

tests/functional/n/non/non_init_parent_called.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,6 @@ class Super2(dict):
4646
""" Using the same idiom as Super, but without calling
4747
the __init__ method.
4848
"""
49-
def __init__(self): # [super-init-not-called]
49+
def __init__(self):
5050
base = super()
5151
base.__woohoo__() # [no-member]

tests/functional/n/non/non_init_parent_called.txt

-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@ import-error:7:0:7:18::Unable to import 'nonexistant':UNDEFINED
22
non-parent-init-called:15:8:15:26:AAAA.__init__:__init__ method from a non direct base class 'BBBBMixin' is called:UNDEFINED
33
no-member:23:50:23:77:CCC:Module 'functional.n.non.non_init_parent_called' has no 'BBBB' member:INFERENCE
44
no-member:28:8:28:35:CCC.__init__:Module 'functional.n.non.non_init_parent_called' has no 'BBBB' member:INFERENCE
5-
super-init-not-called:49:4:49:16:Super2.__init__:__init__ method from base class 'dict' is not called:INFERENCE
65
no-member:51:8:51:23:Super2.__init__:Super of 'Super2' has no '__woohoo__' member:INFERENCE

tests/functional/s/super/super_init_not_called.py

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""Tests for super-init-not-called."""
22
# pylint: disable=too-few-public-methods, missing-class-docstring
33

4+
import abc
45
import ctypes
56

67

@@ -53,5 +54,45 @@ def __init__(self): # [super-init-not-called]
5354
# Regression test as reported in
5455
# https://github.com/PyCQA/pylint/issues/6027
5556
class MyUnion(ctypes.Union):
56-
def __init__(self): # [super-init-not-called]
57+
def __init__(self):
5758
pass
59+
60+
61+
# Should not be called on abstract __init__ methods
62+
# https://github.com/PyCQA/pylint/issues/3975
63+
class Base:
64+
def __init__(self, param: int, param_two: str) -> None:
65+
raise NotImplementedError()
66+
67+
68+
class Derived(Base):
69+
def __init__(self, param: int, param_two: str) -> None:
70+
self.param = param + 1
71+
self.param_two = param_two[::-1]
72+
73+
74+
class AbstractBase(abc.ABC):
75+
def __init__(self, param: int) -> None:
76+
self.param = param + 1
77+
78+
def abstract_method(self) -> str:
79+
"""This needs to be implemented."""
80+
raise NotImplementedError()
81+
82+
83+
class DerivedFromAbstract(AbstractBase):
84+
def __init__(self, param: int) -> None: # [super-init-not-called]
85+
print("Called")
86+
87+
def abstract_method(self) -> str:
88+
return "Implemented"
89+
90+
91+
class DerivedFrom(UnknownParent): # [undefined-variable]
92+
def __init__(self) -> None:
93+
print("Called")
94+
95+
96+
class DerivedFromUnknownGrandparent(DerivedFrom):
97+
def __init__(self) -> None:
98+
DerivedFrom.__init__(self)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
[testoptions]
2+
# ctypes has a different implementation in PyPy and does have an inferable
3+
# __init__ method for ctypes.Union.
4+
except_implementations=PyPy
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
undefined-variable:18:23:18:40:UninferableChild:Undefined variable 'UninferableParent':UNDEFINED
2-
super-init-not-called:49:4:49:16:ChildThree.__init__:__init__ method from base class 'ParentWithoutInit' is not called:INFERENCE
3-
super-init-not-called:56:4:56:16:MyUnion.__init__:__init__ method from base class 'Union' is not called:INFERENCE
1+
undefined-variable:19:23:19:40:UninferableChild:Undefined variable 'UninferableParent':UNDEFINED
2+
super-init-not-called:50:4:50:16:ChildThree.__init__:__init__ method from base class 'ParentWithoutInit' is not called:INFERENCE
3+
super-init-not-called:84:4:84:16:DerivedFromAbstract.__init__:__init__ method from base class 'AbstractBase' is not called:INFERENCE
4+
undefined-variable:91:18:91:31:DerivedFrom:Undefined variable 'UnknownParent':UNDEFINED

0 commit comments

Comments
 (0)