Extending Zope Dynamically
Created by .
Last modified on 2003/08/05.
Zope's built in functionality is quite impressive.
It's object model is full and there are many
classes to choose from. However, many times a
Zope object or management screen lacks a certain
feature that would like to have. There might also be
a product out there that you really like except for
a few things...
Waiting for ZC or the product's author to include the
feature you want is not usually a good option, since your
feature is likely more important to you than to them (that
is not to say you shouldn't suggest the change of course).
So, you decide to take advantage of the open source nature
of Zope and hack in the feature yourself.
But... You quickly come to the realization that
any changes you make to Zope or the Product could be
obliterated when you install a new version. And since new
versions of Zope come out as often as they open a new
Starbucks, this is a major problem with your plan.
So, what do you do?
Python to the Rescue
Python is a highly dynamic language as you well
know if you've done much programming with it. By dynamic
I mean you can put everything off until run-time. You
can define classes and functions, modify existing classes,
the list goes on and on. The latter is the feature explained
in this how-to. How to modify existing Zope classes at
run-time, without touching the code of Zope itself!
To modify Zope dynamically, we must have Zope execute
some code we write when Zope is started. Luckily, this is
trivial to do. Creating a simple Python Zope product is
all it takes. Here are the basic steps we need to modify
Zope through a monkey patch:
- Create a product directory under {Zope dir}/lib/python/Products
- Add an __init__.py file in the product directory.
- In the __init__ module, import the classes that you
want to modify, and change away!
Obviously the last step can be as simple or complex as you
like.
A Simple Example
Let's say you want to add a management tab to all DTML method objects
in Zope. For our example, we will create a simple tab that displays
the size of the method code in bytes. Here is the code to insert into
__init__.py:
1: """Simple Monkey Patch"""
2: from OFS.DTMLMethod import DTMLMethod
3:
4: def manage_showSize(self):
5: """Show method size"""
6: return "<p>%d bytes</p>" % self.get_size()
7:
8: DTMLMethod.manage_showSize = manage_showSize
9: DTMLMethod.manage_options = DTMLMethod.manage_options + \
10: ({"label": "Size", "action": "manage_showSize"},)
Lets take a closer look at what each line does:
2: |
Imports the DTMLMethod class from OFS.DTMLMethod in the Zope core. |
| 4-6:
Defines a method to display the size of the DTMLMethod.
get_size is an existing method of the DTMLMethod class.
(Remember that public methods called from Zope must
have a doc string). |
8: |
Adds the new method to the class dynamically. This is the magic
given to us by Python. |
9-10: |
Modifies the manage_options attribute of the
DTMLMethod class which tells Zope what tabs to draw in
the management interface and
what method to call when someone clicks the tab. |
Since we are modifying the DTMLMethod class, all existing
and new instances will be affected. So, once this code is in place,
and you restart Zope, all DTML
methods will have your new tab! And since this code is separate
from the core module, it will survive upgrading to new Zope
versions and can easily be applied to several Zope installs.
Our example adds a new feature to a class, but the same
technique can be used to override an existing method, such as
replacing a management screen with an improved
version written by you.
Other Ideas
Here are some other ideas on how you could use Monkey Patches:
- Add new capabilities to existing objects, such as
making DTML documents and methods render themselves
when they are cataloged.
- Modify property sheets to allow your own custom data
types.
- Add custom options to existing dtml tags.
Obviously you must take care not to get too overzealous.
You can also easily create bugs and security holes using these
techniques. Remember, though that this is a perfect way to
experiment, because you can simply remove your product's
folder to restore Zope back to original. You never need to
touch any of Zope's code!