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)
The
property
decorator only works with new-style classes; that is to say, classes that inherit fromobject
. Acquisition (which gives you access to the globalREQUEST
object via attribute access) on the other hand is very much 'old-skool' python and the two do not work well together, asproperty
ignores acquisition wrappers, which are needed to acquire theREQUEST
object.Zope has it's own
property
-like method that pre-dates new-style classes and theproperty
decorater, calledComputedAttribute
, which actually predates theproperty
decorator and new-style classes by many years. AComputedAttribute
-wrapped function does know how to behave with anAcquisition
-wrapped object, though.You can use
ComputedAttibute
much like theproperty
decorator: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 theComputedAttribute
as a decorator in that case:It is easy enough to define a new function to do the decorating for us though:
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:
Note that unlike
property
,ComputedAttribute
can only be used for getters; there is no support for setters or deleters.If you want to route around needing acquisition and cannot explicitly set the request from calling code in the constructor of your class, use zope.globalrequest. Otherwise, you may want to consider a browser view (which always multi-adapts some context and a request).