While having deep dive into how the built-in unittest.mock
was designed, I run into these lines in the official source code of mock.py
:
class Base(object):
_mock_return_value = DEFAULT
_mock_side_effect = None
def __init__(self, /, *args, **kwargs):
pass
class NonCallableMock(Base):
...
# and later in the init
def _init__ (...):
...
_safe_super(NonCallableMock, self).__init__(
spec, wraps, name, spec_set, parent,
_spec_state
)
What is the role of Base
class besides providing common class attributes _mock_return_value
and _mock_side_effect
as it has just an empty __init__
?
And why NonCallableMock
has to call _safe_super(NonCallableMock, self).__init__()
, which I believe is exactly just the empty __init__
method of the Base
class ?
Thanks a lot for your answers in advance.
I tried to understand the code but couldn't see the rationale behind the design.
It's for multiple inheritance, which unittest.mock
uses for classes like class MagicMock(MagicMixin, Mock):
.
Despite the name, super
doesn't mean "call the superclass method". Instead, it finds the next method implementation in a type's method resolution order, which might not come from a parent of the current class when multiple inheritance is involved. When you don't know what method super
will call, you have to be a lot more careful about what arguments you pass to that method.
Most of the classes in this class hierarchy forward arguments like spec
and wraps
to the next __init__
implementation when they call _safe_super(...).__init__(...)
. Even if none of their ancestors need those arguments, a sibling implementation could still need them. If all of the classes were to forward these arguments, then object.__init__
would eventually receive those arguments, and object.__init__
would throw an exception.
Some class has to handle the job of specifically not passing those arguments to object.__init__
, and that class has to sit at the root of the class hierarchy, right below object
itself.
Thus, this Base
class: a class for all the other classes in this multiple inheritance hierarchy to inherit from, existing almost solely for the purpose of preventing object.__init__
from complaining.