def process(self, name, value): """ :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: TypedClassAny """ if self.required is False and value is None: return if self.desimplifier is not None: try: value = self.desimplifier(value) except TypedClassValidationError as exc: raise TypedClassValidationError('{name}: {error}'.format( name=name, error=str(exc), )) for func in self.all_validators: try: func(self, value) except TypedClassValidationError as exc: raise TypedClassValidationError('{name}: {error}'.format( name=name, error=str(exc), )) return value
def process(self, name, value): """ :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: tuple|None """ from typedclass.core import TypedClass # <-- circular import if self.required is False and value is None: return if isinstance(value, (tuple, list)): converted_value = [] for idx, entry in enumerate(value): try: if isinstance(entry, self.cls): converted_value.append(entry) elif isinstance(entry, dict) and issubclass( self.cls, TypedClass): f_instance = self.cls(**entry) converted_value.append(f_instance) elif issubclass(self.cls, BaseDataField): f_instance = self.cls() _converted = f_instance.process( name='{name}[{idx}]'.format( name=name, idx=idx, ), value=entry, ) converted_value.append(_converted) else: raise TypedClassValidationError() except TypedClassValidationError: raise TypedClassValidationError( '{name}: element with idx {idx} is not instance of {cls}' .format( name=name, idx=idx, cls=self.cls, )) return tuple(converted_value) else: raise TypedClassValidationError( '{name} is not list or tuple of {cls}'.format( name=name, cls=self.cls, ))
def validator_float(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ if not isinstance(value, float): raise TypedClassValidationError('Not an float') if field.min_value is not None and value < field.min_value: raise TypedClassValidationError('Float value < {}'.format( field.min_value)) if field.max_value is not None and value > field.max_value: raise TypedClassValidationError('Float value > {}'.format( field.max_value))
def desimplifier_datetime(value): """ :type value: TypedClassAny :rtype: TypedClassDatetime|TypedClassAny """ if isinstance(value, str): try: return dt.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S:%f') except ValueError: pass # ATTENTION! # all formats below are deprecated! # in future versions of typedclass this code will be deleted! # TODO: deprecated, remove after implementing custom format in f.DateTime try: return dt.datetime.strptime(value, '%Y-%m-%dT%H:%M:%SZ') except ValueError: pass try: return dt.datetime.strptime(value, '%Y-%m-%dT%H:%M:%S') except ValueError: pass try: return dt.datetime.strptime(value, '%Y-%m-%dT%H:%M') except ValueError: raise TypedClassValidationError('Not a datetime') return value
def validator_binary(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ if not isinstance(value, bytes): raise TypedClassValidationError('Not a binary')
def validator_decimal(field, value): """ :type field: TypedClassBaseDataField :type value: TypedClassAny :rtype: None """ if not isinstance(value, Decimal): raise TypedClassValidationError('Not a Decimal') if field.min_value is not None and value < field.min_value: raise TypedClassValidationError('Decimal value < {}'.format( field.min_value)) if field.max_value is not None and value > field.max_value: raise TypedClassValidationError('Decimal value > {}'.format( field.max_value))
def process(self, name, value): """ :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: set|None """ from typedclass.core import TypedClass # <-- circular import if self.required is False and value is None: return if isinstance(value, (set, frozenset, tuple, list)): converted_value = set() for entry in value: try: if isinstance(entry, self.cls): converted_value.add(entry) elif isinstance(entry, dict) and issubclass(self.cls, TypedClass): f_instance = self.cls(**entry) converted_value.add(f_instance) elif issubclass(self.cls, BaseDataField): f_instance = self.cls() _converted = f_instance.process( name=name, value=entry, ) converted_value.add(_converted) else: raise TypedClassValidationError() except TypedClassValidationError: raise TypedClassValidationError( '{name}: element "{value}" is not instance of {cls}'.format( name=name, value=entry, cls=self.cls, ) ) return converted_value else: raise TypedClassValidationError( '{name} is not set / frozenset / list / tuple of {cls}'.format( name=name, cls=self.cls, ) )
def simplifier_time(value): """ :type value: TypedClassAny :rtype: str """ if isinstance(value, dt.time): return value.strftime('%H:%M:%S') raise TypedClassValidationError('Not a time')
def validator_int(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ if not isinstance(value, int): raise TypedClassValidationError('Not an int') if field.min_value is not None and value < field.min_value: raise TypedClassValidationError('Int value < {}'.format( field.min_value)) if field.max_value is not None and value > field.max_value: raise TypedClassValidationError('Int value > {}'.format( field.max_value)) if field.choices and value not in field.choices: raise TypedClassValidationError('value not found in choices')
def simplifier_decimal(value): """ :type value: TypedClassAny :rtype: str """ if isinstance(value, Decimal): return str(value) raise TypedClassValidationError('Not a Decimal')
def validator_string(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ if not isinstance(value, str): raise TypedClassValidationError('Not a string') if field.min_length and len(value) < field.min_length: raise TypedClassValidationError('String length < {}'.format( field.min_length)) if field.max_length and len(value) > field.max_length: raise TypedClassValidationError('String length > {}'.format( field.max_length)) if field.choices and value not in field.choices: raise TypedClassValidationError('value not found in choices')
def simplifier_datetime(value): """ :type value: TypedClassAny :rtype: str """ if isinstance(value, dt.datetime): return value.strftime('%Y-%m-%dT%H:%M:%S:%f') raise TypedClassValidationError('Not a datetime')
def validator_string_english(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ error_msg = 'Not a string english' if not isinstance(value, str): raise TypedClassValidationError(error_msg) # ATTENTION! # don't forget about spaces! allowed_chars = string.ascii_letters + string.digits + "!#$%\()*+,-./:;&=?@[\\]^_`{|}~ " for character in value: if character not in allowed_chars: raise TypedClassValidationError(error_msg) return
def validator_time(field, value): """ :type field: TypedClassBaseDataField :type value: TypedClassAny :rtype: None """ if isinstance(value, dt.time): return raise TypedClassValidationError('Not a time')
def loads(cls, data, serializer=SimpleSerializer): """ :type cls: TypedClassCls :type data: str|TypedClassBytes :type serializer: TypedClassBaseSerializerCls :rtype: TypedClass """ try: return serializer.loads(cls, data) except ValueError: raise TypedClassValidationError('load data error')
def desimplifier_date(value): """ :type value: TypedClassAny :rtype: TypedClassDate|TypedClassAny """ if isinstance(value, str): try: return dt.datetime.strptime(value, '%Y-%m-%d').date() except ValueError: raise TypedClassValidationError('Not a date') return value
def desimplifier_float(value): """ :type value: TypedClassAny :rtype: float|TypedClassAny """ if isinstance(value, (str, int)): try: return float(value) except ValueError: raise TypedClassValidationError('Not a Float') return value
def validator_string_int(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ if isinstance(value, ( str, int, )): return raise TypedClassValidationError('Not a string / int')
def desimplifier_decimal(value): """ :type value: TypedClassAny :rtype: TypedClassDecimal|TypedClassAny """ if isinstance(value, (str, int)): try: return Decimal(value) except DecimalException: raise TypedClassValidationError('Not a Decimal') return value
def process_base(self, name, value): """ base validation for all fields value - external raw_data :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: None """ if self.required is True and value is None: raise TypedClassValidationError('value "{}" is required but None'.format(name))
def validator_string_email(field, value): """ :type field: TypedClassBaseDataField :rtype: None """ error_msg = 'Not a string email' if not isinstance(value, str): raise TypedClassValidationError(error_msg) if not len(value) < 255: raise TypedClassValidationError(error_msg) if value.count('@') > 1: raise TypedClassValidationError(error_msg) if '..' in value: raise TypedClassValidationError(error_msg) if re.search(_EMAIL_RE, value, re.I): return raise TypedClassValidationError(error_msg)
def process(self, name, value): """ :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: dict|None """ if self.required is False and value is None: return if not isinstance(value, Mapping): raise TypedClassValidationError( '{} is not Mapping type'.format(name) ) return value
def desimplifier_time(value): """ :type value: TypedClassAny :rtype: TypedClassTime|TypedClassAny """ if isinstance(value, str): try: return dt.datetime.strptime(value, '%H:%M:%S').time() except ValueError: pass try: return dt.datetime.strptime(value, '%H:%M').time() except ValueError: raise TypedClassValidationError('Not a time') return value
def test_desimplifier_error(): # create our new class, because we'll change it behaviour class TestBool(f.Bool): pass m_desimplifier = Mock(side_effect=TypedClassValidationError('test')) TestBool.desimplifier = m_desimplifier f_bool = TestBool() v_bool = '1' error = None try: f_bool.process(name='f_bool', value=v_bool) except TypedClassValidationError as exc: error = exc assert error msg = str(error) assert msg == 'f_bool: test'
def process(self, name, value): """ :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: TypedClass|None """ if self.required is False and value is None: return if isinstance(value, self.cls): return value elif isinstance(value, dict): f_instance = self.cls(**value) return f_instance else: raise TypedClassValidationError( '{name} is not instance of {cls}'.format( name=name, cls=self.cls, ))
def process(self, name, value): """ :type self: TypedClassBaseField :type name: str :type value: TypedClassAny :rtype: dict|None """ if self.required is False and value is None: return if not isinstance(value, Mapping): raise TypedClassValidationError( '{} is not Mapping type'.format(name)) converted = {} for _key, _value in value.items(): _key_converted = self.key.process('key', _key) _value_converted = self.value.process('value of {}'.format(_key), _value) converted[_key_converted] = _value_converted return converted
def _positive_validator(field, value): if value < pyDecimal('0'): raise TypedClassValidationError('Decimal is negative')
def _future_validator(field, value): if value < dt.date.today(): raise TypedClassValidationError('Date is not in future')
def _morning_validator(field, value): # 06:00 <= time < 12:00 if not (dt.time(6, 0) <= value < dt.time(12, 0)): raise TypedClassValidationError('Time is not in the morning range')
def _true_validator(field, value): if value is False: raise TypedClassValidationError('Bool is not True')