# Copyright (C) 2009, Tutorius.org # # 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA """ Constraints Defines a set of constraints with their related errors. These constraints are made to be used inside TutoriusProperties in order to limit the values that they might take. They can also be used to enforce a particular format or type for some properties. """ # For the File Constraint import os class Constraint(): """ Basic block for defining constraints on a TutoriusProperty. Every class inheriting from Constraint will have a validate function that will be executed when the property's value is to be changed. """ def validate(self, value): """ This function receives the value that is proposed as a new value for the property. It needs to raise an Error in the case where the value does not respect this constraint. """ raise NotImplementedError("Unable to validate a base Constraint") class ValueConstraint(Constraint): """ A value constraint contains a _limit member that can be used in a children class as a basic value. See UpperLimitConstraint for an exemple. """ def __init__(self, limit): self.limit = limit class UpperLimitConstraintError(Exception): pass class UpperLimitConstraint(ValueConstraint): def validate(self, value): """ Evaluates whether the given value is smaller than the limit. @raise UpperLimitConstraintError When the value is strictly higher than the limit. """ if self.limit is not None: if self.limit >= value: return raise UpperLimitConstraintError() return class LowerLimitConstraintError(Exception): pass class LowerLimitConstraint(ValueConstraint): def validate(self, value): """ If the value is lower than the limit, this function raises an error. @raise LowerLimitConstraintError When the value is strictly smaller than the limit. """ if self.limit is not None: if value >= self.limit: return raise LowerLimitConstraintError() return class MaxSizeConstraintError(Exception): pass class MaxSizeConstraint(ValueConstraint): def validate(self, value): """ Evaluate whether a given object is smaller than the given size when run through len(). Great for string, lists and the like. ;) @raise SizeConstraintError If the length of the value is strictly bigger than the limit. """ if self.limit is not None: if self.limit >= len(value): return raise MaxSizeConstraintError("Setter : trying to set value of length %d while limit is %d"%(len(value), self.limit)) return class MinSizeConstraintError(Exception): pass class MinSizeConstraint(ValueConstraint): def validate(self, value): """ Evaluate whether a given object is smaller than the given size when run through len(). Great for string, lists and the like. ;) @raise SizeConstraintError If the length of the value is strictly bigger than the limit. """ if self.limit is not None: if self.limit <= len(value): return raise MinSizeConstraintError("Setter : trying to set value of length %d while limit is %d"%(len(value), self.limit)) return class ColorConstraintError(Exception): pass class ColorArraySizeError(ColorConstraintError): pass class ColorTypeError(ColorConstraintError): pass class ColorValueError(ColorConstraintError): pass class ColorConstraint(Constraint): """ Validates that the value is an array of size 3 with three numbers between 0 and 255 (inclusively) in it. """ def validate(self, value): if len(value) != 3: raise ColorArraySizeError("The value is not an array of size 3") if not (type(value[0]) == type(22) and type(value[1]) == type(22) and type(value[2]) == type(22)): raise ColorTypeError("Not all the elements of the array are integers") if value[0] > 255 or value[0] <0: raise ColorValueError("Red value is not between 0 and 255") if value[1] > 255 or value[1] <0: raise ColorValueError("Green value is not between 0 and 255") if value[2] > 255 or value[2] <0: raise ColorValueError("Blue value is not between 0 and 255") return class BooleanConstraintError(Exception): pass class BooleanConstraint(Constraint): """ Validates that the value is either True or False. """ def validate(self, value): if value == True or value == False: return raise BooleanConstraintError("Value is not True or False") class EnumConstraintError(Exception): pass class EnumConstraint(Constraint): """ Validates that the value is part of a set of well-defined values. """ def __init__(self, accepted_values): """ Creates the constraint and stores the list of accepted values. @param correct_values A list that contains all the values that will be declared as satisfying the constraint """ self._accepted_values = accepted_values def validate(self, value): """ Ensures that the value that is passed is part of the list of accepted values. """ if not value in self._accepted_values: raise EnumConstraintError("Value is not part of the enumeration") return class FileConstraintError(Exception): pass class FileConstraint(Constraint): """ Ensures that the string given corresponds to an existing file on disk. """ def validate(self, value): # TODO : Decide on the architecture for file retrieval on disk # Relative paths? From where? Support macros? # if not os.path.isfile(value): raise FileConstraintError("Non-existing file : %s"%value) return class IntCheckConstraintError(Exception):####################################################### pass class IntCheckConstraint(Constraint):########################################################### """ Ensures that the value can be converted into an Int """ def validate(self, value): try: int(value)#la fonction int() ne peut convertir que des nombres ou des string sinon error except: raise IntCheckConstraintError("The value can't be converted into an Int") return class FloatCheckConstraintError(Exception):####################################################### pass class FloatCheckConstraint(Constraint):########################################################### """ Ensures that the value can be converted into a float """ def validate(self, value): try: float(value)#la fonction float() ne peut convertir que des nombres ou des string sinon error (ex pas de int([0,0])) except: raise FloatCheckConstraintError("The value can't be converted into a float") return class ListIntCheckConstraintError(Exception):##################################################### pass class ListIntCheckConstraint(Constraint):######################################################### """ Ensures that the value is a tuple of int or can be converted into this """ def validate(self, value): try: if len(value)==0: raise IntCheckConstraint("Tuple is empty") for i in range(len(value)): int(value[i])#la fonction int() ne peut convertir que des nombres ou des string sinon error (ex pas de int([0,0])) except: raise IntCheckConstraintError("The value: '" + str(value) + "' can't be converted into an int") return class SameTypeConstraintError(Exception):######################################################## pass class SameTypeConstraint(Constraint):######################################################## """ Ensures that the list is not empty and that properties of the list have the same type. """ def __init__(self, tutoProp): if tutoProp is not None: self.tutoProp = tutoProp else: raise Exception("Property must exist")#ToDo def validate(self, value): if len(value)==0: raise SameTypeConstraintError("The list is empty") for i in value: self.tutoProp.validate(i) #raise SameTypeConstraintError("Properties have diffferent type") return value #faire pour une collection qui fait appel a une contrainte type sur une valeur