Example #1
0
    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()
Example #2
0
    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()
Example #3
0
    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()