Source code for ripozo.viewsets.fields.common

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from datetime import datetime
from ripozo.exceptions import ValidationException, TranslationException
from ripozo.viewsets.constants.input_categories import BODY_ARGS
from ripozo.viewsets.fields.base import BaseField

import six


[docs]class StringField(BaseField): """ Used for casting and validating string fields. """ field_type = six.text_type def __init__(self, name, required=False, maximum=None, minimum=None, arg_type=BODY_ARGS, regex=None, error_message=None): """ A field class for validating string inputs. :param arg_type: :param int min_length: The minimum legnth of the string :param _sre.SRE_Pattern regex: A compiled regular expression that must match at least once. """ super(StringField, self).__init__(name, required=required, maximum=maximum, minimum=minimum, arg_type=arg_type, error_message=error_message) self.regex = regex def _translate(self, obj, skip_required=False): """ Attempts to convert the object to a string type :param object obj: :return: The object in its string representation :rtype: unicode :raises: TranslationsException """ # A none input should be handled by the validator if obj is None: return obj obj = super(StringField, self)._translate(obj, skip_required=skip_required) return six.text_type(obj) def _validate(self, obj, skip_required=False): """ Validates the object. It makes a call to super checking if the input can be None :param unicode obj: :return: :rtype: unicode :raises: ValidationException """ obj = super(StringField, self)._validate(obj, skip_required=skip_required) if self._skip_validation(obj): return obj obj = self._validate_size(obj, len(obj)) if self.regex and not self.regex.match(obj): raise ValidationException(self.error_message or 'The input string did not match the' ' required regex: {0} != {1}'.format(obj, self.regex)) # passed validation return obj
[docs]class IntegerField(BaseField): """ A field used for translating and validating an integer input """ field_type = int def _translate(self, obj, skip_required=False): # A none input should be handled by the validator if obj is None: return obj obj = super(IntegerField, self)._translate(obj, skip_required=skip_required) try: return int(obj) except ValueError: raise TranslationException(self.error_message or 'Not a valid integer type: {0}'.format(obj)) def _validate(self, obj, skip_required=False): obj = super(IntegerField, self)._validate(obj, skip_required=skip_required) if self._skip_validation(obj): return obj return self._validate_size(obj, obj)
[docs]class FloatField(IntegerField): """ A field used for translating and validating a float input """ field_type = float def _translate(self, obj, skip_required=False): # A none input should be handled by the validator if obj is None: return obj obj = super(IntegerField, self)._translate(obj, skip_required=skip_required) try: return float(obj) except (ValueError, TypeError): raise TranslationException(self.error_message or 'obj is not castable to float: {0}'.format(obj))
[docs]class BooleanField(BaseField): """ A field used for translating and validating a boolean input It can take either a boolean or a string. """ field_type = bool def _translate(self, obj, skip_required=False): # A none input should be handled by the validator obj = super(BooleanField, self)._translate(obj, skip_required=skip_required) if obj is None: return obj if isinstance(obj, bool): return obj if isinstance(obj, six.string_types): if obj.lower() == 'false': return False elif obj.lower() == 'true': return True raise TranslationException(self.error_message or '{0} is not a valid boolean. Either' ' "true" or "false" is required (case insensitive)'.format(obj))
[docs]class DateTimeField(BaseField): """ A field for validating and translating a datetime input. By default it accepts the following formats: %Y-%m-%dT%H:%M:%S.%fZ If you need other formats simply pass a list of valid formats into the valid_formats parameter on initialization """ field_type = datetime valid_formats = ['%Y-%m-%dT%H:%M:%S.%fZ'] def __init__(self, name, required=False, maximum=None, minimum=None, arg_type=BODY_ARGS, valid_formats=None, error_message=None): """ :param unicode name: The name of the field :param bool required: Whether the field is required :param datetime maximum: The field must be less than the maximum :param datetime minimum: The input must be greater than this :param unicode arg_type: Where the input should be put :param list valid_formats: A list of datetime formats that are valid for translation. By default it accepts %Y-%m-%dT%H:%M:%S.%fZ :param unicode error_message: The error message to be returned if the validation or translation fails. """ super(DateTimeField, self).__init__(name, required=required, maximum=maximum, minimum=minimum, arg_type=arg_type, error_message=error_message) self.valid_formats = valid_formats or self.valid_formats def _translate(self, obj, skip_required=False): """ First checks if the obj is None or already a datetime object Returns that if true. Otherwise assumes that it is a string and attempts to parse it out using the formats in self.valid_formats and the datetime.strptime method Additionally it strips out any whitespace from the beginning and end of the input before attempting to parse out a datetime string :param unicode obj: The input that is being translated :return: The parse datetime object :rtype: datetime """ if obj is None or isinstance(obj, datetime): return obj obj = obj.strip() for f in self.valid_formats: try: return datetime.strptime(obj, f) except ValueError: continue raise TranslationException(self.error_message or 'The object ({0}) could not be parsed as a datetime ' 'string using the formats {1}'.format(obj, self.valid_formats)) def _validate(self, obj, skip_required=False): """ Just makes a size check on top of instance type check :param datetime obj: :return: The object unchanged :rtype: datetime :raises: ValidationException """ obj = super(DateTimeField, self)._validate(obj, skip_required=skip_required) return self._validate_size(obj, obj)
[docs]class ListField(BaseField): """ A field for a list of objects. A field for the individual results can also be provided. This would be run against every individual item in the list that is provided. """ field_type = list # TODO test and finish docs def __init__(self, name, required=False, maximum=None, minimum=None, arg_type=BODY_ARGS, error_message=None, indv_field=BaseField('list')): self.indv_field = indv_field super(ListField, self).__init__(name, required=required, maximum=maximum, minimum=minimum, arg_type=arg_type, error_message=error_message)
[docs] def translate(self, obj, skip_required=False, validate=False): obj = super(ListField, self).translate(obj, skip_required=skip_required, validate=validate) if obj is None: return obj translated_list = [] for f in obj: translated_list.append(self.indv_field.translate(f, skip_required=skip_required, validate=validate)) return translated_list
def _translate(self, obj, skip_required=False): if obj is None: # let the validation handle it. return obj if not isinstance(obj, (list, set, tuple,)): raise TranslationException(self.error_message or 'A list field must be an instance of a list, ' 'tuple, or set') return obj def _validate(self, obj, skip_required=False): obj = super(ListField, self)._validate(obj, skip_required=skip_required) if not obj: obj = [] return self._validate_size(obj, len(obj), msg=self.error_message)