def __init__(self, fields, **kwargs): # Some helpful functions is_basetype = lambda tipe: isinstance(tipe, BaseType) is_model = lambda tipe: isinstance(tipe, ModelType) is_dicttype = lambda tipe: isinstance(tipe, DictType) # field instance if is_basetype(fields): if is_model(fields): kwargs.setdefault('primary_embedded', fields) fields = [fields] # something other than a list elif not isinstance(fields, list): raise TypeException('Argument to ListType constructor must be ' 'a valid field or list of fields', self.field_name, list) # some bad stuff in the list elif list(ifilterfalse(is_basetype, fields)): raise TypeException('Argument to ListType constructor must be ' 'a valid field or list of valid fields', self.field_name, list) else: models = filter(is_model, fields) dicts = filter(is_dicttype, fields) if dicts: kwargs.setdefault('primary_embedded', None) if models: kwargs.setdefault('primary_embedded', models[0]) self.fields = fields kwargs.setdefault('default', list) self.primary_embedded = kwargs.pop('primary_embedded', None) super(ListType, self).__init__(**kwargs)
def validate(self, value): if len(value) != MD5Type.hash_length: raise TypeException('MD5 value is wrong length', self.field_name, value) try: int(value, 16) except: raise TypeException('MD5 value is not hex', self.field_name, value) return value
def validate(self, value): """Make sure that a list of valid fields is being used. """ if not isinstance(value, dict): raise TypeException('Only dictionaries may be used in a ' 'DictType', self.field_name, value) if any(('.' in k or '$' in k) for k in value): raise TypeException('Invalid dictionary key name - keys may not ' 'contain "." or "$" characters', self.field_name, value) return value
def validate(self, value): if not URLType.URL_REGEX.match(value): raise TypeException('Invalid URL', self.field_name, value) if self.verify_exists: import urllib2 try: request = urllib2.Request(value) urllib2.urlopen(request) except Exception: message = 'URL does not exist' raise TypeException(message, self.field_name, value) return value
def validate(self, value): assert isinstance(value, (str, unicode)) if self.max_length is not None and len(value) > self.max_length: raise TypeException('String value is too long', self.field_name, value) if self.min_length is not None and len(value) < self.min_length: raise TypeException('String value is too short', self.field_name, value) if self.regex is not None and self.regex.match(value) is None: message = 'String value did not match validation regex', raise TypeException(message, self.field_name, value) return value
def _validate_helper(cls, field_inspector, values, validate_all=False, delete_rogues=True): """This is a convenience function that loops over the given values and attempts to validate them against the class definition. It only validates the data in values and does not guarantee a complete model is present. 'not present' is defined as not having a value OR having '' (or u'') as a value. """ if not hasattr(cls, '_fields'): raise ValueError('cls is not a Model instance') internal_fields = cls._get_internal_fields() # Create function for handling exceptions exceptions = list() handle_exception = cls._gen_handle_exception(validate_all, exceptions) # Create function for handling a flock of frakkin palins (rogue fields) data_fields = set(values.keys()) class_fields = list() handle_class_field = cls._gen_handle_class_field( delete_rogues, class_fields) # Loop across fields present in model for k, v in cls._fields.items(): # handle common id name if k is 'id': k = '_id' handle_class_field(k) # we don't accept internal fields from users if k in internal_fields and k in values: value_is_default = (values[k] is v.default) if not value_is_default: error_msg = 'Overwrite of internal fields attempted' e = TypeException(error_msg, k, v) handle_exception(e) continue if field_inspector(k, v): datum = values[k] # if datum is None, skip if datum is None: continue # treat empty strings as empty values and skip if isinstance(datum, (str, unicode)) and \ len(datum.strip()) == 0: continue try: v.validate(datum) except TypeException, e: handle_exception(e)
def validate(self, value): """Make sure that a list of valid fields is being used. """ if not isinstance(value, (list, tuple)): error_msg = 'Only lists and tuples may be used in a list field' raise TypeException(error_msg, self.field_name, value) if not self.fields: # if we want everything to validate return for item in value: try: for field in self.fields: field.validate(item) except Exception, e: raise TypeException('Invalid ListType item', self.field_name, str(item))
def __init__(self, model_type, **kwargs): is_embeddable = lambda dt: issubclass(dt, Model) if not isinstance(model_type, basestring): if not model_type or not is_embeddable(model_type): raise TypeException('Invalid model class provided to an ' 'ModelType', self.field_name, model_type) self.model_type_obj = model_type super(ModelType, self).__init__(**kwargs)
def validate(self, value): try: value = self.number_class(value) except: raise TypeException('Not %s' % self.number_type, self.field_name, value) if self.min_value is not None and value < self.min_value: raise TypeException('%s value below min_value: %s' % (self.number_type, self.min_value), self.field_name, value) if self.max_value is not None and value > self.max_value: raise TypeException('%s value above max_value: %s' % (self.number_type, self.max_value), self.field_name, value) return value
def _validate(self, value): # check choices if self.choices is not None: if value not in self.choices: raise TypeException( "Value must be one of %s." % unicode(self.choices), self.field_name, value) # check validation argument if self.validation is not None: if callable(self.validation): if not self.validation(value): raise TypeException( 'Value does not match custom' 'validation method.', self.field_name, value) else: raise ValueError('validation argument must be a callable.') return self.validate(value)
def validate(self, value): if not isinstance(value, decimal.Decimal): if not isinstance(value, basestring): value = str(value) try: value = decimal.Decimal(value) except Exception: raise TypeException('Could not convert to decimal', self.field_name, value) if self.min_value is not None and value < self.min_value: raise TypeException('Decimal value below min_value: %s' % self.min_value, self.field_name, value) if self.max_value is not None and value > self.max_value: raise TypeException('Decimal value above max_value: %s' % self.max_value, self.field_name, value) return value
def validate(self, value): """Make sure that the model instance is an instance of the Model subclass provided when the model was defined. """ # Using isinstance also works for subclasses of self.model if not isinstance(value, self.model_type): raise TypeException('Invalid modeltype instance ' 'provided to an ModelType', self.field_name, value) self.model_type.validate(value) return value
def validate(self, value): """Make sure the value is a valid uuid representation. See http://docs.python.org/library/uuid.html for accepted formats. """ if not isinstance(value, (uuid.UUID,)): try: value = uuid.UUID(value) except ValueError: raise TypeException('Not a valid UUID value', self.field_name, value) return value
def _validate(self, value): """This function runs before `validate()` and handles applying the global environment parameters. """ # `choices` if self.choices is not None: if value not in self.choices: raise TypeException("Value must be one of %s." % unicode(self.choices), self.field_name, value) # `validation` function if self.validation is not None: if callable(self.validation): if not self.validation(value): raise TypeException('Value does not match custom' 'validation method.', self.field_name, value) else: raise ValueError('validation argument must be a callable.') return self.validate(value)
class BaseModel(object): def __init__(self, **values): self._data = {} minimized_field_map = {} # Assign default values to instance for attr_name, attr_value in self._fields.items(): # Use default value if present value = getattr(self, attr_name, None) setattr(self, attr_name, value) if attr_value.minimized_field_name: field_name = attr_value.minimized_field_name minimized_field_map[field_name] = attr_value.uniq_field # Assign initial values to instance for attr_name, attr_value in values.items(): try: if attr_name == '_id': attr_name = 'id' setattr(self, attr_name, attr_value) if attr_name in minimized_field_map: setattr(self, minimized_field_map[attr_name], attr_value) # Put a diaper on the keys that don't belong and send 'em home except AttributeError: pass def validate(self, validate_all=False): """Ensure that all fields' values are valid and that required fields are present. Throws a ModelException if Model is invalid """ # Get a list of tuples of field names and their current values fields = [(field, getattr(self, name)) for name, field in self._fields.items()] # Ensure that each field is matched to a valid value errs = [] for field, value in fields: err = None # treat empty strings as nonexistent if value is not None and value != '': try: field._validate(value) except TypeException, e: err = e except (ValueError, AttributeError, AssertionError): err = TypeException('Invalid value', field.field_name, value) elif field.required: err = TypeException('Required field missing', field.field_name, value)
def validate(self, value): """Make sure that a geo-value is of type (x, y) """ if not len(value) == 2: raise TypeException('Value must be a two-dimensional point', self.field_name, value) if isinstance(value, dict): for v in value.values(): if not isinstance(v, (float, int)): error_msg = 'Both values in point must be float or int' raise TypeException(error_msg, self.field_name, value) elif isinstance(value, (list, tuple)): if (not isinstance(value[0], (float, int)) and not isinstance(value[1], (float, int))): error_msg = 'Both values in point must be float or int' raise TypeException(error_msg, self.field_name, value) else: raise TypeException('GeoPointType can only accept tuples, ' 'lists of (x, y), or dicts of {k1: v1, ' 'k2: v2}', self.field_name, value) return value
def date_to_iso8601(cls, dt, format): """Classmethod that goes the opposite direction of iso8601_to_date. Defaults to using isoformat(), but can use the optional format argument either as a strftime format string or as a custom date formatting function or lambda. """ if isinstance(format, str): iso_dt = dt.strftime(format) elif hasattr(format, '__call__'): iso_dt = format(dt) else: raise TypeException('DateTimeType format must be a string or callable') return iso_dt
def validate_instance(model, validate_all=False): """Ensure that all fields' values are valid and that required fields are present. Throws a ModelException if Model is invalid """ # Get a list of tuples of field names and their current values fields = [(field, getattr(model, name)) for name, field in model._fields.items()] # Ensure that each field is matched to a valid value errs = [] for field, value in fields: err = None # treat empty strings as nonexistent if value is not None and value != '': try: field._validate(value) except TypeException, e: err = e except (ValueError, AttributeError, AssertionError): err = TypeException('Invalid value', field.field_name, value)
def for_python(self, value): try: return bson.objectid.ObjectId(unicode(value)) except Exception, e: raise TypeException('Invalid ObjectId', self.field_name, value)
# Ensure that each field is matched to a valid value errs = [] for field, value in fields: err = None # treat empty strings as nonexistent if value is not None and value != '': try: field._validate(value) except TypeException, e: err = e except (ValueError, AttributeError, AssertionError): err = TypeException('Invalid value', field.field_name, value) elif field.required: err = TypeException('Required field missing', field.field_name, value) # If validate_all, save errors to a list # Otherwise, throw the first error if err: errs.append(err) if err and not validate_all: # NB: raising a ModelException in this case would be more # consistent, but existing code might expect TypeException raise err if errs: raise ModelException(model._model_name, errs) return True
def validate(self, value): if not EmailType.EMAIL_REGEX.match(value): raise TypeException('Invalid email address', self.field_name, value) return value
def validate(self, value): if not isinstance(value, bson.objectid.ObjectId): try: value = bson.objectid.ObjectId(unicode(value)) except Exception, e: raise TypeException('Invalid ObjectId', self.field_name, value)
def validate(self, value): if not isinstance(value, bool): raise TypeException('Not a boolean', self.field_name, value) return value
def validate(self, value): if not isinstance(value, datetime.datetime): raise TypeException('Not a datetime', self.field_name, value) return value