I am trying to monkey patch a python module to override a method within the class. This is a proxy module for simplification and not the actual code or module I am overwriting but follows the same structure.
The module looks like internally:
dog_module.py
from ._util import b
from ._util import log
class Bork(BorkBase):
def __init__(self, verbose=False, options=None):
self.a = 42
def define_bork(self, bark):
result = bark
log.info('Importing: %r', bark)
return result
where _util.py
lives within the same parent folder as this dog_module.py
I modified the package code at the source (within the python/.../site-packages/) and this works fine, but I want to monkey patch it so it's easier for others to deploy (so they don't have to go into the source code and make these changes themselves on their machines).
I have tried overriding def define_bork():
in my script with:
import dog_module
def new_bork(self, bark, breed):
result = bark
log.info('Importing: %r', bark)
if breed == "big":
result = bark + "!"
return result
class Dog:
def __init__(self, color, breed):
self.color = color
self.breed = breed
self.woof = self.woof()
def woof(self):
dog_module.Bork.define_bork = new_bork
bark = dog_module.Bork()
return bark.define_bork("woof",self.breed) # returns string "woof!"
my_dog_spot = Dog(“black”, “big”)
but the problem is that it seems to properly modify the "define_bork()" method within the original dog_module, but it throws:
61 def new_bork(self, bark, breed):
62 result = bark
---> 63 log.info('Importing: %r', bark)
64 if breed == "big":
65 result = bark + "!"
66 return result
NameError: name 'log' is not defined
There are other methods within _utils.py
other than just log
, so removing it entirely is not an option. I figured it would still correctly inherit everything from the class and just override the one method, but it seems to not work that way.
A function will see the global variables of the module it is defined in. And by "global variables", we mean also any other functions, methods constants present in that module, including ones that were imported from 3rd modules.
In this case, you need the function you are defining in the overriding script to have access to some names of the original module, were it will replace another function -
All you need to do, if you can import the other module as you are doing here, is to refer to the qualified name of those names you need - so, instead of log
you refer to dog_module.log
inside your function that needs access to these values.
Your code will work with this simple replacement:
import dog_module
def new_bork(self, bark, breed):
result = bark
dog_module.log.info('Importing: %r', bark)
if breed == "big":
result = bark + "!"
return result
...