Package platecom :: Package utils :: Module fieldproperty
[hide private]
[frames] | no frames]

Source Code for Module iccommunity.core.fieldproperty

  1  """Field properties based on Archetypes schema 
  2  """ 
  3   
  4  from zope.app.component.hooks import getSite 
  5   
6 -class ATFieldProperty(object):
7 """Field properties based on Archetypes schema 8 9 These properties can only be used on Archetypes objects. They delegate 10 to schema.getField(fieldname).get() and set(). 11 12 You can use it in your type as follows. The name of the field does 13 not need to conincide with the field-property name, but this is probably 14 sensible. However, AttributeStorage will interfere here, so we explicitly 15 use annoation storage. 16 17 >>> import string 18 >>> from Products.Archetypes.atapi import * 19 >>> from iccommunity.core.fieldproperty import ATFieldProperty 20 21 >>> class MyContent(BaseObject): 22 ... portal_type = meta_type = 'MyContent' 23 ... schema = Schema(( 24 ... StringField('some_field', storage=AnnotationStorage()), 25 ... StringField('_other_field'), 26 ... )) 27 ... 28 ... some_field = ATFieldProperty('some_field') 29 ... other_field = ATFieldProperty('_other_field') 30 ... upper_lower = ATFieldProperty('_other_field', 31 ... get_transform=string.upper, set_transform=string.lower) 32 33 >>> registerType(MyContent, 'Archetypes') 34 35 Now, get and set operations on the fieldproperty behave the same way as 36 the mutator and accessor. 37 38 >>> foo = MyContent('foo') 39 >>> foo.some_field 40 '' 41 >>> foo.some_field = "Bar" 42 >>> foo.some_field 43 'Bar' 44 >>> foo.getField('some_field').get(foo) 45 'Bar' 46 47 The old-style mutator and accessors still work, of course 48 49 >>> foo.getSome_field() 50 'Bar' 51 52 >>> foo.setSome_field("Baz") 53 >>> foo.some_field 54 'Baz' 55 56 Here is an example using the default AttributeStorage. In this case, we 57 need different names for the AT field name and the properity, because 58 AttributeStorage will use the field name as the attribute name. If 59 you don't do this, you may get infinite recursion! 60 61 >>> foo.other_field = "Hello" 62 >>> foo.other_field 63 'Hello' 64 >>> foo.get_other_field() 65 'Hello' 66 >>> foo.set_other_field("Good bye") 67 >>> foo.other_field 68 'Good bye' 69 70 Finally, the get_transform and set_transform arguments can be used to 71 perform transformations on the retrieved value and the value before it 72 is set, respectively. The field upper_lower uses string.upper() on the 73 way out and string.lower() on the way in. 74 75 >>> foo.upper_lower = "MiXeD" 76 >>> foo.upper_lower 77 'MIXED' 78 >>> foo.get_other_field() 79 'mixed' 80 >>> foo.set_other_field('UpPeRaNdLoWeR') 81 >>> foo.upper_lower 82 'UPPERANDLOWER' 83 84 A less frivolous example of this functionality can be seen in the 85 ATDateTimeFieldProperty class below. 86 """ 87
88 - def __init__(self, name, get_transform=None, set_transform=None):
89 self._name = name 90 self._get_transform = get_transform 91 self._set_transform = set_transform
92
93 - def __get__(self, inst, klass):
94 if inst is None: 95 return self 96 field = inst.getField(self._name) 97 if field is None: 98 raise KeyError("Cannot find field with name %s" % self._name) 99 value = field.get(inst) 100 if self._get_transform is not None: 101 value = self._get_transform(value) 102 return value
103
104 - def __set__(self, inst, value):
105 field = inst.getField(self._name) 106 if field is None: 107 raise KeyError("Cannot find field with name %s" % self._name) 108 if self._set_transform is not None: 109 value = self._set_transform(value) 110 field.set(inst, value)
111
112 -class ATToolDependentFieldProperty(ATFieldProperty):
113 """A version of the field property type which is able to acquire 114 tools. This uses a not-very-nice acquisition hack, and is not 115 generalisable to all acquisition-dependent operations, but should work 116 for tools in the portal root. 117 118 >>> from Products.Archetypes.atapi import * 119 >>> from iccommunity.core.fieldproperty import ATToolDependentFieldProperty 120 >>> from zope.app.component.hooks import setSite 121 >>> setSite(portal) 122 123 >>> class MyContent(BaseContent): 124 ... portal_type = meta_type = 'MyContent' 125 ... schema = Schema(( 126 ... ReferenceField('some_field', multiValued=True, 127 ... relationship='foo', storage=AnnotationStorage()), 128 ... )) 129 ... 130 ... some_field = ATToolDependentFieldProperty('some_field') 131 132 >>> registerType(MyContent, 'Archetypes') 133 134 >>> self.portal._setOb('foo', MyContent('foo')) 135 >>> foo = getattr(self.portal, 'foo') 136 137 These lines would fail with AttributeError: reference_catalog if it used 138 the standard accessor. 139 140 >>> foo.some_field 141 [] 142 >>> foo.some_field = [self.folder.UID()] 143 >>> foo.some_field 144 [<ATFolder at /plone/Members/test_user_1_>] 145 """ 146
147 - def __init__(self, name, get_transform=None, set_transform=None):
148 self._name = name 149 self._get_transform = get_transform 150 self._set_transform = set_transform
151
152 - def __get__(self, inst, klass):
153 if inst is None: 154 return self 155 field = inst.getField(self._name) 156 if field is None: 157 raise KeyError("Cannot find field with name %s" % self._name) 158 value = field.get(inst.__of__(getSite())) 159 if self._get_transform is not None: 160 value = self._get_transform(value) 161 return value
162
163 - def __set__(self, inst, value):
164 field = inst.getField(self._name) 165 if field is None: 166 raise KeyError("Cannot find field with name %s" % self._name) 167 if self._set_transform is not None: 168 value = self._set_transform(value) 169 field.set(inst.__of__(getSite()), value)
170
171 -class ATReferenceFieldProperty(ATToolDependentFieldProperty):
172 """A more friendly/use-case-specific name for ATReferenceFieldProperty. 173 """
174
175 -class ATFieldMultilingualProperty(object):
176 """Field properties based on Archetypes schema 177 178 These properties can only be used on Archetypes objects. They delegate 179 to schema.getField(fieldname).get() and set(). 180 181 You can use it in your type as follows. The name of the field does 182 not need to conincide with the field-property name, but this is probably 183 sensible. However, AttributeStorage will interfere here, so we explicitly 184 use annoation storage. 185 186 >>> import string 187 >>> from Products.Archetypes.atapi import * 188 >>> from iccommunity.core.fieldproperty import ATFieldProperty 189 190 >>> class MyContent(BaseObject): 191 ... portal_type = meta_type = 'MyContent' 192 ... schema = Schema(( 193 ... StringField('some_field', storage=AnnotationStorage()), 194 ... StringField('_other_field'), 195 ... )) 196 ... 197 ... some_field = ATFieldProperty('some_field') 198 ... other_field = ATFieldProperty('_other_field') 199 ... upper_lower = ATFieldProperty('_other_field', 200 ... get_transform=string.upper, set_transform=string.lower) 201 202 >>> registerType(MyContent, 'Archetypes') 203 204 Now, get and set operations on the fieldproperty behave the same way as 205 the mutator and accessor. 206 207 >>> foo = MyContent('foo') 208 >>> foo.some_field 209 '' 210 >>> foo.some_field = "Bar" 211 >>> foo.some_field 212 'Bar' 213 >>> foo.getField('some_field').get(foo) 214 'Bar' 215 216 The old-style mutator and accessors still work, of course 217 218 >>> foo.getSome_field() 219 'Bar' 220 221 >>> foo.setSome_field("Baz") 222 >>> foo.some_field 223 'Baz' 224 225 Here is an example using the default AttributeStorage. In this case, we 226 need different names for the AT field name and the properity, because 227 AttributeStorage will use the field name as the attribute name. If 228 you don't do this, you may get infinite recursion! 229 230 >>> foo.other_field = "Hello" 231 >>> foo.other_field 232 'Hello' 233 >>> foo.get_other_field() 234 'Hello' 235 >>> foo.set_other_field("Good bye") 236 >>> foo.other_field 237 'Good bye' 238 239 Finally, the get_transform and set_transform arguments can be used to 240 perform transformations on the retrieved value and the value before it 241 is set, respectively. The field upper_lower uses string.upper() on the 242 way out and string.lower() on the way in. 243 244 >>> foo.upper_lower = "MiXeD" 245 >>> foo.upper_lower 246 'MIXED' 247 >>> foo.get_other_field() 248 'mixed' 249 >>> foo.set_other_field('UpPeRaNdLoWeR') 250 >>> foo.upper_lower 251 'UPPERANDLOWER' 252 253 A less frivolous example of this functionality can be seen in the 254 ATDateTimeFieldProperty class below. 255 """ 256
257 - def __init__(self, name, get_transform=None, set_transform=None):
258 self._name = name 259 self._get_transform = get_transform 260 self._set_transform = set_transform
261
262 - def __get__(self, inst, klass):
263 if inst is None: 264 return self 265 field = inst.getField(self._name) 266 if field is None: 267 raise KeyError("Cannot find field with name %s" % self._name) 268 value = field.get(inst) 269 if not value: 270 es_inst = inst.getTranslations()['es'][0] 271 field = es_inst.getField(self._name) 272 if field is None: 273 raise KeyError("Cannot find field with name %s" % self._name) 274 value = field.get(es_inst) 275 if self._get_transform is not None: 276 value = self._get_transform(value) 277 return value
278
279 - def __set__(self, inst, value):
280 field = inst.getField(self._name) 281 if field is None: 282 raise KeyError("Cannot find field with name %s" % self._name) 283 if self._set_transform is not None: 284 value = self._set_transform(value) 285 field.set(inst, value)
286 287 _marker = object() 288
289 -class ToolDependentFieldProperty(object):
290 """A version of the field property type for zope schemas which is 291 able to acquire tools. This uses a not-very-nice acquisition hack, 292 and is not generalisable to all acquisition-dependent operations, 293 but should work for tools in the portal root. 294 295 >>> from zope.interface import Interface, implements 296 >>> from zope import schema 297 >>> from OFS.SimpleItem import SimpleItem 298 >>> from iccommunity.core.fieldproperty import ToolDependentFieldProperty 299 >>> from zope.app.component.hooks import setSite 300 >>> setSite(portal) 301 302 >>> class IToolFields(Interface): 303 ... field1 = schema.List(title = u"field1", 304 ... required = False, 305 ... default = [], 306 ... description = u"Tool dependent field", 307 ... value_type=schema.Choice(vocabulary="plone.content_types")) 308 309 >>> class ToolFields(SimpleItem): 310 ... implements(IToolFields) 311 ... field1 = ToolDependentFieldProperty(IToolFields['field1']) 312 313 >>> self.portal._setOb('foo', ToolFields()) 314 >>> foo = getattr(self.portal, 'foo') 315 >>> foo.field1 316 [] 317 >>> foo.field1 = ['ATEvent',] 318 >>> foo.field1 319 ['ATEvent'] 320 321 """ 322
323 - def __init__(self, field, name=None, get_transform=None, set_transform=None):
324 if name is None: 325 name = field.__name__ 326 327 self.__field = field 328 self.__name = name 329 self._get_transform = get_transform 330 self._set_transform = set_transform
331
332 - def __get__(self, inst, klass):
333 if inst is None: 334 return self 335 336 value = inst.__dict__.get(self.__name, _marker) 337 if value is _marker: 338 site = getSite() 339 if not site: 340 # import pdb;pdb.set_trace() 341 raise AttributeError(self.__name) 342 field = self.__field.bind(inst.__of__(site)) 343 value = getattr(field, 'default', _marker) 344 if value is _marker: 345 raise AttributeError(self.__name) 346 347 if self._get_transform is not None: 348 value = self._get_transform(value) 349 return value
350
351 - def __set__(self, inst, value):
352 field = self.__field.bind(inst.__of__(getSite())) 353 field.validate(value) 354 if field.readonly and inst.__dict__.has_key(self.__name): 355 raise ValueError(self.__name, 'field is readonly') 356 if self._set_transform is not None: 357 value = self._set_transform(value) 358 inst.__dict__[self.__name] = value
359
360 - def __getattr__(self, name):
361 return getattr(self.__field, name)
362