def _validate(self): """ Compare fields to the schema and raise AttributeError if mismatched. Named _validate instead of validate because the data may have a field named "validate". """ fields, schema = self.__dict__, self._schema # Check for extra fields not defined in the schema extra_fields = fields.viewkeys() - schema.viewkeys() - BUILT_IN_ATTRS if len(extra_fields) > 0: raise AttributeError( 'Fields found that are not in the schema: %r' % (list(extra_fields))) required_decorator = 'Required' content_type_decorator = 'ContentType' content_count_decorator = 'ContentCount' value_range_decorator = 'ValueRange' value_pattern_decorator = 'ValuePattern' # Check required field criteria met for key in schema: if 'decorators' in schema[key] and required_decorator in schema[ key]['decorators']: if not key in fields or fields[key] is None: raise AttributeError('Required value "%s" not set' % key) # Check each attribute for key in fields.iterkeys(): if key in BUILT_IN_ATTRS: continue schema_val = schema[key] # Correct any float or long types that got downgraded to int if isinstance(fields[key], int): if schema_val['type'] == 'float': fields[key] = float(fields[key]) elif schema_val['type'] == 'long': fields[key] = long(fields[key]) # argh, annoying work around for OrderedDict vs dict issue if type(fields[key] ) == dict and schema_val['type'] == 'OrderedDict': fields[key] = OrderedDict(fields[key]) # Basic type checking field_val = fields[key] if type(field_val).__name__ != schema_val['type']: # if the schema doesn't define a type, we can't very well validate it if schema_val['type'] == 'NoneType': continue # Allow unicode instead of str. This may be too lenient. if schema_val['type'] == 'str' and type( field_val).__name__ == 'unicode': continue # Already checked for required above. Assume optional and continue if field_val is None: continue # Allow unicode instead of str. This may be too lenient. if schema_val['type'] == 'str' and type( field_val).__name__ == 'unicode': continue # IonObjects are ok for dict fields too! if isinstance( field_val, IonObjectBase) and schema_val['type'] == 'OrderedDict': continue if not key in fields or fields[key] is None: raise AttributeError('Required value "%s" not set' % key) # Check for inheritance if self.check_inheritance_chain(type(field_val), schema_val['type']): continue # Check enum types from pyon.core.registry import enum_classes if isinstance(field_val, int) and schema_val['type'] in enum_classes: if field_val not in enum_classes( schema_val['type'])._str_map: raise AttributeError( 'Invalid enum value "%d" for field "%s.%s", should be between 1 and %d' % (fields[key], type(self).__name__, key, len(enum_classes(schema_val['type'])._str_map))) else: continue if type(field_val) == tuple and schema_val['type'] == 'list': continue if isinstance(field_val, IonObjectBase) and schema_val['type'] == 'dict': log.warn( 'TODO: Please convert generic dict attribute type to abstract type for field "%s.%s"' % (type(self).__name__, key)) continue # Special case check for ION object being passed where default type is dict or str if 'decorators' in schema_val: if content_type_decorator in schema_val['decorators']: if isinstance( field_val, IonObjectBase ) and schema_val['type'] == 'dict' or schema_val[ 'type'] == 'str': self.check_content( key, field_val, schema_val['decorators'] [content_type_decorator]) continue raise AttributeError( 'Invalid type "%s" for field "%s.%s", should be "%s"' % (type(fields[key]), type(self).__name__, key, schema_val['type'])) if type(field_val).__name__ == 'str': if value_pattern_decorator in schema_val['decorators']: self.check_string_pattern_match( key, field_val, schema_val['decorators'][value_pattern_decorator]) if type(field_val).__name__ in ['int', 'float', 'long']: if value_range_decorator in schema_val['decorators']: self.check_numeric_value_range( key, field_val, schema_val['decorators'][value_range_decorator]) if 'decorators' in schema_val: if content_type_decorator in schema_val['decorators']: if schema_val['type'] == 'list': self.check_collection_content( key, field_val, schema_val['decorators'][content_type_decorator]) elif schema_val['type'] == 'dict' or schema_val[ 'type'] == 'OrderedDict': self.check_collection_content( key, field_val.values(), schema_val['decorators'][content_type_decorator]) else: self.check_content( key, field_val, schema_val['decorators'][content_type_decorator]) if content_count_decorator in schema_val['decorators']: if schema_val['type'] == 'list': self.check_collection_length( key, field_val, schema_val['decorators'][content_count_decorator]) if schema_val['type'] == 'dict' or schema_val[ 'type'] == 'OrderedDict': self.check_collection_length( key, field_val.values(), schema_val['decorators'][content_count_decorator]) if isinstance(field_val, IonObjectBase): field_val._validate() # Next validate only IonObjects found in child collections. # Note that this is non-recursive; only for first-level collections. elif isinstance(field_val, Mapping): for subkey in field_val: subval = field_val[subkey] if isinstance(subval, IonObjectBase): subval._validate() elif isinstance(field_val, Iterable): for subval in field_val: if isinstance(subval, IonObjectBase): subval._validate()
def _validate(self): """ Compare fields to the schema and raise AttributeError if mismatched. Named _validate instead of validate because the data may have a field named "validate". """ fields, schema = self.__dict__, self._schema # Check for extra fields not defined in the schema extra_fields = fields.viewkeys() - schema.viewkeys() - built_in_attrs if len(extra_fields) > 0: raise AttributeError('Fields found that are not in the schema: %r' % (list(extra_fields))) required_decorator = 'Required' content_type_decorator = 'ContentType' content_count_decorator = 'ContentCount' value_range_decorator = 'ValueRange' value_pattern_decorator = 'ValuePattern' # Check required field criteria met for key in schema: if 'decorators' in schema[key] and required_decorator in schema[key]['decorators']: if not key in fields or fields[key] is None: raise AttributeError('Required value "%s" not set' % key) # Check each attribute for key in fields.iterkeys(): if key in built_in_attrs: continue schema_val = schema[key] # Correct any float or long types that got downgraded to int if isinstance(fields[key], int): if schema_val['type'] == 'float': fields[key] = float(fields[key]) elif schema_val['type'] == 'long': fields[key] = long(fields[key]) # argh, annoying work around for OrderedDict vs dict issue if type(fields[key]) == dict and schema_val['type'] == 'OrderedDict': fields[key] = OrderedDict(fields[key]) # Basic type checking field_val = fields[key] if 'decorators' in schema_val: log.debug("Validating %s: %s: %s: %s" % (key, schema_val["type"], schema_val["decorators"], str(field_val))) else: log.debug("Validating %s: %s: %s" % (key, schema_val["type"], str(field_val))) if type(field_val).__name__ != schema_val['type']: # if the schema doesn't define a type, we can't very well validate it if schema_val['type'] == 'NoneType': continue # Already checked for required above. Assume optional and continue if field_val is None: continue # IonObjects are ok for dict fields too! if isinstance(field_val, IonObjectBase) and schema_val['type'] == 'OrderedDict': continue if not key in fields or fields[key] is None: raise AttributeError('Required value "%s" not set' % key) # Check for inheritance if self.check_inheritance_chain(type(field_val), schema_val['type']): continue # Check enum types from pyon.core.registry import enum_classes if isinstance(field_val, int) and schema_val['type'] in enum_classes: if field_val not in enum_classes(schema_val['type'])._str_map: raise AttributeError('Invalid enum value "%d" for field "%s.%s", should be between 1 and %d' % (fields[key], type(self).__name__, key, len(enum_classes(schema_val['type'])._str_map))) else: continue # TODO work around for msgpack issue if type(field_val) == tuple and schema_val['type'] == 'list': continue # TODO remove this at some point if isinstance(field_val, IonObjectBase) and schema_val['type'] == 'dict': log.warn('TODO: Please convert generic dict attribute type to abstract type for field "%s.%s"' % (type(self).__name__, key)) continue # Special case check for ION object being passed where default type is dict or str if 'decorators' in schema_val: if content_type_decorator in schema_val['decorators']: if isinstance(field_val, IonObjectBase) and schema_val['type'] == 'dict' or schema_val['type'] == 'str': self.check_content(key, field_val, schema_val['decorators'][content_type_decorator]) continue raise AttributeError('Invalid type "%s" for field "%s.%s", should be "%s"' % (type(fields[key]), type(self).__name__, key, schema_val['type'])) if type(field_val).__name__ == 'str': if value_pattern_decorator in schema_val['decorators']: self.check_string_pattern_match(key, field_val, schema_val['decorators'][value_pattern_decorator]) if type(field_val).__name__ in ['int', 'float', 'long']: if value_range_decorator in schema_val['decorators']: self.check_numeric_value_range(key, field_val, schema_val['decorators'][value_range_decorator]) if 'decorators' in schema_val: if content_type_decorator in schema_val['decorators']: if schema_val['type'] == 'list': self.check_collection_content(key, field_val, schema_val['decorators'][content_type_decorator]) elif schema_val['type'] == 'dict' or schema_val['type'] == 'OrderedDict': self.check_collection_content(key, field_val.values(), schema_val['decorators'][content_type_decorator]) else: self.check_content(key, field_val, schema_val['decorators'][content_type_decorator]) if content_count_decorator in schema_val['decorators']: if schema_val['type'] == 'list': self.check_collection_length(key, field_val, schema_val['decorators'][content_count_decorator]) if schema_val['type'] == 'dict' or schema_val['type'] == 'OrderedDict': self.check_collection_length(key, field_val.values(), schema_val['decorators'][content_count_decorator]) if isinstance(field_val, IonObjectBase): field_val._validate() # Next validate only IonObjects found in child collections. # Note that this is non-recursive; only for first-level collections. elif isinstance(field_val, Mapping): for subkey in field_val: subval = field_val[subkey] if isinstance(subval, IonObjectBase): subval._validate() elif isinstance(field_val, Iterable): for subval in field_val: if isinstance(subval, IonObjectBase): subval._validate()
def _validate(self, validate_objects=True): """ Compare fields to the schema and raise AttributeError if mismatched. Named _validate instead of validate because the data may have a field named "validate". """ fields, schema = self.__dict__, self._schema # Check for extra fields not defined in the schema extra_fields = fields.viewkeys() - schema.viewkeys() - BUILT_IN_ATTRS if len(extra_fields) > 0: raise AttributeError("Invalid field(s): %r" % (list(extra_fields))) # Check required field criteria met for key in schema: if DECO_VALIDATE_REQUIRED in schema[key].get('decorators', {}): if key not in fields or fields[key] is None: raise AttributeError("Value required for '%s'" % key) # Check each attribute for key in fields.iterkeys(): if key in BUILT_IN_ATTRS: continue schema_val = schema[key] schema_val_type = schema_val['type'] schema_val_decos = schema_val.get('decorators', {}) # Side effect - Correct any float or long types that got downgraded to int if isinstance(fields[key], int): if schema_val_type == 'float': fields[key] = float(fields[key]) elif schema_val_type == 'long': fields[key] = long(fields[key]) # Side effect - Work around for OrderedDict vs dict issue if type(fields[key]) == dict and schema_val_type == 'OrderedDict': fields[key] = OrderedDict(fields[key]) # Basic type checking field_val = fields[key] field_val_type = type(field_val).__name__ #log.debug("Validating %s: %s: %s: %s" % (key, schema_val_type, schema_val_decos, field_val)) if field_val_type == "long" and schema_val_type == "int": # Accept a long for an int pass elif field_val_type != schema_val_type: # If the schema type is None, all types are allowed if schema_val_type == 'NoneType': continue # Allow unicode instead of str. This may be too lenient. if schema_val_type == 'str' and field_val_type == 'unicode': continue # Already checked for required above. Assume optional and continue if field_val is None: continue # Allow unicode instead of str. This may be too lenient. if schema_val_type == 'str' and field_val_type == 'unicode': continue # IonObjects are ok for dict fields too! if isinstance(field_val, IonObjectBase) and schema_val_type == 'OrderedDict': continue # Check for inheritance if self._check_inheritance_chain(type(field_val), schema_val_type): continue # Check enum types from pyon.core.registry import enum_classes if isinstance(field_val, int) and schema_val_type in enum_classes: if field_val in enum_classes[schema_val_type]._str_map: continue raise AttributeError("Invalid enum value '%d' for field '%s.%s', should be between 1 and %d" % (fields[key], type(self).__name__, key, len(enum_classes(schema_val_type)._str_map))) # Tuple allowed for list type (Msgpack decodes list to tuples) if type(field_val) == tuple and schema_val_type == 'list': continue # IonObject allowed for dict type if isinstance(field_val, IonObjectBase) and schema_val_type == 'dict': #log.warn('Please convert generic dict attribute type to abstract type for field "%s.%s"' % (type(self).__name__, key)) continue # Special case check for ION object being passed where default type is dict or str if DECO_VALIDATE_CONTENT_TYPE in schema_val_decos: if isinstance(field_val, IonObjectBase) and schema_val_type in ('dict', 'str'): self._check_content(key, field_val, schema_val_decos[DECO_VALIDATE_CONTENT_TYPE]) continue raise AttributeError("Invalid type '%s' for field '%s.%s', should be '%s'" % (field_val_type, type(self).__name__, key, schema_val_type)) if field_val_type == 'str' and DECO_VALIDATE_VALUE_PATTERN in schema_val_decos: self._check_string_pattern_match(key, field_val, schema_val_decos[DECO_VALIDATE_VALUE_PATTERN]) if field_val_type in ('int', 'float', 'long') and DECO_VALIDATE_VALUE_RANGE in schema_val_decos: self._check_numeric_value_range(key, field_val, schema_val_decos[DECO_VALIDATE_VALUE_RANGE]) if DECO_VALIDATE_CONTENT_TYPE in schema_val_decos: if schema_val_type == 'list': self._check_collection_content(key, field_val, schema_val_decos[DECO_VALIDATE_CONTENT_TYPE]) elif schema_val_type in ('dict', 'OrderedDict'): self._check_collection_content(key, field_val.values(), schema_val_decos[DECO_VALIDATE_CONTENT_TYPE]) else: self._check_content(key, field_val, schema_val_decos[DECO_VALIDATE_CONTENT_TYPE]) if DECO_VALIDATE_CONTENT_COUNT in schema_val_decos and schema_val_type in ('list', 'dict', 'OrderedDict'): self._check_collection_length(key, len(field_val), schema_val_decos[DECO_VALIDATE_CONTENT_COUNT]) if validate_objects: # Only if desired - if entire object is walked anyways, these checks are redundant if isinstance(field_val, IonObjectBase): field_val._validate() # Next validate only IonObjects found in child collections. # Note that this is non-recursive; only for first-level collections. elif isinstance(field_val, Mapping): for subkey in field_val: subval = field_val[subkey] if isinstance(subval, IonObjectBase): subval._validate() elif isinstance(field_val, Iterable): for subval in field_val: if isinstance(subval, IonObjectBase): subval._validate()