mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-01-19 14:32:16 +00:00
151 lines
4.7 KiB
Python
151 lines
4.7 KiB
Python
##############################################################################
|
|
#
|
|
# Copyright (c) 2002 Zope Foundation and Contributors.
|
|
# All Rights Reserved.
|
|
#
|
|
# This software is subject to the provisions of the Zope Public License,
|
|
# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
|
|
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
|
|
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
|
|
# FOR A PARTICULAR PURPOSE.
|
|
#
|
|
##############################################################################
|
|
"""Computed attributes based on schema fields
|
|
"""
|
|
|
|
from copy import copy
|
|
import sys
|
|
import zope.schema
|
|
from zope import interface
|
|
from zope import event
|
|
from zope.schema import interfaces
|
|
from zope.schema._bootstrapinterfaces import NO_VALUE
|
|
|
|
_marker = object()
|
|
|
|
|
|
@interface.implementer(interfaces.IFieldUpdatedEvent)
|
|
class FieldUpdatedEvent(object):
|
|
|
|
def __init__(self, inst, field, old_value, new_value):
|
|
self.inst = inst
|
|
self.field = field
|
|
self.old_value = old_value
|
|
self.new_value = new_value
|
|
|
|
|
|
class FieldProperty(object):
|
|
"""Computed attributes based on schema fields
|
|
|
|
Field properties provide default values, data validation and error messages
|
|
based on data found in field meta-data.
|
|
|
|
Note that FieldProperties cannot be used with slots. They can only
|
|
be used for attributes stored in instance dictionaries.
|
|
"""
|
|
|
|
def __init__(self, field, name=None):
|
|
if name is None:
|
|
name = field.__name__
|
|
|
|
self.__field = field
|
|
self.__name = name
|
|
|
|
def __get__(self, inst, klass):
|
|
if inst is None:
|
|
return self
|
|
|
|
value = inst.__dict__.get(self.__name, _marker)
|
|
if value is _marker:
|
|
field = self.__field.bind(inst)
|
|
value = getattr(field, 'default', _marker)
|
|
if value is _marker:
|
|
raise AttributeError(self.__name)
|
|
|
|
return value
|
|
|
|
def queryValue(self, inst, default):
|
|
value = inst.__dict__.get(self.__name, default)
|
|
if value is default:
|
|
field = self.__field.bind(inst)
|
|
value = getattr(field, 'default', default)
|
|
return value
|
|
|
|
def __set__(self, inst, value):
|
|
field = self.__field.bind(inst)
|
|
field.validate(value)
|
|
if field.readonly and self.__name in inst.__dict__:
|
|
raise ValueError(self.__name, 'field is readonly')
|
|
oldvalue = self.queryValue(inst, NO_VALUE)
|
|
inst.__dict__[self.__name] = value
|
|
event.notify(FieldUpdatedEvent(inst, field, oldvalue, value))
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self.__field, name)
|
|
|
|
|
|
def createFieldProperties(schema, omit=[]):
|
|
"""Creates a FieldProperty fields in `schema` on the class it is called on.
|
|
|
|
schema ... interface those fields should be added to class
|
|
omit ... list of field names to be omitted in creation
|
|
|
|
"""
|
|
frame = sys._getframe(1)
|
|
for name in zope.schema.getFieldNamesInOrder(schema):
|
|
if name in omit:
|
|
continue
|
|
frame.f_locals[name] = FieldProperty(schema[name])
|
|
|
|
|
|
class FieldPropertyStoredThroughField(object):
|
|
|
|
def __init__(self, field, name=None):
|
|
if name is None:
|
|
name = field.__name__
|
|
|
|
self.field = copy(field)
|
|
self.field.__name__ = "__st_%s_st" % self.field.__name__
|
|
self.__name = name
|
|
|
|
def setValue(self, inst, field, value):
|
|
field.set(inst, value)
|
|
|
|
def getValue(self, inst, field):
|
|
return field.query(inst, _marker)
|
|
|
|
def queryValue(self, inst, field, default):
|
|
return field.query(inst, default)
|
|
|
|
def __getattr__(self, name):
|
|
return getattr(self.field, name)
|
|
|
|
def __get__(self, inst, klass):
|
|
if inst is None:
|
|
return self
|
|
|
|
field = self.field.bind(inst)
|
|
value = self.getValue(inst, field)
|
|
if value is _marker:
|
|
value = getattr(field, 'default', _marker)
|
|
if value is _marker:
|
|
raise AttributeError(self.__name)
|
|
|
|
return value
|
|
|
|
def __set__(self, inst, value):
|
|
field = self.field.bind(inst)
|
|
field.validate(value)
|
|
if field.readonly:
|
|
if self.queryValue(inst, field, _marker) is _marker:
|
|
field.readonly = False
|
|
self.setValue(inst, field, value)
|
|
field.readonly = True
|
|
return
|
|
else:
|
|
raise ValueError(self.__name, 'field is readonly')
|
|
oldvalue = self.queryValue(inst, field, NO_VALUE)
|
|
self.setValue(inst, field, value)
|
|
event.notify(FieldUpdatedEvent(inst, self.field, oldvalue, value))
|