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.
54 class Error(Exception):
55 """Base class for all package errors."""
58 class AttributeDefinitionError(Error
):
59 """An error occurred in the definition of class attributes."""
62 class ValidationError(Error
):
63 """Base class for raising exceptions during validation."""
65 def __init__(self
, message
, cause
=None):
66 """Initialize exception."""
67 if hasattr(cause
, 'args') and cause
.args
:
68 Error
.__init
__(self
, message
, *cause
.args
)
72 Error
.__init
__(self
, message
)
73 self
.message
= message
77 return str(self
.message
)
80 class MissingAttribute(ValidationError
):
81 """Raised when a required attribute is missing from object."""
84 def AsValidator(validator
):
85 """Wrap various types as instances of a validator.
87 Used to allow shorthand for common validator types. It
88 converts the following types to the following Validators.
93 Validator -> Its self!
96 validator: Object to wrap in a validator.
99 Validator instance that wraps the given value.
102 AttributeDefinitionError: if validator is not one of the above described
105 if isinstance(validator
, (str, unicode)):
106 return Regex(validator
, type(validator
))
107 if isinstance(validator
, type):
108 return Type(validator
)
109 if isinstance(validator
, (list, tuple, set)):
110 return Options(*tuple(validator
))
111 if isinstance(validator
, Validator
):
114 raise AttributeDefinitionError('%s is not a valid validator' %
118 def _SimplifiedValue(validator
, value
):
119 """Convert any value to simplified collections and basic types.
122 validator: An instance of Validator that corresponds with 'value'.
123 May also be 'str' or 'int' if those were used instead of a full
125 value: Value to convert to simplified collections.
128 The value as a dictionary if it is a ValidatedBase object. A list of
129 items converted to simplified collections if value is a list
130 or a tuple. Otherwise, just the value.
132 if isinstance(value
, ValidatedBase
):
134 return value
.ToDict()
135 elif isinstance(value
, (list, tuple)):
137 return [_SimplifiedValue(validator
, item
) for item
in value
]
138 elif isinstance(validator
, Validator
):
139 return validator
.ToValue(value
)
143 class ValidatedBase(object):
144 """Base class for all validated objects."""
147 def GetValidator(self
, key
):
148 """Safely get the Validator corresponding to the given key.
150 This function should be overridden by subclasses
153 key: The attribute or item to get a validator for.
156 Validator associated with key or attribute.
159 ValidationError: if the requested key is illegal.
161 raise NotImplementedError('Subclasses of ValidatedBase must '
162 'override GetValidator.')
164 def SetMultiple(self
, attributes
):
165 """Set multiple values on Validated instance.
167 All attributes will be validated before being set.
170 attributes: A dict of attributes/items to set.
173 ValidationError: when no validated attribute exists on class.
175 for key
, value
in attributes
.iteritems():
178 def Set(self
, key
, value
):
179 """Set a single value on Validated instance.
181 This method should be overridded by sub-classes.
183 This method can only be used to assign validated attributes/items.
186 key: The name of the attributes
187 value: The value to set
190 ValidationError: when no validated attribute exists on class.
192 raise NotImplementedError('Subclasses of ValidatedBase must override Set.')
194 def CheckInitialized(self
):
195 """Checks that all required fields are initialized.
197 This function is called after all attributes have been checked to
198 verify any higher level constraints, for example ensuring all required
199 attributes are present.
201 Subclasses should override this function and raise an exception for
207 """Convert ValidatedBase object to a dictionary.
209 Recursively traverses all of its elements and converts everything to
210 simplified collections.
212 Subclasses should override this method.
215 A dictionary mapping all attributes to simple values or collections.
217 raise NotImplementedError('Subclasses of ValidatedBase must '
221 """Print validated object as simplified YAML.
224 Object as a simplified YAML string compatible with parsing using the
227 return yaml
.dump(self
.ToDict(),
228 default_flow_style
=False,
229 Dumper
=yaml
.SafeDumper
)
232 class Validated(ValidatedBase
):
233 """Base class for classes that require validation.
235 A class which intends to use validated fields should sub-class itself from
236 this class. Each class should define an 'ATTRIBUTES' class variable which
237 should be a map from attribute name to its validator. For example:
239 class Story(Validated):
240 ATTRIBUTES = {'title': Type(str),
241 'authors': Repeated(Type(str)),
242 'isbn': Optional(Type(str)),
246 Attributes that are not listed under ATTRIBUTES work like normal and are
247 not validated upon assignment.
253 def __init__(self
, **attributes
):
254 """Constructor for Validated classes.
256 This constructor can optionally assign values to the class via its
260 AttributeDefinitionError: when class instance is missing ATTRIBUTE
261 definition or when ATTRIBUTE is of the wrong type.
263 if not isinstance(self
.ATTRIBUTES
, dict):
264 raise AttributeDefinitionError(
265 'The class %s does not define an ATTRIBUTE variable.'
269 for key
in self
.ATTRIBUTES
.keys():
270 object.__setattr
__(self
, key
, self
.GetValidator(key
).default
)
272 self
.SetMultiple(attributes
)
275 def GetValidator(self
, key
):
276 """Safely get the underlying attribute definition as a Validator.
279 key: Name of attribute to get.
282 Validator associated with key or attribute value wrapped in a
285 if key
not in self
.ATTRIBUTES
:
286 raise ValidationError(
287 'Unexpected attribute \'%s\' for object of type %s.' %
288 (key
, self
.__name
__))
290 return AsValidator(self
.ATTRIBUTES
[key
])
292 def Set(self
, key
, value
):
293 """Set a single value on Validated instance.
295 This method can only be used to assign validated attributes.
298 key: The name of the attributes
299 value: The value to set
302 ValidationError when no validated attribute exists on class.
304 setattr(self
, key
, value
)
307 """Get a single value on Validated instance.
309 This method can only be used to retrieve validated attributes.
312 key: The name of the attributes
315 ValidationError when no validated attribute exists on class.
317 self
.GetValidator(key
)
318 return getattr(self
, key
)
320 def CheckInitialized(self
):
321 """Checks that all required fields are initialized.
323 Since an instance of Validated starts off in an uninitialized state, it
324 is sometimes necessary to check that it has been fully initialized.
325 The main problem this solves is how to validate that an instance has
326 all of its required fields set. By default, Validator classes do not
327 allow None, but all attributes are initialized to None when instantiated.
330 Exception relevant to the kind of validation. The type of the exception
331 is determined by the validator. Typically this will be ValueError or
334 for key
in self
.ATTRIBUTES
.iterkeys():
336 self
.GetValidator(key
)(getattr(self
, key
))
337 except MissingAttribute
, e
:
338 e
.message
= "Missing required value '%s'." % key
341 def __setattr__(self
, key
, value
):
344 Setting a value on an object of this type will only work for attributes
345 defined in ATTRIBUTES. To make other assignments possible it is necessary
346 to override this method in subclasses.
348 It is important that assignment is restricted in this way because
349 this validation is used as validation for parsing. Absent this restriction
350 it would be possible for method names to be overwritten.
353 key: Name of attribute to set.
354 value: Attributes new value.
357 ValidationError: when trying to assign to an attribute
360 value
= self
.GetValidator(key
)(value
, key
)
361 object.__setattr
__(self
, key
, value
)
364 """Formatted view of validated object and nested values."""
368 """Formatted view of validated object and nested values."""
369 values
= [(attr
, getattr(self
, attr
)) for attr
in self
.ATTRIBUTES
]
372 for attr
, value
in values
:
373 value_list
.append('\n%s%s=%s' % (dent
, attr
, value
))
375 return "<%s %s\n%s>" % (self
.__class
__.__name
__, ' '.join(value_list
), dent
)
377 def __eq__(self
, other
):
378 """Equality operator.
380 Comparison is done by comparing all attribute values to those in the other
381 instance. Objects which are not of the same type are not equal.
384 other: Other object to compare against.
387 True if validated objects are equal, else False.
389 if type(self
) != type(other
):
391 for key
in self
.ATTRIBUTES
.iterkeys():
392 if getattr(self
, key
) != getattr(other
, key
):
396 def __ne__(self
, other
):
397 """Inequality operator."""
398 return not self
.__eq
__(other
)
401 """Hash function for using Validated objects in sets and maps.
403 Hash is done by hashing all keys and values and xor'ing them together.
406 Hash of validated object.
409 for key
in self
.ATTRIBUTES
.iterkeys():
410 value
= getattr(self
, key
)
411 if isinstance(value
, list):
413 result
= result ^
hash(key
) ^
hash(value
)
417 """Convert Validated object to a dictionary.
419 Recursively traverses all of its elements and converts everything to
420 simplified collections.
423 A dict of all attributes defined in this classes ATTRIBUTES mapped
424 to its value. This structure is recursive in that Validated objects
425 that are referenced by this object and in lists are also converted to
429 for name
, validator
in self
.ATTRIBUTES
.iteritems():
430 value
= getattr(self
, name
)
432 if not(isinstance(validator
, Validator
) and value
== validator
.default
):
433 result
[name
] = _SimplifiedValue(validator
, value
)
437 class ValidatedDict(ValidatedBase
, dict):
438 """Base class for validated dictionaries.
440 You can control the keys and values that are allowed in the dictionary
441 by setting KEY_VALIDATOR and VALUE_VALIDATOR to subclasses of Validator (or
442 things that can be interpreted as validators, see AsValidator).
444 For example if you wanted only capitalized keys that map to integers
447 class CapitalizedIntegerDict(ValidatedDict):
448 KEY_VALIDATOR = Regex('[A-Z].*')
449 VALUE_VALIDATOR = int # this gets interpreted to Type(int)
451 The following code would result in an error:
453 my_dict = CapitalizedIntegerDict()
454 my_dict['lowercase'] = 5 # Throws a validation exception
456 You can freely nest Validated and ValidatedDict inside each other so:
458 class MasterObject(Validated):
459 ATTRIBUTES = {'paramdict': CapitalizedIntegerDict}
461 Could be used to parse the following yaml:
464 AnotherArbitraryKey: 9931
467 VALUE_VALIDATOR
= None
469 def __init__(self
, **kwds
):
470 """Construct a validated dict by interpreting the key and value validators.
473 **kwds: keyword arguments will be validated and put into the dict.
478 def GetValidator(self
, key
):
479 """Check the key for validity and return a corresponding value validator.
482 key: The key that will correspond to the validator we are returning.
484 key
= AsValidator(self
.KEY_VALIDATOR
)(key
, 'key in %s' % self
.__name
__)
485 return AsValidator(self
.VALUE_VALIDATOR
)
487 def __setitem__(self
, key
, value
):
490 Only attributes accepted by GetValidator and values that validate
491 with the validator returned from GetValidator are allowed to be set
495 key: Name of item to set.
496 value: Items new value.
499 ValidationError: when trying to assign to a value that does not exist.
501 dict.__setitem
__(self
, key
, self
.GetValidator(key
)(value
, key
))
503 def setdefault(self
, key
, value
=None):
504 """Trap setdefaultss to ensure all key/value pairs are valid.
506 See the documentation for setdefault on dict for usage details.
509 ValidationError: if the specified key is illegal or the
512 return dict.setdefault(self
, key
, self
.GetValidator(key
)(value
, key
))
514 def update(self
, other
, **kwds
):
515 """Trap updates to ensure all key/value pairs are valid.
517 See the documentation for update on dict for usage details.
520 ValidationError: if any of the specified keys are illegal or
523 if hasattr(other
, 'keys') and callable(getattr(other
, 'keys')):
526 newother
[k
] = self
.GetValidator(k
)(other
[k
], k
)
528 newother
= [(k
, self
.GetValidator(k
)(v
, k
)) for (k
, v
) in other
]
532 newkwds
[k
] = self
.GetValidator(k
)(kwds
[k
], k
)
534 dict.update(self
, newother
, **newkwds
)
536 def Set(self
, key
, value
):
537 """Set a single value on Validated instance.
539 This method checks that a given key and value are valid and if so
540 puts the item into this dictionary.
543 key: The name of the attributes
544 value: The value to set
547 ValidationError: when no validated attribute exists on class.
552 """Convert ValidatedBase object to a dictionary.
554 Recursively traverses all of its elements and converts everything to
555 simplified collections.
557 Subclasses should override this method.
560 A dictionary mapping all attributes to simple values or collections.
563 for name
, value
in self
.iteritems():
564 validator
= self
.GetValidator(name
)
565 result
[name
] = _SimplifiedValue(validator
, value
)
572 class Validator(object):
573 """Validator base class.
575 Though any callable can be used as a validator, this class encapsulates the
576 case when a specific validator needs to hold a particular state or
579 To implement Validator sub-class, override the validate method.
581 This class is permitted to change the ultimate value that is set to the
582 attribute if there is a reasonable way to perform the conversion.
585 expected_type
= object
587 def __init__(self
, default
=None):
591 default: Default assignment is made during initialization and will
592 not pass through validation.
594 self
.default
= default
596 def __call__(self
, value
, key
='???'):
597 """Main interface to validator is call mechanism."""
598 return self
.Validate(value
, key
)
600 def Validate(self
, value
, key
='???'):
601 """Override this method to customize sub-class behavior.
604 value: Value to validate.
605 key: Name of the field being validated.
608 Value if value is valid, or a valid representation of value.
612 def ToValue(self
, value
):
613 """Convert 'value' to a simplified collection or basic type.
615 Subclasses of Validator should override this method when the dumped
616 representation of 'value' is not simply <type>(value) (e.g. a regex).
619 value: An object of the same type that was returned from Validate().
622 An instance of a builtin type (e.g. int, str, dict, etc). By default
623 it returns 'value' unmodified.
628 class Type(Validator
):
629 """Verifies property is of expected type.
631 Can optionally convert value if it is not of the expected type.
633 It is possible to specify a required field of a specific type in shorthand
634 by merely providing the type. This method is slightly less efficient than
635 providing an explicit type but is not significant unless parsing a large
636 amount of information:
638 class Person(Validated):
639 ATTRIBUTES = {'name': unicode,
643 However, in most instances it is best to use the type constants:
645 class Person(Validated):
646 ATTRIBUTES = {'name': TypeUnicode,
651 def __init__(self
, expected_type
, convert
=True, default
=None):
652 """Initialize Type validator.
655 expected_type: Type that attribute should validate against.
656 convert: Cause conversion if value is not the right type.
657 Conversion is done by calling the constructor of the type
658 with the value as its first parameter.
659 default: Default assignment is made during initialization and will
660 not pass through validation.
662 super(Type
, self
).__init
__(default
)
663 self
.expected_type
= expected_type
664 self
.convert
= convert
666 def Validate(self
, value
, key
):
667 """Validate that value has the correct type.
670 value: Value to validate.
671 key: Name of the field being validated.
674 value if value is of the correct type. value is coverted to the correct
675 type if the Validator is configured to do so.
678 MissingAttribute: if value is None and the expected type is not NoneType.
679 ValidationError: if value is not of the right type and the validator
680 is either configured not to convert or cannot convert.
682 if not isinstance(value
, self
.expected_type
):
684 raise MissingAttribute('Missing value is required.')
688 return self
.expected_type(value
)
689 except ValueError, e
:
690 raise ValidationError(
691 'Value %r for %s could not be converted to type %s.' % (
692 value
, key
, self
.expected_type
.__name
__), e
)
694 raise ValidationError(
695 'Value %r for %s is not of the expected type %s' % (
696 value
, key
, self
.expected_type
.__name
__), e
)
698 raise ValidationError(
699 'Value %r for %s is not of the expected type %s' % (
700 value
, key
, self
.expected_type
.__name
__))
705 TYPE_BOOL
= Type(bool)
707 TYPE_LONG
= Type(long)
709 TYPE_UNICODE
= Type(unicode)
710 TYPE_FLOAT
= Type(float)
713 class Options(Validator
):
714 """Limit field based on pre-determined values.
716 Options are used to make sure an enumerated set of values are the only
717 one permitted for assignment. It is possible to define aliases which
718 map multiple string values to a single original. An example of usage:
720 class ZooAnimal(validated.Class):
723 'kind': Options('platypus', # No aliases
724 ('rhinoceros', ['rhino']), # One alias
725 ('canine', ('dog', 'puppy')), # Two aliases
729 def __init__(self
, *options
, **kw
):
730 """Initialize options.
733 options: List of allowed values.
736 default
= kw
['default']
741 def AddAlias(alias
, original
):
742 """Set new alias on alias_map.
745 AttributeDefinitionError: when option already exists or if alias is
748 if not isinstance(alias
, str):
749 raise AttributeDefinitionError(
750 'All option values must be of type str.')
751 elif alias
in alias_map
:
752 raise AttributeDefinitionError(
753 "Option '%s' already defined for options property." % alias
)
754 alias_map
[alias
] = original
757 for option
in options
:
758 if isinstance(option
, str):
759 AddAlias(option
, option
)
761 elif isinstance(option
, (list, tuple)):
764 raise AttributeDefinitionError("Alias is defined as a list of tuple "
765 "with two items. The first is the "
766 "original option, while the second "
767 "is a list or tuple of str aliases.\n"
769 " ('original', ('alias1', "
771 original
, aliases
= option
772 AddAlias(original
, original
)
773 if not isinstance(aliases
, (list, tuple)):
774 raise AttributeDefinitionError('Alias lists must be a list or tuple')
776 for alias
in aliases
:
777 AddAlias(alias
, original
)
780 raise AttributeDefinitionError("All options must be of type str "
781 "or of the form (str, [str...]).")
782 super(Options
, self
).__init
__(default
)
783 self
.options
= alias_map
785 def Validate(self
, value
, key
):
789 Original value for provided alias.
792 ValidationError: when value is not one of predefined values.
795 raise ValidationError('Value for options field must not be None.')
797 if value
not in self
.options
:
798 raise ValidationError('Value \'%s\' for %s not in %s.'
799 % (value
, key
, self
.options
))
800 return self
.options
[value
]
803 class Optional(Validator
):
804 """Definition of optional attributes.
806 Optional values are attributes which can be set to None or left
807 unset. All values in a basic Validated class are set to None
808 at initialization. Failure to assign to non-optional values
809 will result in a validation error when calling CheckInitialized.
812 def __init__(self
, validator
, default
=None):
815 This constructor will make a few guesses about the value passed in
818 - If the validator argument is a type, it automatically creates a Type
821 - If the validator argument is a list or tuple, it automatically
822 creates an Options validator around it.
825 validator: Optional validation condition.
828 AttributeDefinitionError: if validator is not callable.
830 self
.validator
= AsValidator(validator
)
831 self
.expected_type
= self
.validator
.expected_type
832 self
.default
= default
834 def Validate(self
, value
, key
):
835 """Optionally require a value.
837 Normal validators do not accept None. This will accept none on
838 behalf of the contained validator.
841 value: Value to be validated as optional.
842 key: Name of the field being validated.
845 None if value is None, else results of contained validation.
849 return self
.validator(value
, key
)
851 def ToValue(self
, value
):
852 """Convert 'value' to a simplified collection or basic type."""
855 return self
.validator
.ToValue(value
)
858 class Regex(Validator
):
859 """Regular expression validator.
861 Regular expression validator always converts value to string. Note that
862 matches must be exact. Partial matches will not validate. For example:
864 class ClassDescr(Validated):
865 ATTRIBUTES = { 'name': Regex(r'[a-zA-Z_][a-zA-Z_0-9]*'),
866 'parent': Type(type),
869 Alternatively, any attribute that is defined as a string is automatically
870 interpreted to be of type Regex. It is possible to specify unicode regex
871 strings as well. This approach is slightly less efficient, but usually
872 is not significant unless parsing large amounts of data:
874 class ClassDescr(Validated):
875 ATTRIBUTES = { 'name': r'[a-zA-Z_][a-zA-Z_0-9]*',
876 'parent': Type(type),
879 # This will raise a ValidationError exception.
880 my_class(name='AName with space', parent=AnotherClass)
883 def __init__(self
, regex
, string_type
=unicode, default
=None):
884 """Initialized regex validator.
887 regex: Regular expression string to use for comparison.
890 AttributeDefinitionError: if string_type is not a kind of string.
892 super(Regex
, self
).__init
__(default
)
893 if (not issubclass(string_type
, basestring
) or
894 string_type
is basestring
):
895 raise AttributeDefinitionError(
896 'Regex fields must be a string type not %s.' % str(string_type
))
897 if isinstance(regex
, basestring
):
898 self
.re
= re
.compile('^(?:%s)$' % regex
)
900 raise AttributeDefinitionError(
901 'Regular expression must be string. Found %s.' % str(regex
))
903 self
.expected_type
= string_type
905 def Validate(self
, value
, key
):
906 """Does validation of a string against a regular expression.
909 value: String to match against regular expression.
910 key: Name of the field being validated.
913 ValidationError: when value does not match regular expression or
914 when value does not match provided string type.
916 if issubclass(self
.expected_type
, str):
917 cast_value
= TYPE_STR(value
)
919 cast_value
= TYPE_UNICODE(value
)
921 if self
.re
.match(cast_value
) is None:
922 raise ValidationError('Value \'%s\' for %s does not match expression '
923 '\'%s\'' % (value
, key
, self
.re
.pattern
))
927 class _RegexStrValue(object):
928 """Simulates the regex object to support recompilation when necessary.
930 Used by the RegexStr class to dynamically build and recompile regular
931 expression attributes of a validated object. This object replaces the normal
932 object returned from re.compile which is immutable.
934 When the value of this object is a string, that string is simply used as the
935 regular expression when recompilation is needed. If the state of this object
936 is a list of strings, the strings are joined in to a single 'or' expression.
939 def __init__(self
, attribute
, value
, key
):
940 """Initialize recompilable regex value.
943 attribute: Attribute validator associated with this regex value.
944 value: Initial underlying python value for regex string. Either a single
945 regex string or a list of regex strings.
946 key: Name of the field.
948 self
.__attribute
= attribute
953 def __AsString(self
, value
):
954 """Convert a value to appropriate string.
957 String version of value with all carriage returns and line feeds removed.
959 if issubclass(self
.__attribute
.expected_type
, str):
960 cast_value
= TYPE_STR(value
)
962 cast_value
= TYPE_UNICODE(value
)
964 cast_value
= cast_value
.replace('\n', '')
965 cast_value
= cast_value
.replace('\r', '')
968 def __BuildRegex(self
):
969 """Build regex string from state.
972 String version of regular expression. Sequence objects are constructed
973 as larger regular expression where each regex in the list is joined with
974 all the others as single 'or' expression.
976 if isinstance(self
.__value
, list):
977 value_list
= self
.__value
980 value_list
= [self
.__value
]
984 for item
in value_list
:
985 regex_list
.append(self
.__AsString
(item
))
988 return '|'.join('%s' % item
for item
in regex_list
)
993 """Build regular expression object from state.
996 Compiled regular expression based on internal value.
998 regex
= self
.__BuildRegex
()
1000 return re
.compile(regex
)
1002 raise ValidationError('Value \'%s\' for %s does not compile: %s' %
1003 (regex
, self
.__key
, e
), e
)
1007 """Compiled regular expression as described by underlying value."""
1008 return self
.__Compile
()
1010 def match(self
, value
):
1011 """Match against internal regular expression.
1014 Regular expression object built from underlying value.
1016 return re
.match(self
.__BuildRegex
(), value
)
1019 """Ensure that regex string compiles."""
1023 """Regular expression string as described by underlying value."""
1024 return self
.__BuildRegex
()
1026 def __eq__(self
, other
):
1027 """Comparison against other regular expression string values."""
1028 if isinstance(other
, _RegexStrValue
):
1029 return self
.__BuildRegex
() == other
.__BuildRegex
()
1030 return str(self
) == other
1032 def __ne__(self
, other
):
1033 """Inequality operator for regular expression string value."""
1034 return not self
.__eq
__(other
)
1037 class RegexStr(Validator
):
1038 """Validates that a string can compile as a regex without errors.
1040 Use this validator when the value of a field should be a regex. That
1041 means that the value must be a string that can be compiled by re.compile().
1042 The attribute will then be a compiled re object.
1045 def __init__(self
, string_type
=unicode, default
=None):
1046 """Initialized regex validator.
1049 AttributeDefinitionError: if string_type is not a kind of string.
1051 if default
is not None:
1052 default
= _RegexStrValue(self
, default
, None)
1053 re
.compile(str(default
))
1054 super(RegexStr
, self
).__init
__(default
)
1055 if (not issubclass(string_type
, basestring
) or
1056 string_type
is basestring
):
1057 raise AttributeDefinitionError(
1058 'RegexStr fields must be a string type not %s.' % str(string_type
))
1060 self
.expected_type
= string_type
1062 def Validate(self
, value
, key
):
1063 """Validates that the string compiles as a regular expression.
1065 Because the regular expression might have been expressed as a multiline
1066 string, this function also strips newlines out of value.
1069 value: String to compile as a regular expression.
1070 key: Name of the field being validated.
1073 ValueError when value does not compile as a regular expression. TypeError
1074 when value does not match provided string type.
1076 if isinstance(value
, _RegexStrValue
):
1078 value
= _RegexStrValue(self
, value
, key
)
1082 def ToValue(self
, value
):
1083 """Returns the RE pattern for this validator."""
1087 class Range(Validator
):
1088 """Validates that numbers fall within the correct range.
1090 In theory this class can be emulated using Options, however error
1091 messages generated from that class will not be very intelligible.
1092 This class essentially does the same thing, but knows the intended
1095 Also, this range class supports floats and other types that implement
1098 The range is inclusive, meaning 3 is considered in the range
1102 def __init__(self
, minimum
, maximum
, range_type
=int, default
=None):
1103 """Initializer for range.
1106 minimum: Minimum for attribute.
1107 maximum: Maximum for attribute.
1108 range_type: Type of field. Defaults to int.
1110 super(Range
, self
).__init
__(default
)
1111 if not isinstance(minimum
, range_type
):
1112 raise AttributeDefinitionError(
1113 'Minimum value must be of type %s, instead it is %s (%s).' %
1114 (str(range_type
), str(type(minimum
)), str(minimum
)))
1115 if not isinstance(maximum
, range_type
):
1116 raise AttributeDefinitionError(
1117 'Maximum value must be of type %s, instead it is %s (%s).' %
1118 (str(range_type
), str(type(maximum
)), str(maximum
)))
1120 self
.minimum
= minimum
1121 self
.maximum
= maximum
1122 self
.expected_type
= range_type
1123 self
._type
_validator
= Type(range_type
)
1125 def Validate(self
, value
, key
):
1126 """Validate that value is within range.
1128 Validates against range-type then checks the range.
1131 value: Value to validate.
1132 key: Name of the field being validated.
1135 ValidationError: when value is out of range. ValidationError when value
1136 is notd of the same range type.
1138 cast_value
= self
._type
_validator
.Validate(value
, key
)
1139 if cast_value
< self
.minimum
or cast_value
> self
.maximum
:
1140 raise ValidationError('Value \'%s\' for %s is out of range %s - %s'
1148 class Repeated(Validator
):
1149 """Repeated field validator.
1151 Indicates that attribute is expected to be a repeated value, ie,
1152 a sequence. This adds additional validation over just Type(list)
1153 in that it retains information about what can be stored in the list by
1154 use of its constructor field.
1157 def __init__(self
, constructor
, default
=None):
1158 """Initializer for repeated field.
1161 constructor: Type used for verifying elements of sequence attribute.
1163 super(Repeated
, self
).__init
__(default
)
1164 self
.constructor
= constructor
1165 self
.expected_type
= list
1167 def Validate(self
, value
, key
):
1168 """Do validation of sequence.
1170 Value must be a list and all elements must be of type 'constructor'.
1173 value: Value to validate.
1174 key: Name of the field being validated.
1177 ValidationError: if value is None, not a list or one of its elements is
1180 if not isinstance(value
, list):
1181 raise ValidationError('Value \'%s\' for %s should be a sequence but '
1182 'is not.' % (value
, key
))
1185 if isinstance(self
.constructor
, Validator
):
1186 item
= self
.constructor
.Validate(item
, key
)
1187 elif not isinstance(item
, self
.constructor
):
1188 raise ValidationError('Value element \'%s\' for %s must be type %s.' % (
1189 str(item
), key
, self
.constructor
.__name
__))
1194 class TimeValue(Validator
):
1195 """Validates time values with units, such as 1h or 3.5d."""
1197 _EXPECTED_SYNTAX
= ('must be a non-negative number followed by a time unit, '
1198 'such as 1h or 3.5d')
1201 super(TimeValue
, self
).__init
__()
1202 self
.expected_type
= str
1204 def Validate(self
, value
, key
):
1205 """Validate a time value.
1208 value: Value to validate.
1209 key: Name of the field being validated.
1212 ValidationError: if value is not a time value with the expected format.
1214 if not isinstance(value
, basestring
):
1215 raise ValidationError("Value '%s' for %s is not a string (%s)"
1216 % (value
, key
, TimeValue
._EXPECTED
_SYNTAX
))
1218 raise ValidationError("Value for %s is empty (%s)"
1219 % (key
, TimeValue
._EXPECTED
_SYNTAX
))
1220 if value
[-1] not in "smhd":
1221 raise ValidationError("Value '%s' for %s must end with a time unit, "
1222 "one of s (seconds), m (minutes), h (hours), "
1223 "or d (days)" % (value
, key
))
1225 t
= float(value
[:-1])
1227 raise ValidationError("Value '%s' for %s is not a valid time value (%s)"
1228 % (value
, key
, TimeValue
._EXPECTED
_SYNTAX
))
1230 raise ValidationError("Value '%s' for %s is negative (%s)"
1231 % (value
, key
, TimeValue
._EXPECTED
_SYNTAX
))