We have a third party lib that we use in our Django 1.9 app. We would like to amend that application with some functionality not in the original app (targeting MongoDB). We currently do this via our own fork of the original lib, but would like to make the changes a bit more orthogonal, so that they might be pulled upstream eventually.
We've tried patching during the app config ready()
but model imports are handled before this call in django.apps.registry.populate()
, and performing it in the \__init__
suffers from apps_ready == False
. What is the best part of the lifecycle to perform this?
class MongoConfig(AppConfig):
def __init__(self, app_name, app_module):
super(MongoConfig, self).__init__(app_name, app_module)
for p in patches:
patch(*p)
def patch(old, new):
old_module, old_item = split_mod(old)
new_module, new_item = split_mod(new)
print('patching {0} with {1}'.format(old, new))
old_module = import_module(old_module)
new_module = import_module(new_module)
setattr(old_module, old_item, getattr(new_module, new_item))
Monkey patching is a technique to modify module functions or class methods in Python and other dynamic languages run-time. It differs from the traditional source code patching that it does not need separate utility or compilation process to become effective.
Monkey patching can only be done in dynamic languages, of which python is a good example. Changing a method at runtime instead of updating the object definition is one example;similarly, adding attributes (whether methods or variables) at runtime is considered monkey patching.
Monkey patching is more a way for debugging, experiencing, patching, or hacking existing code than rather a long-term solution for a code base, even if it could be used as a natural solution in a few specific cases.
I am really not for monkey patching (except during test cases, even then I believe mock is better).
Why don't you try the simpler option? Create a proxy of the app within your project (it will be called first, due to Python's lookup system) and then simply patch the methods you want, and bypass the ones you don't to the original app.
So if the component is called "FooProject" you would create another app called "FooProject" in your project, in this app's __init__.py
:
from originalproject import FooProject as OriginalFoo
class FooProject(OriginalFoo):
def override_method_here(self, foo):
return my_own_magic(foo)
I ended up doing this in the wsgi portion of initialization
In wsgi.py
# Monkey Patch a few things
from huey_monitor.apps import HueyMonitorConfig
HueyMonitorConfig.verbose_name = 'Task Monitor'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With