Commit 9de6c065 authored by Arnaud Fontaine's avatar Arnaud Fontaine

Add Property Type Validity Constraint for ZODB Property Sheets and its test


git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@40945 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 93b3d86b
##############################################################################
#
# Copyright (c) 2002, 2005 Nexedi SARL and Contributors. All Rights Reserved.
# Sebastien Robin <seb@nexedi.com>
# Jean-Paul Smets <jp@nexedi.com>
# Romain Courteaud <romain@nexedi.com>
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# garantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
##############################################################################
from Products.ERP5Type.mixin.constraint import ConstraintMixin
from Products.ERP5Type import PropertySheet
from DateTime import DateTime
class PropertyTypeValidityConstraint(ConstraintMixin):
"""
This constraint class allows to check / fix type of each attributes
defined in the PropertySheets.
This is only relevant for ZODB Property Sheets (filesystem Property
Sheets rely on Products.ERP5Type.Constraint.PropertyTypeValidity
instead).
"""
meta_type = 'ERP5 Property Type Validity Constraint'
portal_type = 'Property Type Validity Constraint'
property_sheets = (PropertySheet.SimpleItem,
PropertySheet.Predicate,
PropertySheet.Reference,
PropertySheet.PropertyTypeValidityConstraint)
# Initialize type dict
_type_dict = {
'string': (str, ),
'text': (str, ),
'int': (int, ),
'boolean': (int, bool),
'float': (float, ),
'long': (long, ),
'tales': (str, ),
'lines': (list, tuple),
'tokens': (list, tuple),
'selection': (list, tuple),
'multiple selection': (list, tuple),
'date': (DateTime, ),
}
# Properties of type eg. "object" can hold anything
_permissive_type_list = ('object', 'data')
def checkConsistency(self, obj, fixit=0):
"""
Check the object's consistency.
"""
if not self.test(obj):
return []
error_list = []
# For each attribute name, we check type
for prop in obj.propertyMap():
property_id = prop['id']
if prop.get('multivalued', 0):
property_type = 'lines'
else:
property_type = prop['type']
# if this property was a local property and has been later added in a
# property sheet, we want to remove it from _local_properties
if fixit and \
property_id in [x['id'] for x in
getattr(obj, '_local_properties', ())] and \
len([x for x in obj._propertyMap() if x['id'] == property_id]) > 1:
obj._local_properties = tuple([x for x in obj._local_properties
if x['id'] != property_id])
if property_type in self._permissive_type_list:
continue
wrong_type = 0
if property_type == 'tales':
value = obj.getProperty(property_id, evaluate=0)
else:
value = obj.getProperty(property_id)
if value is not None:
# Check known type
try:
wrong_type = not isinstance(value, self._type_dict[property_type])
except KeyError:
wrong_type = 0
error_list.append(self._generateError(obj,
self._getMessage('message_unknown_type'),
mapping=dict(attribute_name=property_id,
type_name=property_type)))
if wrong_type:
# Type is wrong, so, raise constraint error
error_message = 'message_incorrect_type'
mapping = dict(attribute_name=property_id,
expected_type=property_type,
actual_type=str(type(value)))
if fixit:
# try to cast to correct type
if wrong_type:
try:
value = self._type_dict[property_type][0](value)
except (KeyError, ValueError), error:
error_message = 'message_incorrect_type_fix_failed'
mapping['type_cast_error'] = str(error)
else:
obj.setProperty(property_id, value)
error_message = 'message_incorrect_type_fixed'
error_list.append(self._generateError(obj,
self._getMessage(error_message), mapping))
elif fixit:
oldvalue = getattr(obj, property_id, value)
if oldvalue != value:
obj.setProperty(property_id, oldvalue)
return error_list
############################################################################## ##############################################################################
# #
# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved. # Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved.
# Arnaud Fontaine <arnaud.fontaine@nexedi.com>
# #
# WARNING: This program as such is intended to be used by professional # WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsability of assessing all potential # programmers who take the whole responsability of assessing all potential
...@@ -26,12 +27,32 @@ ...@@ -26,12 +27,32 @@
############################################################################## ##############################################################################
class PropertyTypeValidityConstraint: class PropertyTypeValidityConstraint:
"""Property sheet to enable Property Type Validity Constraint
""" """
Define an Attribute Equality Constraint for ZODB Property Sheets
_constraints = ( """
{ 'type': 'PropertyTypeValidity', _properties = (
'id': 'type_check', {'id': 'message_unknown_type',
'description': "Type Validity Check Error", 'type': 'string',
}, 'description' : "Error message when the attribute's type is unknown",
'default': "Attribute ${attribute_name} is defined with an unknown "\
"type ${type_name}" },
{'id': 'message_incorrect_type',
'type': 'string',
'description' : "Error message when the type of attribute's value is "\
"incorrect",
'default': "Attribute ${attribute_name} should be of type "\
"${expected_type} but is of type ${actual_type}" },
{'id': 'message_incorrect_type_fix_failed',
'type': 'string',
'description' : "Error message when the type of attribute's value is "\
"incorrect and it could not be fixed",
'default': "Attribute ${attribute_name} should be of type "\
"${expected_type} but is of type ${actual_type} (Type cast "\
"failed with error ${type_cast_error})" },
{'id': 'message_incorrect_type_fixed',
'type': 'string',
'description' : "Error message when the type of attribute's value is "\
"incorrect but could be fixed",
'default': "Attribute ${attribute_name} should be of type "\
"${expected_type} but is of type ${actual_type} (Fixed)" },
) )
...@@ -25,3 +25,4 @@ from CategoryMembershipArityConstraint import CategoryMembershipArityConstraint ...@@ -25,3 +25,4 @@ from CategoryMembershipArityConstraint import CategoryMembershipArityConstraint
from CategoryRelatedMembershipArityConstraint import \ from CategoryRelatedMembershipArityConstraint import \
CategoryRelatedMembershipArityConstraint CategoryRelatedMembershipArityConstraint
from TALESConstraint import TALESConstraint from TALESConstraint import TALESConstraint
from PropertyTypeValidityConstraint import PropertyTypeValidityConstraint
...@@ -459,6 +459,15 @@ class TestZodbPropertySheet(ERP5TypeTestCase): ...@@ -459,6 +459,15 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
portal_type='TALES Constraint', portal_type='TALES Constraint',
expression='python: object.getTitle() == "my_tales_constraint_title"') expression='python: object.getTitle() == "my_tales_constraint_title"')
def _newPropertyTypeValidityConstraint(self):
"""
Create a new Property Type Validity Constraint within test
Property Sheet
"""
self.test_property_sheet.newContent(
reference='test_property_type_validity_constraint',
portal_type='Property Type Validity Constraint')
def afterSetUp(self): def afterSetUp(self):
""" """
Create a test Property Sheet (and its properties) Create a test Property Sheet (and its properties)
...@@ -512,6 +521,9 @@ class TestZodbPropertySheet(ERP5TypeTestCase): ...@@ -512,6 +521,9 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
# Create a TALES Constraint in the test Property Sheet # Create a TALES Constraint in the test Property Sheet
self._newTALESConstraint() self._newTALESConstraint()
# Create a Property Type Validity Constraint in the test Property Sheet
self._newPropertyTypeValidityConstraint()
# Create all the test Properties # Create all the test Properties
for operation_type in ('change', 'delete', 'assign'): for operation_type in ('change', 'delete', 'assign'):
self._newStandardProperty(operation_type) self._newStandardProperty(operation_type)
...@@ -994,6 +1006,19 @@ class TestZodbPropertySheet(ERP5TypeTestCase): ...@@ -994,6 +1006,19 @@ class TestZodbPropertySheet(ERP5TypeTestCase):
self.test_module.setTitle, self.test_module.setTitle,
'my_tales_constraint_title') 'my_tales_constraint_title')
def testPropertyTypeValidityConstraint(self):
"""
Take the test module and check whether the Property Type Validity
Constraint is there, then set the title of Test Module to any
value besides of a string. Until the title of Test Module has been
set to any string, the constraint should fail
"""
self.test_module.title = 123
self._checkConstraint('test_property_type_validity_constraint',
self.test_module.setTitle,
'my_property_type_validity_constraint_title')
TestZodbPropertySheet = skip("ZODB Property Sheets code is not enabled yet")( TestZodbPropertySheet = skip("ZODB Property Sheets code is not enabled yet")(
TestZodbPropertySheet) TestZodbPropertySheet)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment