3 # Copyright 2007 Google Inc.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
21 """Validation tools for generic object structures.
23 This library is used for defining classes with constrained attributes.
24 Attributes are defined on the class which contains them using validators.
25 Although validators can be defined by any client of this library, a number
26 of standard validators are provided here.
28 Validators can be any callable that takes a single parameter which checks
29 the new value before it is assigned to the attribute. Validators are
30 permitted to modify a received value so that it is appropriate for the
31 attribute definition. For example, using int as a validator will cast
32 a correctly formatted string to a number, or raise an exception if it
33 can not. This is not recommended, however. the correct way to use a
34 validator that ensure the correct type is to use the Type validator.
36 This validation library is mainly intended for use with the YAML object
37 builder. See yaml_object.py.
55 class Error(Exception):
56 """Base class for all package errors."""
59 class AttributeDefinitionError(Error
):
60 """An error occurred in the definition of class attributes."""
63 class ValidationError(Error
):
64 """Base class for raising exceptions during validation."""
66 def __init__(self
, message
, cause
=None):
67 """Initialize exception."""
68 if hasattr(cause
, 'args') and cause
.args
:
69 Error
.__init
__(self
, message
, *cause
.args
)
73 Error
.__init
__(self
, message
)
74 self
.message
= message
78 return str(self
.message
)
81 class MissingAttribute(ValidationError
):
82 """Raised when a required attribute is missing from object."""
85 def AsValidator(validator
):
86 """Wrap various types as instances of a validator.
88 Used to allow shorthand for common validator types. It
89 converts the following types to the following Validators.
94 Validator -> Its self!
97 validator: Object to wrap in a validator.
100 Validator instance that wraps the given value.
103 AttributeDefinitionError: if validator is not one of the above described
106 if isinstance(validator
, (str, unicode)):
107 return Regex(validator
, type(validator
))
108 if isinstance(validator
, type):
109 return Type(validator
)
110 if isinstance(validator
, (list, tuple, set)):
111 return Options(*tuple(validator
))
112 if isinstance(validator
, Validator
):
115 raise AttributeDefinitionError('%s is not a valid validator' %
119 def _SimplifiedValue(validator
, value
):
120 """Convert any value to simplified collections and basic types.
123 validator: An instance of Validator that corresponds with 'value'.
124 May also be 'str' or 'int' if those were used instead of a full
126 value: Value to convert to simplified collections.
129 The value as a dictionary if it is a ValidatedBase object. A list of
130 items converted to simplified collections if value is a list
131 or a tuple. Otherwise, just the value.
133 if isinstance(value
, ValidatedBase
):
135 return value
.ToDict()
136 elif isinstance(value
, (list, tuple)):
138 return [_SimplifiedValue(validator
, item
) for item
in value
]
139 elif isinstance(validator
, Validator
):
140 return validator
.ToValue(value
)
144 class ValidatedBase(object):
145 """Base class for all validated objects."""
148 def GetValidator(self
, key
):
149 """Safely get the Validator corresponding to the given key.
151 This function should be overridden by subclasses
154 key: The attribute or item to get a validator for.
157 Validator associated with key or attribute.
160 ValidationError: if the requested key is illegal.
162 raise NotImplementedError('Subclasses of ValidatedBase must '
163 'override GetValidator.')
165 def SetMultiple(self
, attributes
):
166 """Set multiple values on Validated instance.
168 All attributes will be validated before being set.
171 attributes: A dict of attributes/items to set.
174 ValidationError: when no validated attribute exists on class.
176 for key
, value
in attributes
.iteritems():
179 def Set(self
, key
, value
):
180 """Set a single value on Validated instance.
182 This method should be overridded by sub-classes.
184 This method can only be used to assign validated attributes/items.
187 key: The name of the attributes
188 value: The value to set
191 ValidationError: when no validated attribute exists on class.
193 raise NotImplementedError('Subclasses of ValidatedBase must override Set.')
195 def CheckInitialized(self
):
196 """Checks that all required fields are initialized.
198 This function is called after all attributes have been checked to
199 verify any higher level constraints, for example ensuring all required
200 attributes are present.
202 Subclasses should override this function and raise an exception for
208 """Convert ValidatedBase object to a dictionary.
210 Recursively traverses all of its elements and converts everything to
211 simplified collections.
213 Subclasses should override this method.
216 A dictionary mapping all attributes to simple values or collections.
218 raise NotImplementedError('Subclasses of ValidatedBase must '
222 """Print validated object as simplified YAML.
225 Object as a simplified YAML string compatible with parsing using the
228 return yaml
.dump(self
.ToDict(),
229 default_flow_style
=False,
230 Dumper
=yaml
.SafeDumper
)
233 class Validated(ValidatedBase
):
234 """Base class for classes that require validation.
236 A class which intends to use validated fields should sub-class itself from
237 this class. Each class should define an 'ATTRIBUTES' class variable which
238 should be a map from attribute name to its validator. For example:
240 class Story(Validated):
241 ATTRIBUTES = {'title': Type(str),
242 'authors': Repeated(Type(str)),
243 'isbn': Optional(Type(str)),
247 Attributes that are not listed under ATTRIBUTES work like normal and are
248 not validated upon assignment.
254 def __init__(self
, **attributes
):
255 """Constructor for Validated classes.
257 This constructor can optionally assign values to the class via its
261 AttributeDefinitionError: when class instance is missing ATTRIBUTE
262 definition or when ATTRIBUTE is of the wrong type.
264 if not isinstance(self
.ATTRIBUTES
, dict):
265 raise AttributeDefinitionError(
266 'The class %s does not define an ATTRIBUTE variable.'
270 for key
in self
.ATTRIBUTES
.keys():
271 object.__setattr
__(self
, key
, self
.GetValidator(key
).default
)
273 self
.SetMultiple(attributes
)
276 def GetValidator(self
, key
):
277 """Safely get the underlying attribute definition as a Validator.
280 key: Name of attribute to get.
283 Validator associated with key or attribute value wrapped in a
286 if key
not in self
.ATTRIBUTES
:
287 raise ValidationError(
288 'Unexpected attribute \'%s\' for object of type %s.' %
289 (key
, self
.__name
__))
291 return AsValidator(self
.ATTRIBUTES
[key
])
293 def Set(self
, key
, value
):
294 """Set a single value on Validated instance.
296 This method can only be used to assign validated attributes.
299 key: The name of the attributes
300 value: The value to set
303 ValidationError when no validated attribute exists on class.
305 setattr(self
, key
, value
)
308 """Get a single value on Validated instance.
310 This method can only be used to retrieve validated attributes.
313 key: The name of the attributes
316 ValidationError when no validated attribute exists on class.
318 self
.GetValidator(key
)
319 return getattr(self
, key
)
321 def CheckInitialized(self
):
322 """Checks that all required fields are initialized.
324 Since an instance of Validated starts off in an uninitialized state, it
325 is sometimes necessary to check that it has been fully initialized.
326 The main problem this solves is how to validate that an instance has
327 all of its required fields set. By default, Validator classes do not
328 allow None, but all attributes are initialized to None when instantiated.
331 Exception relevant to the kind of validation. The type of the exception
332 is determined by the validator. Typically this will be ValueError or
335 for key
in self
.ATTRIBUTES
.iterkeys():
337 self
.GetValidator(key
)(getattr(self
, key
))
338 except MissingAttribute
, e
:
339 e
.message
= "Missing required value '%s'." % key
342 def __setattr__(self
, key
, value
):
345 Setting a value on an object of this type will only work for attributes
346 defined in ATTRIBUTES. To make other assignments possible it is necessary
347 to override this method in subclasses.
349 It is important that assignment is restricted in this way because
350 this validation is used as validation for parsing. Absent this restriction
351 it would be possible for method names to be overwritten.
354 key: Name of attribute to set.
355 value: Attributes new value.
358 ValidationError: when trying to assign to an attribute
361 value
= self
.GetValidator(key
)(value
, key
)
362 object.__setattr
__(self
, key
, value
)
365 """Formatted view of validated object and nested values."""
369 """Formatted view of validated object and nested values."""
370 values
= [(attr
, getattr(self
, attr
)) for attr
in self
.ATTRIBUTES
]
373 for attr
, value
in values
:
374 value_list
.append('\n%s%s=%s' % (dent
, attr
, value
))
376 return "<%s %s\n%s>" % (self
.__class
__.__name
__, ' '.join(value_list
), dent
)
378 def __eq__(self
, other
):
379 """Equality operator.
381 Comparison is done by comparing all attribute values to those in the other
382 instance. Objects which are not of the same type are not equal.
385 other: Other object to compare against.
388 True if validated objects are equal, else False.
390 if type(self
) != type(other
):
392 for key
in self
.ATTRIBUTES
.iterkeys():
393 if getattr(self
, key
) != getattr(other
, key
):
397 def __ne__(self
, other
):
398 """Inequality operator."""
399 return not self
.__eq
__(other
)
402 """Hash function for using Validated objects in sets and maps.
404 Hash is done by hashing all keys and values and xor'ing them together.
407 Hash of validated object.
410 for key
in self
.ATTRIBUTES
.iterkeys():
411 value
= getattr(self
, key
)
412 if isinstance(value
, list):
414 result
= result ^
hash(key
) ^
hash(value
)
418 """Convert Validated object to a dictionary.
420 Recursively traverses all of its elements and converts everything to
421 simplified collections.
424 A dict of all attributes defined in this classes ATTRIBUTES mapped
425 to its value. This structure is recursive in that Validated objects
426 that are referenced by this object and in lists are also converted to
430 for name
, validator
in self
.ATTRIBUTES
.iteritems():
431 value
= getattr(self
, name
)
433 if not(isinstance(validator
, Validator
) and value
== validator
.default
):
434 result
[name
] = _SimplifiedValue(validator
, value
)
438 class ValidatedDict(ValidatedBase
, dict):
439 """Base class for validated dictionaries.
441 You can control the keys and values that are allowed in the dictionary
442 by setting KEY_VALIDATOR and VALUE_VALIDATOR to subclasses of Validator (or
443 things that can be interpreted as validators, see AsValidator).
445 For example if you wanted only capitalized keys that map to integers
448 class CapitalizedIntegerDict(ValidatedDict):
449 KEY_VALIDATOR = Regex('[A-Z].*')
450 VALUE_VALIDATOR = int # this gets interpreted to Type(int)
452 The following code would result in an error:
454 my_dict = CapitalizedIntegerDict()
455 my_dict['lowercase'] = 5 # Throws a validation exception
457 You can freely nest Validated and ValidatedDict inside each other so:
459 class MasterObject(Validated):
460 ATTRIBUTES = {'paramdict': CapitalizedIntegerDict}
462 Could be used to parse the following yaml:
465 AnotherArbitraryKey: 9931
468 VALUE_VALIDATOR
= None
470 def __init__(self
, **kwds
):
471 """Construct a validated dict by interpreting the key and value validators.
474 **kwds: keyword arguments will be validated and put into the dict.
479 def GetValidator(self
, key
):
480 """Check the key for validity and return a corresponding value validator.
483 key: The key that will correspond to the validator we are returning.
485 key
= AsValidator(self
.KEY_VALIDATOR
)(key
, 'key in %s' % self
.__name
__)
486 return AsValidator(self
.VALUE_VALIDATOR
)
488 def __setitem__(self
, key
, value
):
491 Only attributes accepted by GetValidator and values that validate
492 with the validator returned from GetValidator are allowed to be set
496 key: Name of item to set.
497 value: Items new value.
500 ValidationError: when trying to assign to a value that does not exist.
502 dict.__setitem
__(self
, key
, self
.GetValidator(key
)(value
, key
))
504 def setdefault(self
, key
, value
=None):
505 """Trap setdefaultss to ensure all key/value pairs are valid.
507 See the documentation for setdefault on dict for usage details.
510 ValidationError: if the specified key is illegal or the
513 return dict.setdefault(self
, key
, self
.GetValidator(key
)(value
, key
))
515 def update(self
, other
, **kwds
):
516 """Trap updates to ensure all key/value pairs are valid.
518 See the documentation for update on dict for usage details.
521 ValidationError: if any of the specified keys are illegal or
524 if hasattr(other
, 'keys') and callable(getattr(other
, 'keys')):
527 newother
[k
] = self
.GetValidator(k
)(other
[k
], k
)
529 newother
= [(k
, self
.GetValidator(k
)(v
, k
)) for (k
, v
) in other
]
533 newkwds
[k
] = self
.GetValidator(k
)(kwds
[k
], k
)
535 dict.update(self
, newother
, **newkwds
)
537 def Set(self
, key
, value
):
538 """Set a single value on Validated instance.
540 This method checks that a given key and value are valid and if so
541 puts the item into this dictionary.
544 key: The name of the attributes
545 value: The value to set
548 ValidationError: when no validated attribute exists on class.
553 """Convert ValidatedBase object to a dictionary.
555 Recursively traverses all of its elements and converts everything to
556 simplified collections.
558 Subclasses should override this method.
561 A dictionary mapping all attributes to simple values or collections.
564 for name
, value
in self
.iteritems():
565 validator
= self
.GetValidator(name
)
566 result
[name
] = _SimplifiedValue(validator
, value
)
573 class Validator(object):
574 """Validator base class.
576 Though any callable can be used as a validator, this class encapsulates the
577 case when a specific validator needs to hold a particular state or
580 To implement Validator sub-class, override the validate method.
582 This class is permitted to change the ultimate value that is set to the
583 attribute if there is a reasonable way to perform the conversion.
586 expected_type
= object
588 def __init__(self
, default
=None):
592 default: Default assignment is made during initialization and will
593 not pass through validation.
595 self
.default
= default
597 def __call__(self
, value
, key
='???'):
598 """Main interface to validator is call mechanism."""
599 return self
.Validate(value
, key
)
601 def Validate(self
, value
, key
='???'):
602 """Override this method to customize sub-class behavior.
605 value: Value to validate.
606 key: Name of the field being validated.
609 Value if value is valid, or a valid representation of value.
613 def ToValue(self
, value
):
614 """Convert 'value' to a simplified collection or basic type.
616 Subclasses of Validator should override this method when the dumped
617 representation of 'value' is not simply <type>(value) (e.g. a regex).
620 value: An object of the same type that was returned from Validate().
623 An instance of a builtin type (e.g. int, str, dict, etc). By default
624 it returns 'value' unmodified.
629 class Type(Validator
):
630 """Verifies property is of expected type.
632 Can optionally convert value if it is not of the expected type.
634 It is possible to specify a required field of a specific type in shorthand
635 by merely providing the type. This method is slightly less efficient than
636 providing an explicit type but is not significant unless parsing a large
637 amount of information:
639 class Person(Validated):
640 ATTRIBUTES = {'name': unicode,
644 However, in most instances it is best to use the type constants:
646 class Person(Validated):
647 ATTRIBUTES = {'name': TypeUnicode,
652 def __init__(self
, expected_type
, convert
=True, default
=None):
653 """Initialize Type validator.
656 expected_type: Type that attribute should validate against.
657 convert: Cause conversion if value is not the right type.
658 Conversion is done by calling the constructor of the type
659 with the value as its first parameter.
660 default: Default assignment is made during initialization and will
661 not pass through validation.
663 super(Type
, self
).__init
__(default
)
664 self
.expected_type
= expected_type
665 self
.convert
= convert
667 def Validate(self
, value
, key
):
668 """Validate that value has the correct type.
671 value: Value to validate.
672 key: Name of the field being validated.
675 value if value is of the correct type. value is coverted to the correct
676 type if the Validator is configured to do so.
679 MissingAttribute: if value is None and the expected type is not NoneType.
680 ValidationError: if value is not of the right type and the validator
681 is either configured not to convert or cannot convert.
683 if not isinstance(value
, self
.expected_type
):
685 raise MissingAttribute('Missing value is required.')
689 return self
.expected_type(value
)
690 except ValueError, e
:
691 raise ValidationError(
692 'Value %r for %s could not be converted to type %s.' % (
693 value
, key
, self
.expected_type
.__name
__), e
)
695 raise ValidationError(
696 'Value %r for %s is not of the expected type %s' % (
697 value
, key
, self
.expected_type
.__name
__), e
)
699 raise ValidationError(
700 'Value %r for %s is not of the expected type %s' % (
701 value
, key
, self
.expected_type
.__name
__))
706 TYPE_BOOL
= Type(bool)
708 TYPE_LONG
= Type(long)
710 TYPE_UNICODE
= Type(unicode)
711 TYPE_FLOAT
= Type(float)
714 class Options(Validator
):
715 """Limit field based on pre-determined values.
717 Options are used to make sure an enumerated set of values are the only
718 one permitted for assignment. It is possible to define aliases which
719 map multiple string values to a single original. An example of usage:
721 class ZooAnimal(validated.Class):
724 'kind': Options('platypus', # No aliases
725 ('rhinoceros', ['rhino']), # One alias
726 ('canine', ('dog', 'puppy')), # Two aliases
730 def __init__(self
, *options
, **kw
):
731 """Initialize options.
734 options: List of allowed values.
737 default
= kw
['default']
742 def AddAlias(alias
, original
):
743 """Set new alias on alias_map.
746 AttributeDefinitionError: when option already exists or if alias is
749 if not isinstance(alias
, str):
750 raise AttributeDefinitionError(
751 'All option values must be of type str.')
752 elif alias
in alias_map
:
753 raise AttributeDefinitionError(
754 "Option '%s' already defined for options property." % alias
)
755 alias_map
[alias
] = original
758 for option
in options
:
759 if isinstance(option
, str):
760 AddAlias(option
, option
)
762 elif isinstance(option
, (list, tuple)):
765 raise AttributeDefinitionError("Alias is defined as a list of tuple "
766 "with two items. The first is the "
767 "original option, while the second "
768 "is a list or tuple of str aliases.\n"
770 " ('original', ('alias1', "
772 original
, aliases
= option
773 AddAlias(original
, original
)
774 if not isinstance(aliases
, (list, tuple)):
775 raise AttributeDefinitionError('Alias lists must be a list or tuple')
777 for alias
in aliases
:
778 AddAlias(alias
, original
)
781 raise AttributeDefinitionError("All options must be of type str "
782 "or of the form (str, [str...]).")
783 super(Options
, self
).__init
__(default
)
784 self
.options
= alias_map
786 def Validate(self
, value
, key
):
790 Original value for provided alias.
793 ValidationError: when value is not one of predefined values.
796 raise ValidationError('Value for options field must not be None.')
798 if value
not in self
.options
:
799 raise ValidationError('Value \'%s\' for %s not in %s.'
800 % (value
, key
, self
.options
))
801 return self
.options
[value
]
804 class Optional(Validator
):
805 """Definition of optional attributes.
807 Optional values are attributes which can be set to None or left
808 unset. All values in a basic Validated class are set to None
809 at initialization. Failure to assign to non-optional values
810 will result in a validation error when calling CheckInitialized.
813 def __init__(self
, validator
, default
=None):
816 This constructor will make a few guesses about the value passed in
819 - If the validator argument is a type, it automatically creates a Type
822 - If the validator argument is a list or tuple, it automatically
823 creates an Options validator around it.
826 validator: Optional validation condition.
829 AttributeDefinitionError: if validator is not callable.
831 self
.validator
= AsValidator(validator
)
832 self
.expected_type
= self
.validator
.expected_type
833 self
.default
= default
835 def Validate(self
, value
, key
):
836 """Optionally require a value.
838 Normal validators do not accept None. This will accept none on
839 behalf of the contained validator.
842 value: Value to be validated as optional.
843 key: Name of the field being validated.
846 None if value is None, else results of contained validation.
850 return self
.validator(value
, key
)
852 def ToValue(self
, value
):
853 """Convert 'value' to a simplified collection or basic type."""
856 return self
.validator
.ToValue(value
)
859 class Regex(Validator
):
860 """Regular expression validator.
862 Regular expression validator always converts value to string. Note that
863 matches must be exact. Partial matches will not validate. For example:
865 class ClassDescr(Validated):
866 ATTRIBUTES = { 'name': Regex(r'[a-zA-Z_][a-zA-Z_0-9]*'),
867 'parent': Type(type),
870 Alternatively, any attribute that is defined as a string is automatically
871 interpreted to be of type Regex. It is possible to specify unicode regex
872 strings as well. This approach is slightly less efficient, but usually
873 is not significant unless parsing large amounts of data:
875 class ClassDescr(Validated):
876 ATTRIBUTES = { 'name': r'[a-zA-Z_][a-zA-Z_0-9]*',
877 'parent': Type(type),
880 # This will raise a ValidationError exception.
881 my_class(name='AName with space', parent=AnotherClass)
884 def __init__(self
, regex
, string_type
=unicode, default
=None):
885 """Initialized regex validator.
888 regex: Regular expression string to use for comparison.
891 AttributeDefinitionError: if string_type is not a kind of string.
893 super(Regex
, self
).__init
__(default
)
894 if (not issubclass(string_type
, basestring
) or
895 string_type
is basestring
):
896 raise AttributeDefinitionError(
897 'Regex fields must be a string type not %s.' % str(string_type
))
898 if isinstance(regex
, basestring
):
899 self
.re
= re
.compile('^(?:%s)$' % regex
)
901 raise AttributeDefinitionError(
902 'Regular expression must be string. Found %s.' % str(regex
))
904 self
.expected_type
= string_type
906 def Validate(self
, value
, key
):
907 """Does validation of a string against a regular expression.
910 value: String to match against regular expression.
911 key: Name of the field being validated.
914 ValidationError: when value does not match regular expression or
915 when value does not match provided string type.
917 if issubclass(self
.expected_type
, str):
918 cast_value
= TYPE_STR(value
)
920 cast_value
= TYPE_UNICODE(value
)
922 if self
.re
.match(cast_value
) is None:
923 raise ValidationError('Value \'%s\' for %s does not match expression '
924 '\'%s\'' % (value
, key
, self
.re
.pattern
))
928 class _RegexStrValue(object):
929 """Simulates the regex object to support recompilation when necessary.
931 Used by the RegexStr class to dynamically build and recompile regular
932 expression attributes of a validated object. This object replaces the normal
933 object returned from re.compile which is immutable.
935 When the value of this object is a string, that string is simply used as the
936 regular expression when recompilation is needed. If the state of this object
937 is a list of strings, the strings are joined in to a single 'or' expression.
940 def __init__(self
, attribute
, value
, key
):
941 """Initialize recompilable regex value.
944 attribute: Attribute validator associated with this regex value.
945 value: Initial underlying python value for regex string. Either a single
946 regex string or a list of regex strings.
947 key: Name of the field.
949 self
.__attribute
= attribute
954 def __AsString(self
, value
):
955 """Convert a value to appropriate string.
958 String version of value with all carriage returns and line feeds removed.
960 if issubclass(self
.__attribute
.expected_type
, str):
961 cast_value
= TYPE_STR(value
)
963 cast_value
= TYPE_UNICODE(value
)
965 cast_value
= cast_value
.replace('\n', '')
966 cast_value
= cast_value
.replace('\r', '')
969 def __BuildRegex(self
):
970 """Build regex string from state.
973 String version of regular expression. Sequence objects are constructed
974 as larger regular expression where each regex in the list is joined with
975 all the others as single 'or' expression.
977 if isinstance(self
.__value
, list):
978 value_list
= self
.__value
981 value_list
= [self
.__value
]
985 for item
in value_list
:
986 regex_list
.append(self
.__AsString
(item
))
989 return '|'.join('%s' % item
for item
in regex_list
)
994 """Build regular expression object from state.
997 Compiled regular expression based on internal value.
999 regex
= self
.__BuildRegex
()
1001 return re
.compile(regex
)
1003 raise ValidationError('Value \'%s\' for %s does not compile: %s' %
1004 (regex
, self
.__key
, e
), e
)
1008 """Compiled regular expression as described by underlying value."""
1009 return self
.__Compile
()
1011 def match(self
, value
):
1012 """Match against internal regular expression.
1015 Regular expression object built from underlying value.
1017 return re
.match(self
.__BuildRegex
(), value
)
1020 """Ensure that regex string compiles."""
1024 """Regular expression string as described by underlying value."""
1025 return self
.__BuildRegex
()
1027 def __eq__(self
, other
):
1028 """Comparison against other regular expression string values."""
1029 if isinstance(other
, _RegexStrValue
):
1030 return self
.__BuildRegex
() == other
.__BuildRegex
()
1031 return str(self
) == other
1033 def __ne__(self
, other
):
1034 """Inequality operator for regular expression string value."""
1035 return not self
.__eq
__(other
)
1038 class RegexStr(Validator
):
1039 """Validates that a string can compile as a regex without errors.
1041 Use this validator when the value of a field should be a regex. That
1042 means that the value must be a string that can be compiled by re.compile().
1043 The attribute will then be a compiled re object.
1046 def __init__(self
, string_type
=unicode, default
=None):
1047 """Initialized regex validator.
1050 AttributeDefinitionError: if string_type is not a kind of string.
1052 if default
is not None:
1053 default
= _RegexStrValue(self
, default
, None)
1054 re
.compile(str(default
))
1055 super(RegexStr
, self
).__init
__(default
)
1056 if (not issubclass(string_type
, basestring
) or
1057 string_type
is basestring
):
1058 raise AttributeDefinitionError(
1059 'RegexStr fields must be a string type not %s.' % str(string_type
))
1061 self
.expected_type
= string_type
1063 def Validate(self
, value
, key
):
1064 """Validates that the string compiles as a regular expression.
1066 Because the regular expression might have been expressed as a multiline
1067 string, this function also strips newlines out of value.
1070 value: String to compile as a regular expression.
1071 key: Name of the field being validated.
1074 ValueError when value does not compile as a regular expression. TypeError
1075 when value does not match provided string type.
1077 if isinstance(value
, _RegexStrValue
):
1079 value
= _RegexStrValue(self
, value
, key
)
1083 def ToValue(self
, value
):
1084 """Returns the RE pattern for this validator."""
1088 class Range(Validator
):
1089 """Validates that numbers fall within the correct range.
1091 In theory this class can be emulated using Options, however error
1092 messages generated from that class will not be very intelligible.
1093 This class essentially does the same thing, but knows the intended
1096 Also, this range class supports floats and other types that implement
1099 The range is inclusive, meaning 3 is considered in the range
1103 def __init__(self
, minimum
, maximum
, range_type
=int, default
=None):
1104 """Initializer for range.
1106 At least one of minimum and maximum must be supplied.
1109 minimum: Minimum for attribute.
1110 maximum: Maximum for attribute.
1111 range_type: Type of field. Defaults to int.
1114 AttributeDefinitionError: if the specified parameters are incorrect.
1116 super(Range
, self
).__init
__(default
)
1117 if minimum
is None and maximum
is None:
1118 raise AttributeDefinitionError('Must specify minimum or maximum.')
1119 if minimum
is not None and not isinstance(minimum
, range_type
):
1120 raise AttributeDefinitionError(
1121 'Minimum value must be of type %s, instead it is %s (%s).' %
1122 (str(range_type
), str(type(minimum
)), str(minimum
)))
1123 if maximum
is not None and not isinstance(maximum
, range_type
):
1124 raise AttributeDefinitionError(
1125 'Maximum value must be of type %s, instead it is %s (%s).' %
1126 (str(range_type
), str(type(maximum
)), str(maximum
)))
1128 self
.minimum
= minimum
1129 self
.maximum
= maximum
1130 self
.expected_type
= range_type
1131 self
._type
_validator
= Type(range_type
)
1133 def Validate(self
, value
, key
):
1134 """Validate that value is within range.
1136 Validates against range-type then checks the range.
1139 value: Value to validate.
1140 key: Name of the field being validated.
1143 ValidationError: when value is out of range. ValidationError when value
1144 is not of the same range type.
1146 cast_value
= self
._type
_validator
.Validate(value
, key
)
1147 if self
.maximum
is None and cast_value
< self
.minimum
:
1148 raise ValidationError('Value \'%s\' for %s less than %s'
1149 % (value
, key
, self
.minimum
))
1150 elif self
.minimum
is None and cast_value
> self
.maximum
:
1151 raise ValidationError('Value \'%s\' for %s greater than %s'
1152 % (value
, key
, self
.maximum
))
1154 elif ((self
.minimum
is not None and cast_value
< self
.minimum
) or
1155 (self
.maximum
is not None and cast_value
> self
.maximum
)):
1156 raise ValidationError('Value \'%s\' for %s is out of range %s - %s'
1157 % (value
, key
, self
.minimum
, self
.maximum
))
1161 class Repeated(Validator
):
1162 """Repeated field validator.
1164 Indicates that attribute is expected to be a repeated value, ie,
1165 a sequence. This adds additional validation over just Type(list)
1166 in that it retains information about what can be stored in the list by
1167 use of its constructor field.
1170 def __init__(self
, constructor
, default
=None):
1171 """Initializer for repeated field.
1174 constructor: Type used for verifying elements of sequence attribute.
1176 super(Repeated
, self
).__init
__(default
)
1177 self
.constructor
= constructor
1178 self
.expected_type
= list
1180 def Validate(self
, value
, key
):
1181 """Do validation of sequence.
1183 Value must be a list and all elements must be of type 'constructor'.
1186 value: Value to validate.
1187 key: Name of the field being validated.
1190 ValidationError: if value is None, not a list or one of its elements is
1193 if not isinstance(value
, list):
1194 raise ValidationError('Value \'%s\' for %s should be a sequence but '
1195 'is not.' % (value
, key
))
1198 if isinstance(self
.constructor
, Validator
):
1199 item
= self
.constructor
.Validate(item
, key
)
1200 elif not isinstance(item
, self
.constructor
):
1201 raise ValidationError('Value element \'%s\' for %s must be type %s.' % (
1202 str(item
), key
, self
.constructor
.__name
__))
1207 class TimeValue(Validator
):
1208 """Validates time values with units, such as 1h or 3.5d."""
1210 _EXPECTED_SYNTAX
= ('must be a non-negative number followed by a time unit, '
1211 'such as 1h or 3.5d')
1214 super(TimeValue
, self
).__init
__()
1215 self
.expected_type
= str
1217 def Validate(self
, value
, key
):
1218 """Validate a time value.
1221 value: Value to validate.
1222 key: Name of the field being validated.
1225 ValidationError: if value is not a time value with the expected format.
1227 if not isinstance(value
, basestring
):
1228 raise ValidationError("Value '%s' for %s is not a string (%s)"
1229 % (value
, key
, TimeValue
._EXPECTED
_SYNTAX
))
1231 raise ValidationError("Value for %s is empty (%s)"
1232 % (key
, TimeValue
._EXPECTED
_SYNTAX
))
1233 if value
[-1] not in "smhd":
1234 raise ValidationError("Value '%s' for %s must end with a time unit, "
1235 "one of s (seconds), m (minutes), h (hours), "
1236 "or d (days)" % (value
, key
))
1238 t
= float(value
[:-1])
1240 raise ValidationError("Value '%s' for %s is not a valid time value (%s)"
1241 % (value
, key
, TimeValue
._EXPECTED
_SYNTAX
))
1243 raise ValidationError("Value '%s' for %s is negative (%s)"
1244 % (value
, key
, TimeValue
._EXPECTED
_SYNTAX
))