thirdparty/google_appengine/google/appengine/api/validation.py
changeset 828 f5fd65cc3bf3
parent 149 f2e327a7c5de
child 2864 2e0b0af889be
equal deleted inserted replaced
827:88c186556a80 828:f5fd65cc3bf3
   222       object.__setattr__(self, key, value)
   222       object.__setattr__(self, key, value)
   223     else:
   223     else:
   224       raise ValidationError('Class \'%s\' does not have attribute \'%s\''
   224       raise ValidationError('Class \'%s\' does not have attribute \'%s\''
   225                             % (self.__class__, key))
   225                             % (self.__class__, key))
   226 
   226 
   227   def __eq__(self, other):
       
   228     """Comparison operator."""
       
   229     if isinstance(other, type(self)):
       
   230       for attribute in self.ATTRIBUTES:
       
   231         if getattr(self, attribute) != getattr(other, attribute):
       
   232           return False
       
   233       return True
       
   234     else:
       
   235       return False
       
   236 
       
   237   def __str__(self):
   227   def __str__(self):
   238     """Formatted view of validated object and nested values."""
   228     """Formatted view of validated object and nested values."""
   239     return repr(self)
   229     return repr(self)
   240 
   230 
   241   def __repr__(self):
   231   def __repr__(self):
   676       raise ValidationError('Value \'%s\' does not match expression \'%s\''
   666       raise ValidationError('Value \'%s\' does not match expression \'%s\''
   677                             % (value, self.re.pattern))
   667                             % (value, self.re.pattern))
   678     return cast_value
   668     return cast_value
   679 
   669 
   680 
   670 
       
   671 class _RegexStrValue(object):
       
   672   """Simulates the regex object to support recomplation when necessary.
       
   673 
       
   674   Used by the RegexStr class to dynamically build and recompile regular
       
   675   expression attributes of a validated object.  This object replaces the normal
       
   676   object returned from re.compile which is immutable.
       
   677 
       
   678   When the value of this object is a string, that string is simply used as the
       
   679   regular expression when recompilation is needed.  If the state of this object
       
   680   is a list of strings, the strings are joined in to a single 'or' expression.
       
   681   """
       
   682 
       
   683   def __init__(self, attribute, value):
       
   684     """Initialize recompilable regex value.
       
   685 
       
   686     Args:
       
   687       attribute: Attribute validator associated with this regex value.
       
   688       value: Initial underlying python value for regex string.  Either a single
       
   689         regex string or a list of regex strings.
       
   690     """
       
   691     self.__attribute = attribute
       
   692     self.__value = value
       
   693     self.__regex = None
       
   694 
       
   695   def __AsString(self, value):
       
   696     """Convert a value to appropriate string.
       
   697 
       
   698     Returns:
       
   699       String version of value with all carriage returns and line feeds removed.
       
   700     """
       
   701     if issubclass(self.__attribute.expected_type, str):
       
   702       cast_value = TYPE_STR(value)
       
   703     else:
       
   704       cast_value = TYPE_UNICODE(value)
       
   705 
       
   706     cast_value = cast_value.replace('\n', '')
       
   707     cast_value = cast_value.replace('\r', '')
       
   708     return cast_value
       
   709 
       
   710   def __BuildRegex(self):
       
   711     """Build regex string from state.
       
   712 
       
   713     Returns:
       
   714       String version of regular expression.  Sequence objects are constructed
       
   715       as larger regular expression where each regex in the list is joined with
       
   716       all the others as single 'or' expression.
       
   717     """
       
   718     if isinstance(self.__value, list):
       
   719       value_list = self.__value
       
   720       sequence = True
       
   721     else:
       
   722       value_list = [self.__value]
       
   723       sequence = False
       
   724 
       
   725     regex_list = []
       
   726     for item in value_list:
       
   727       regex_list.append(self.__AsString(item))
       
   728 
       
   729     if sequence:
       
   730       return '|'.join('(?:%s)' % item for item in regex_list)
       
   731     else:
       
   732       return regex_list[0]
       
   733 
       
   734   def __Compile(self):
       
   735     """Build regular expression object from state.
       
   736 
       
   737     Returns:
       
   738       Compiled regular expression based on internal value.
       
   739     """
       
   740     regex = self.__BuildRegex()
       
   741     try:
       
   742       return re.compile(regex)
       
   743     except re.error, e:
       
   744       raise ValidationError('Value \'%s\' does not compile: %s' % (regex, e), e)
       
   745 
       
   746   @property
       
   747   def regex(self):
       
   748     """Compiled regular expression as described by underlying value."""
       
   749     return self.__Compile()
       
   750 
       
   751   def match(self, value):
       
   752     """Match against internal regular expression.
       
   753 
       
   754     Returns:
       
   755       Regular expression object built from underlying value.
       
   756     """
       
   757     return re.match(self.__BuildRegex(), value)
       
   758 
       
   759   def Validate(self):
       
   760     """Ensure that regex string compiles."""
       
   761     self.__Compile()
       
   762 
       
   763   def __str__(self):
       
   764     """Regular expression string as described by underlying value."""
       
   765     return self.__BuildRegex()
       
   766 
       
   767   def __eq__(self, other):
       
   768     """Comparison against other regular expression string values."""
       
   769     if isinstance(other, _RegexStrValue):
       
   770       return self.__BuildRegex() == other.__BuildRegex()
       
   771     return str(self) == other
       
   772 
       
   773   def __ne__(self, other):
       
   774     """Inequality operator for regular expression string value."""
       
   775     return not self.__eq__(other)
       
   776 
       
   777 
   681 class RegexStr(Validator):
   778 class RegexStr(Validator):
   682   """Validates that a string can compile as a regex without errors.
   779   """Validates that a string can compile as a regex without errors.
   683 
   780 
   684   Use this validator when the value of a field should be a regex.  That
   781   Use this validator when the value of a field should be a regex.  That
   685   means that the value must be a string that can be compiled by re.compile().
   782   means that the value must be a string that can be compiled by re.compile().
   691 
   788 
   692     Raises:
   789     Raises:
   693       AttributeDefinitionError if string_type is not a kind of string.
   790       AttributeDefinitionError if string_type is not a kind of string.
   694     """
   791     """
   695     if default is not None:
   792     if default is not None:
   696       default = re.compile(default)
   793       default = _RegexStrValue(self, default)
       
   794       re.compile(str(default))
   697     super(RegexStr, self).__init__(default)
   795     super(RegexStr, self).__init__(default)
   698     if (not issubclass(string_type, basestring) or
   796     if (not issubclass(string_type, basestring) or
   699         string_type is basestring):
   797         string_type is basestring):
   700       raise AttributeDefinitionError(
   798       raise AttributeDefinitionError(
   701           'RegexStr fields must be a string type not %s.' % str(string_type))
   799           'RegexStr fields must be a string type not %s.' % str(string_type))
   713 
   811 
   714     Raises:
   812     Raises:
   715       ValueError when value does not compile as a regular expression.  TypeError
   813       ValueError when value does not compile as a regular expression.  TypeError
   716       when value does not match provided string type.
   814       when value does not match provided string type.
   717     """
   815     """
   718     if issubclass(self.expected_type, str):
   816     if isinstance(value, _RegexStrValue):
   719       cast_value = TYPE_STR(value)
   817       return value
   720     else:
   818     value = _RegexStrValue(self, value)
   721       cast_value = TYPE_UNICODE(value)
   819     value.Validate()
   722 
   820     return value
   723     cast_value = cast_value.replace('\n', '')
       
   724     cast_value = cast_value.replace('\r', '')
       
   725     try:
       
   726       compiled = re.compile(cast_value)
       
   727     except re.error, e:
       
   728       raise ValidationError('Value \'%s\' does not compile: %s' % (value, e), e)
       
   729     return compiled
       
   730 
   821 
   731   def ToValue(self, value):
   822   def ToValue(self, value):
   732     """Returns the RE pattern for this validator."""
   823     """Returns the RE pattern for this validator."""
   733     return value.pattern
   824     return str(value)
   734 
   825 
   735 
   826 
   736 class Range(Validator):
   827 class Range(Validator):
   737   """Validates that numbers fall within the correct range.
   828   """Validates that numbers fall within the correct range.
   738 
   829