Monkey patching the IssueTrackerProduct
10 Mar 2005
This how-to shows an example way of writing your own customisations to the IssueTrackerProduct as a Zope Python product.
File attachments:
ExampleITPMonkey.tgz
2Kb
-__init__.py
1Kb
Monkey patching a Python product means that you write replacement code that gets squeezed into some other product when Zope starts up. It's not an ideal way of doing things because if the product that you're changing changes with a new release it might break your patch but this is quite unlikely. The IssueTrackerProduct contains roughly 600 methods that you can patch and it's very unlikely that all of them will change in a new release.
Let's start. The first thing you do is to create folder where which will be your monkey patching product.:
$ cd zope273/Products $ mkdir ExampleITPMonkey
Then create the most important file:
$ jed __init__.py
(it is of course very important that you create a README.txt file too)
You can read the code by downloading it here but I will now go through some passages that might be of importance:
# our big brother from Products.IssueTrackerProduct import IssueTracker
Here we import the IssueTracker class which just happens to have the same name as the file IssueTracker.py but without the file extension. This is the class we're going to modify. The class has loads of methods and some attributes and when you're writing a monkey patch it doesn't matter if you overwrite a method or an attribute as long as you do it in a way that make sense, i.e. don't put a string variable in the place of function.
The code assumes that the patch won't happen initially and then it sniffs the installed IssueTrackerProduct version and if we're happy we do go ahead with the patch:
# assume that we won't be able to do it
do_patch = False
# Let's only go ahead with this if the issuetracker
# version is above 0.6.4
itpversion = IssueTracker.__version__
major, minor, tiny = [int(number) for number in itpversion.split('.')]
if minor >= 6:
if tiny >= 4:
do_patch = True
The next thing is to write the actual code that we want that the IssueTrackerProduct doesn't provide for us. This could be something that you're unhappy with some of its functionality or you want to custom fit it for your particular installation. In this example I've chosen to replace the default signature function showSignature() with a simpler one that shows a random quote. I've got a file called quotes.py that I put in the folder next to my __init__.py file. What I name it does not matter but my function looks like this:
from quotes import quotes as quotesdict
from random import shuffle
quoteslist = quotesdict.values()
# copied and modified from IssueTracker.py around line 500
def showSignature_Quote(self):
""" our own custom signature function """
shuffle(quoteslist)
return quoteslist[0]
Now, the striking point is when we patch up the IssueTracker class with our "improved" 'showSignature_Quote()':
if do_patch:
# add a new attribute to the class which happens to be
# an overwriting. You can add more functions to the class
# too if you need to.
IssueTracker.IssueTracker.showSignature = showSignature_Quote
LOG("ExampleITPMonkey", INFO, "IssueTrackerProduct patched")
Having the LOG message there might be overkill but it might serve as a good reminder if you forget why they quotes appear non-standard in the future.
Discussion
This example is dirt simple but should at least prove to people that it's possible to improve the IssueTrackerProduct code without having to hack its source or ask for feature requests on RealAdvanced note
This patch modifies all instances of the IssueTrackerProduct. You might want to write more code to make it possible to choose which instances should use the patch. To get you started I suggest you develop aSimpleItem and Persistent based class with your patch and then allow ZMI Managers deploy these kind of objects inside the instances.