Zope: cannot access REQUEST under property decorator

properties, python, request, zope

Solution

The `property` decorator only works with new-style classes; that is to say, classes that inherit from `object`. Acquisition (which gives you access to the global `REQUEST` object via attribute access) on the other hand is very much 'old-skool' python and the two do not work well together, as `property` ignores acquisition wrappers, which are needed to acquire the `REQUEST` object.

Zope has it's own `property`-like method that pre-dates new-style classes and the `property` decorater, called `ComputedAttribute`, which actually predates the `property` decorator and new-style classes by many years. A `ComputedAttribute`-wrapped function does know how to behave with an `Acquisition`-wrapped object, though.

You can use `ComputedAttibute` much like the `property` decorator:

from ComputedAttribute import ComputedAttribute

class SomeClass():   
    @ComputedAttribute
    def someProperty(self):
        return 'somevalue'

The `ComputedAttribute` wrapper function also can be configured with a level of wrapping, which is what we need when dealing with Acquisition wrappers. You cannot use the `ComputedAttribute` as a decorator in that case:

class SomeClass():   
    def someValue(self):
        return self.REQUEST
    someValue = ComputedAttribute(someValue, 1)

It is easy enough to define a new function to do the decorating for us though:

from ComputedAttribute import ComputedAttribute

def computed_attribute_decorator(level=0):
    def computed_attribute_wrapper(func):
        return ComputedAttribute(func, level)
    return computed_attribute_wrapper

Stick this in a utility module somewhere, after which you can then use it as a callable decorator to mark something as an Acquisition-aware property:

class SomeClass(): 
    @computed_attribute_decorator(level=1)
    def someValue(self):
        return self.REQUEST

Note that unlike `property`, `ComputedAttribute` can only be used for getters; there is no support for setters or deleters.

Problem

I'm trying to use the property decorator in a Class. While it works well per se, I can't use any code that has to access the `REQUEST`. ``` class SomeClass(): #Zope magic code _properties=({'id':'someValue', 'type':'ustring', 'mode':'r'},) def get_someValue(self): return self.REQUEST @property def someValue(self): return self.REQUEST ``` Although calling `get_someValue` gets me the desired result, trying to access `someValue` raises an `AttributeError`. What's the logic behind this behaviour? Is there a way to get around this limitation? (I'm using Zope 2.13.16, Python 2.7.3)

Original source