I've been trying to work around a bug in a third party module. The bug was fixed recently, but I've been wondering about my issues nevertheless. Perhaps this question may help me or others in the future.
The module defines a class Runtime with several methods that I use. Upon importing the module it automatically creates an instance of Runtime, loads configuration and gives the instance to the user (me) to work with.
# thirdPartyModule.py
class Runtime:
def __init__(self, a):
self.a = a
def configuration(self, ...):
...
def fun(self):
print(self.a)
rt = Runtime("twice")
rt.configuration(...)
Unfortunately, one of the runtime methods contained a bug. I used to monkeypatch this bug by just overwriting the method of the instance by a working substitute like so:
# mycode.py
import types
from thirdPartyModule import rt
def newfun(self):
print(self.a, self.a)
rt.fun = types.MethodType(newfun, rt)
rt.fun()
This worked just fine while I was waiting for the developer to fix the bug. Or at least it did up to the point where the developer added __slots__
to the class:
# thirdPartyModule.py
class Runtime:
__slots__ = ("a", )
def __init__(self, a):
self.a = a
...
Since then I've tried several method-overwriting solutions in this forum, but all of them were rejected ("AttributeError: 'Runtime' object attribute 'fun' is read-only").
It might be that unittest.mock
can help me out, but I'm not too familiar with mocking. I've tried the following without success:
import unittest.mock
rt.fun = mock.Mock(rt.fun, side_effect=newfun)
This results in the same AttributeError. Perhaps I could mock the entire instance (rt = mock.Mock(rt)
) or something similar, but I'm neither familiar nor completely comfortable with this approach.
As I said the bug has been fixed in the meantime, but I cannot help but wonder how you would proceed in this situation?
>>> class X():
... __slots__ = ("a",)
... def func():
... print("1")
...
>>> x = X()
>>> type(x)
<class '__main__.X'>
>>> type(x).func = lambda self: print("2")
>>> x.func
<bound method <lambda> of <__main__.X object at 0x7f27fb88b050>>
>>> x.func()
2
>>>
Explanation: you have to monkeypatch the Runtime class instead of the instance.