zope2
2011-06-28
Getting the superclasses for a python object
Zope 2 (and Plone) persistent objects usually have an intricate inheritance tree. Finding what classes an object inherits can be a time consuming task, hunting through the various eggs for the relevant source code. Below is a little snippet that shows how to easily get the list of superclasses:
(Pdb) pp type(ff).mro() (<class 'plone.app.blob.subtypes.image.ExtensionBlobField'>, <class 'archetypes.schemaextender.field.TranslatableExtensionField'>, <class 'archetypes.schemaextender.field.BaseExtensionField'>, <class 'plone.app.blob.field.BlobField'>, <class 'Products.Archetypes.Field.ObjectField'>, <class 'Products.Archetypes.Field.Field'>, <class 'Products.Archetypes.Layer.DefaultLayerContainer'>, <class 'plone.app.blob.mixins.ImageFieldMixin'>, <class 'Products.Archetypes.Field.ImageField'>, <class 'Products.Archetypes.Field.FileField'>, <type 'ExtensionClass.Base'>, <type 'object'>)
Credit goes to the original post where I found this.
2011-02-08
Set product configuration globally in zope.conf
I have a Zope product that needs to write in a centralized location, across multiple instances. The classic Python solution would be to write a variable in a config.py module and read that location from the code, but this feels unelegant in an environment that uses zc.buildout for deployment. The solution I have found is, as follows:
In buildout.cfg, in the instance part definition, add:
zope-conf-additional =
<environment>
mylocation ${buildout:directory}/var/mylocation
</environment>
Next, inside the product code I have:
from App.config import getConfiguration import os conf = getConfiguration() dest = conf.environment['mylocation'] if not os.path.exists(dest): os.mkdir(dest)
There were 2 things that I had to research for this task: reading the global zope configuration (that's done with App.config.getConfiguration()) and the fact that you can't add arbitrary key/values in zope.conf and have to use the <environment> section.
2009-02-28
Success on a one year old problem installing CacheFu
I've upgraded CacheFu (Products.CacheSetup) to the latest 1.2 for some of the websites that I manage, in a Plone 2.5 cluster. One of them had a problem that I haven't been able to track previously, due to limited time: on a reinstall of CacheSetup, due to product upgrades, CacheFu couldn't be installed anymore. The traceback was something like:
this product has already been installed without Quickinstaller!failed:
Traceback (most recent call last):
File "/home/zope/z29/Products/CMFQuickInstallerTool/QuickInstallerTool.py", line 330, in installProduct
File "/home/zope/p25/parts/zope2/lib/python/Products/ExternalMethod/ExternalMethod.py", line 225, in __call__
try: return f(*args, **kw)
File "/home/zope/p25/eggs/Products.CacheSetup-1.2-py2.4.egg/Products/CacheSetup/Extensions/Install.py", line 35, in install
policy_utils.addCachePolicies(self, out)
File "/home/zope/p25/eggs/Products.CacheSetup-1.2-py2.4.egg/Products/CacheSetup/Extensions/policy_utils.py", line 72, in addCachePolicies
p.addCacheRules(rules)
File "/home/zope/p25/eggs/Products.CacheSetup-1.2-py2.4.egg/Products/CacheSetup/Extensions/policy_2.py", line 13, in addCacheRules
rules.invokeFactory(id=id, type_name='PolicyHTTPCacheManagerCacheRule')
File "/home/zope/z29/Products/CMFCore/PortalFolder.py", line 408, in invokeFactory
File "/home/zope/z29/Products/CMFCore/TypesTool.py", line 934, in constructContent
File "/home/zope/z29/Products/CMFCore/TypesTool.py", line 343, in constructInstance
File "/home/zope/z29/Products/CMFCore/TypesTool.py", line 574, in _constructInstance
File "", line 6, in addPolicyHTTPCacheManagerCacheRule
File "/home/zope/p25/parts/zope2/lib/python/OFS/ObjectManager.py", line 301, in _setObject
v = self._checkId(id)
File "/home/zope/z29/Products/CMFCore/Skinnable.py", line 223, in _checkId
File "/home/zope/p25/parts/zope2/lib/python/OFS/ObjectManager.py", line 95, in checkValidId
raise BadRequest, (
BadRequest: The id "httpcache" is invalid - it is already in use.
One other weird thing are the paths in this traceback: /home/zope/z29 doesn't exist anymore, the database was moved from a different server. I think it's related to the persistent product entries in the Control_Panels, which can be cleared. Not a big problem. In the log, there was also an entry related to this traceback:
2009-02-28 17:01:18 CRITICAL txn.-1223480432 A storage error occurred during the second phase of the two-phase commit. Resources may be in an inconsistent state
Now, the solution is really simple, but I needed to debug the policy_2 module to find this:
rules.invokeFactory(id=id, type_name='PolicyHTTPCacheManagerCacheRule')
didn't work because there was a document in the root called "rules". Nobody expects the spamish Acquisition! And I didn't either... Lesson? Zope 2 was designed to be too smart for its own good, thus violating the KISS principle. Still love it, though.
2009-02-11
Variable keys in dictionaries with Page Templates TALES syntax
I admit, I didn't knew this until now. In the following construction:
<div tal:content="somedict/keyname/someattr" />
"keyname" is taken as a string, it's the literal name of the key for the somedict mapping. To use a variable instead of the literal value of the key name, I used to do:
<div tal:content="python somedict[key].someattr" />
Browsing through the zope.app.catalog code, I saw that there's actually a way to use the TALES syntax:
<div tal:content="somedict/?key/someattr" />
I'm not sure that this works with TTW code in Zope 2 (I expect that it works with browser views), so I'll just have to try this next time I have the chance.
2008-08-22
Bug in PyPi
The zope.app.form PyPi page looks awful, it should be fixed. Who's fault is that? Django, the framework that sits underneath (AFAIK), or the docutils libraries that probably parse the RST pages?
2008-07-11
Hosting Plone and Zope 3 applications using nginx
I'm doing a setup on a new server, I've decided to replace the default Apache 2.2 with an nginx http server. The setup which is needed for Zope 3 and Plone applications is the following:
[buildout]
parts =
nginx
nginxctl
[nginx]
recipe = gocept.cmmi
url = http://sysoev.ru/nginx/nginx-0.7.6.tar.gz
md5sum = ae7ce6f66a2cf5a5970d9a9a0da0cf7d
[nginxctl]
recipe = gocept.nginx
hostname = localhost
port = 80
configuration =
worker_processes 1;
events {
worker_connections 1024;
}
http {
upstream z3 {
server 127.0.0.1:8080;
}
upstream plone {
server 127.0.0.1:9080;
}
server {
listen ${nginxctl:port};
server_name z3.example.org;
root html;
include /etc/nginx/proxy.conf
location / {
proxy_pass http://z3/++lang++ro/++skin++myskin/mysite/++vh++http:z3.example.org:80/++/;
}
}
server {
server_name plone.example.org;
include /etc/nginx/proxy.conf
location / {
proxy_pass http://plone/VirtualHostBase/http/plone.example.org:80/t1/VirtualHostRoot/;
}
}
server {
server_name plone.example.org;
rewrite ^/(.*) /VirtualHostBase/http/plone.example.org:80/t1/VirtualHostRoot/$1 last;
location / {
proxy_pass http://plone;
}
}
}
Note: this is a buildout.cfg. Using it together with zc.buildout makes the nginx instalation a very simple process: install zc.buildout (easy_install zc.buildout), and then run buildout in the folder that contains the .cfg file.
The settings in proxy.conf are important. Without a valid proxy_temp_path, for some reason delivery of all content that came from a Plone 2.5 site that used CacheFu setup with no proxy cache was freezing at 16014 bytes. The paths in /var/nginx need to be created and set to be writable by the nginx process (user nobody in my case).
client_max_body_size 0; client_body_buffer_size 128k; client_body_temp_path /var/nginx/client_body_temp; proxy_connect_timeout 90; proxy_send_timeout 90; proxy_read_timeout 90; proxy_buffer_size 4k; proxy_buffers 4 32k; proxy_busy_buffers_size 64k; proxy_temp_file_write_size 64k; proxy_temp_path /var/nginx/proxy_temp; proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
Resources
A more complete nginx sample configuration file (but that only covers how to configure Plone)
Grok guide on hosting Zope 3 with nginx (note, at this moment the document is wrong, the setup line is missing a slash at the end).
2008-06-01
Using views as information mixins in templates
This may be basic trick for some, a non-obvious usage of views for others, who knows, I'm documenting it here anyway. I've been using this technique for quite some time without giving it much thought.
There are times when I have an object in a template. I want to display information associated with that object. This information is already coded in a @@detail view on this object. Suppose this example (in mostly pseudocode):
class PersonDetail(BrowserView):
"""Show detail about a person"""
def name(self):
return compute_somehow_name()
class CommentDetail(BrowserView):
"""Show details about a comment"""
Now we have the following template for the CommentDetail view:
<div tal:define='person comment/author; person_info nocall:person/@@detail'>
<a tal:attributes="href person/@@absolute_url" tal:content="person_info/name">The author</a>
</div>
Notice the nocall: keyword placed in from of the person/@@detail call. This ensures that the @@detail view is instantiated, but not called (so it is not rendered). This way we have access to the view class attributes, properly associated to the Person context.
2008-04-15
In case you're having problems installing ssl-for-setuptools...
I've stumbled on this error when trying to install a easyshop buildout:
Exception: No SSL support found
An error occured when trying to install ssl-for-setuptools 1.10.Look above this message for any errors thatwere output by easy_install.
While:
Installing instance.
Getting distribution for 'ssl-for-setuptools'.
Error: Couldn't install: ssl-for-setuptools 1.10
After scratching my head for a while, I've found the solution:
# apt-get install libssl-dev
2008-04-08
A tip on debugging Zope 2 with ZEO
I'm having some troubles with CacheFu, and I've resorted to deleting some objects from a debug prompt, which is very easy to get at if one runs the Zope under ZEO. Still, I couldn't delete the objects because I was getting Unauthorized errors. Luckily, there is #plone, from which I got the following tip:
<naro> from AccessControl.SecurityManagement import newSecurityManager
<naro> user = app.acl_users.getUser('admin')
<naro> newSecurityManager(None, user)
Thanks, naro!
Update: I realize now that I didn't write how to connect to ZEO:
#bin/instance debug
or
#bin/zopectl debug
This will connect the ZEO client and drop you in a python shell
2007-03-26
Open source Zope app in the news!
Today, on the front page of Slashdot, there was a link for an open source server monitoring & system management application. Well, what do you know, it runs on Zope 2! The visible source code is here
2007-02-10
Zope buildout quickstart
One of the bigger players in the latest move to automate Plone and Zope development and deployment has been buildout, so I figured it's about time to start learning it and see how it can help me. I'm writing this short recipe as I progress through learning buildout to help me remember this stuff later on.
Installing buildout
The easiest way to install buildout is to get easy_install (a manager for python packages) on your system. In order to get it installed, I had to do: (based on a custom python 2.4.3 installation in /opt/python):
$mkdir ~/buildout_play
$cd ~/buildout_play
$wget http://peak.telecommunity.com/dist/ez_setup.py
$sudo /opt/python/bin/python ez_setup.py
Next, install the zc.buildout package, using easy_install:
/opt/python/bin/easy_install zc.buildout
This will install the buildout egg in the python site-packages folder and create a 'buildout' script in the scripts folder, in my case /opt/python/bin/buildout.
Next, transform the buildout_play folder in buildout folder, by running:
/opt/python/bin/buildout -v
This will "bootstrap" that folder and prepare it as a buildout environment, also installing the setuptools and zc.buildout eggs. The buildout script will check every time it's being ran if those eggs are at their latest version, run it with the -N option if you want to skip that.
As a simple test for buildout, I've modified my buildout.cfg to contain the following lines:
[buildout]
parts = checkout
[checkout]
recipe = zc.recipe.zope3checkout
url = svn://svn.zope.org/repos/main/Zope3/trunk
This tells buildout to include a part named checkout, which is defined to use the "zc.recipe.zope3checkout" recipe, that is configured with the "url" option. Running
/opt/python/bin/buildout -v -N
will automatically grab the zc.recipe.zope3checkout egg, do a svn checkout in the parts/checkout folder and then compile in place the zope 3 checkout.
When developing new projects, to make this process easier, it is possible to put a bootstrap.py script in the folder where you're developing, which will automatically install setuptools (easy_install) and zc.buildout, transform that folder in a buildout folder and put a bin/bootstrap script that can be ran to do the build.
These are the basics to get started, see below for further details.
Reference
2006-11-23
Setting a dynamic i18n:domain in a ZPT template
<h2 tal:define="statusMessage python:request.get('statusMessage');
domain python:request.get('domain')"
tal:attributes="i18n:domain domain;
i18n:translate string:">someText</h2>
2006-11-07
Getting the parent object in an acquisition context
To get the parent of an object, you'd have to use this code:
myparent = aq_inner.aq_parent.aq_self
2006-10-21
Deliverence - serving semi-static content out of a live site
Deliverance is a lightweight, semi-static system for content delivery of CMS resources. It runs in mod_python, generating branded pages and navigation elements, giving high-performance throughput to anonymous visitors.
Sounds interesting, especially in light of my contact with owners of bigger sites and editorial staff.
This product can be downloaded from http://codespeak.net/svn/z3/deliverance/
2006-10-07
Creating zope content
I had a need to create new external methods on install of a product. So, even if technique is old and well know to any Zope 2 old-timer, I'm placing this here for my own reference.
def install(portal):
portal.manage_addProduct['ExternalMethod'].manage_addExternalMethod(
id = 'emailMe',
title='emailMe',
module='MyProduct.emailMe',
function='emailMe')
The code needs to interact with a legacy module (renamed here emailMe). The idea is that manage_addProduct returns a dictionary of factories and manage_addExternalMethod is the factory method defined in the ExternalMethod module. Most of the old style Zope content can be added this way.
2006-10-04
Start Plone (or Zope) in debug mode under Windows
Lifted from #plone:
bin/runzope.bat -X "debug-mode=on"
2006-10-03
Fixing a zope database with fsrecover.py
Due to hardware corruption I have a broken Data.fs that won't pack. To fix it the fsrecover.py script from the ZODB module can be used. For example, this is how to run the script to repair the broken database (I have zope installed in /opt/Zope2.8):
cd /opt/Zope2.8/lib/python/
python ZODB/fsrecover.py -v 1 /mnt/raid/Data.fs /mnt/raid/Data.fs.fixed
The reason to run the fsrecover script with ZODB in front is that it imports from the ZODB module. Normally the ZODB module wouldn't be in the python path, so using this trick solves this problem. The -v 1 argument makes fsrecover print the information on the current processed transaction.
2006-10-02
Moving a Zope instance
To move a zope instance location 3 files need to be edited in order to update the software home location:
- runzope
- zopectl
- etc/zope.conf (change the software home location, right at the top of the file)
Override __bobo_traverse__ to provide custom URL lookup
This technique is lifted from ATContentTypes/content/image.py
def __bobo_traverse__(self, REQUEST, name):
"""Transparent access to image scales
"""
if name.startswith('image'):
field = self.getField('image')
image = None
if name == 'image':
image = field.getScale(self)
else:
scalename = name[len('image_'):]
if scalename in field.getAvailableSizes(self):
image = field.getScale(self, scale=scalename)
if image is not None and not isinstance(image, basestring):
# image might be None or '' for empty images
return image
return ATCTFileContent.__bobo_traverse__(self, REQUEST, name)
2006-08-14
Short intro to ZEO
Joel Burton is holding ad-hoc tutorials on IRC :-)
Anyway, here's his recipe to running ZEO
<joelburton> having your site running under zeo also allows you to "zopectl debug" it while it's still running, which is insanely useful. i _always_ run zope under zeo, even during development, even on my laptop, etc., and i recommend that to others.
<joelburton> thegoldenaura: zeo just splits zope-the-app-server and zope-the-database into two
<joelburton> the goldenaura: for small sites, where you expect to have just one zope server for your zeo server, i do it like this:
<joelburton> 1) use $ZOPE/bin/mkzeoinstance to make a zeo instance. for these small instances, i put it in $INSTANCE_HOME/zeo
<joelburton> 2) stop your zope instance; move your Data.fs from $INSTANCE_HOME/var to $INSTANCE_HOME/zeo/var
<joelburton> 3) edit your $INSTANCE_HOME/zope.conf to comment out the normal main storage, and ot use the ZEO storage (both at the bottom)
<joelburton> 4) start up zeo and zope