예제 #1
0
    def _validate_collection(self, value, custom_formatters=None):
        if self.items is None:
            raise UndefinedItemsSchema(self.type)

        if self.min_items is not None:
            if self.min_items < 0:
                raise OpenAPISchemaError("Schema for collection invalid:"
                                         " minItems must be non-negative")
            if len(value) < self.min_items:
                raise InvalidSchemaValue(
                    "Value must contain at least {type} item(s),"
                    " {value} found", len(value), self.min_items)
        if self.max_items is not None:
            if self.max_items < 0:
                raise OpenAPISchemaError("Schema for collection invalid:"
                                         " maxItems must be non-negative")
            if len(value) > self.max_items:
                raise InvalidSchemaValue(
                    "Value must contain at most {value} item(s),"
                    " {type} found", len(value), self.max_items)
        if self.unique_items and len(set(value)) != len(value):
            raise OpenAPISchemaError("Value may not contain duplicate items")

        f = functools.partial(self.items.validate,
                              custom_formatters=custom_formatters)
        return list(map(f, value))
예제 #2
0
    def cast(self,
             value,
             custom_formatters=None,
             strict=True,
             require_all_props=False):
        """Cast value to schema type"""
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema",
                                         value, self.type)
            return self.default

        if self.enum and value not in self.enum:
            raise InvalidSchemaValue(
                "Value {value} not in enum choices: {type}", value, self.enum)

        cast_mapping = self.get_cast_mapping(
            custom_formatters=custom_formatters,
            strict=strict,
            require_all_props=require_all_props)

        if self.type is not SchemaType.STRING and value == '':
            return None

        cast_callable = cast_mapping[self.type]
        try:
            return cast_callable(value)
        except UnmarshallerStrictTypeError:
            raise InvalidSchemaValue("Value {value} is not of type {type}",
                                     value, self.type)
        except ValueError:
            raise InvalidSchemaValue(
                "Failed to cast value {value} to type {type}", value,
                self.type)
예제 #3
0
    def _validate_number(self, value, custom_formatters=None):
        if self.minimum is not None:
            if self.exclusive_minimum and value <= self.minimum:
                raise InvalidSchemaValue(
                    "Value {value} is not less than or equal to {type}", value,
                    self.minimum)
            elif value < self.minimum:
                raise InvalidSchemaValue(
                    "Value {value} is not less than {type}", value,
                    self.minimum)

        if self.maximum is not None:
            if self.exclusive_maximum and value >= self.maximum:
                raise InvalidSchemaValue(
                    "Value {value} is not greater than or equal to {type}",
                    value, self.maximum)
            elif value > self.maximum:
                raise InvalidSchemaValue(
                    "Value {value} is not greater than {type}", value,
                    self.maximum)

        if self.multiple_of is not None and value % self.multiple_of:
            raise InvalidSchemaValue(
                "Value {value} is not a multiple of {type}", value,
                self.multiple_of)
예제 #4
0
    def unmarshal(self, value, custom_formatters=None, strict=True):
        """Unmarshal parameter from the value."""
        if self.deprecated:
            warnings.warn("The schema is deprecated", DeprecationWarning)
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema",
                                         value, self.type)
            return self.default

        if self.enum and value not in self.enum:
            raise InvalidSchemaValue(
                "Value {value} not in enum choices: {type}", value, self.enum)

        unmarshal_mapping = self.get_unmarshal_mapping(
            custom_formatters=custom_formatters, strict=strict)

        if self.type is not SchemaType.STRING and value == '':
            return None

        unmarshal_callable = unmarshal_mapping[self.type]
        try:
            unmarshalled = unmarshal_callable(value)
        except UnmarshallerStrictTypeError:
            raise InvalidSchemaValue("Value {value} is not of type {type}",
                                     value, self.type)
        except ValueError:
            raise InvalidSchemaValue(
                "Failed to unmarshal value {value} to type {type}", value,
                self.type)

        return unmarshalled
예제 #5
0
    def unmarshal(self, value, custom_formatters=None):
        """Unmarshal parameter from the value."""
        if self.deprecated:
            warnings.warn("The schema is deprecated", DeprecationWarning)

        casted = self.cast(value, custom_formatters=custom_formatters)

        if casted is None and not self.required:
            return None

        if self.enum and casted not in self.enum:
            raise InvalidSchemaValue(
                "Value {value} not in enum choices: {type}", value, self.enum)

        valid_casted_types_by_original_type = {
            str: (string_types, bytes),
            bytes: string_types,
            int: int,
            float: float,
            dict: Model,
            string_types: bytes,
        }

        is_string_and_format_datetime = self.format in ("date", "date-time") and isinstance(casted, (date, datetime))
        if not (value is None \
                or isinstance(casted, type(value)) \
                or is_string_and_format_datetime \
                or isinstance(casted, valid_casted_types_by_original_type[type(value)])):
            raise InvalidSchemaValue("Input {value} not valid for type {type}", value, self.type)

        return casted
예제 #6
0
 def _validate_number(self, value):
     if self.minimum is not None:
         if value < self.minimum:
             'The :attribute value :input is not between :min - :max.',
             raise InvalidSchemaValue(
                 "The attribute value {0} is less than {1}".format(
                     value, self.minimum))
     if self.maximum is not None:
         if value > self.maximum:
             raise InvalidSchemaValue(
                 "The attribute value {0} is greater than {1}".format(
                     value, self.maximum))
     return
예제 #7
0
    def _validate_object(self, value, custom_formatters=None):
        properties = value.__dict__

        if self.one_of:
            valid_one_of_schema = None
            for one_of_schema in self.one_of:
                try:
                    self._validate_properties(
                      properties, one_of_schema,
                      custom_formatters=custom_formatters)
                except OpenAPISchemaError:
                    pass
                else:
                    if valid_one_of_schema is not None:
                        raise MultipleOneOfSchema(self.type)
                    valid_one_of_schema = True

            if valid_one_of_schema is None:
                raise NoOneOfSchema(self.type)

        else:
            self._validate_properties(properties,
                                      custom_formatters=custom_formatters)

        if self.min_properties is not None:
            if self.min_properties < 0:
                raise OpenAPISchemaError(
                    "Schema for object invalid:"
                    " minProperties must be non-negative"
                )

            if len(properties) < self.min_properties:
                raise InvalidSchemaValue(
                    "Value must contain at least {type} properties,"
                    " {value} found", len(properties), self.min_properties
                )

        if self.max_properties is not None:
            if self.max_properties < 0:
                raise OpenAPISchemaError(
                    "Schema for object invalid:"
                    " maxProperties must be non-negative"
                )
            if len(properties) > self.max_properties:
                raise InvalidSchemaValue(
                    "Value must contain at most {type} properties,"
                    " {value} found", len(properties), self.max_properties
                )

        return True
예제 #8
0
    def validate(self, value):
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema")
            return self.default

        validator = self.VALIDATOR_CALLABLE_GETTER[self.type]

        if not validator(value):
            raise InvalidSchemaValue(
                "Value of {0} not valid type of {1}".format(
                    value, self.type.value))

        return value
예제 #9
0
    def _validate_string(self, value, custom_formatters=None):
        try:
            schema_format = SchemaFormat(self.format)
        except ValueError:
            msg = "Unsupported {0} format validation".format(self.format)
            if custom_formatters is not None:
                formatstring = custom_formatters.get(self.format)
                if formatstring is None:
                    raise OpenAPISchemaError(msg)
            else:
                raise OpenAPISchemaError(msg)
        else:
            formatstring =\
                self.STRING_FORMAT_CALLABLE_GETTER[schema_format]

        if not formatstring.validate(value):
            raise InvalidSchemaValue(
                "Value {value} not valid format {type}", value, self.format)

        if self.min_length is not None:
            if self.min_length < 0:
                raise OpenAPISchemaError(
                    "Schema for string invalid:"
                    " minLength must be non-negative"
                )
            if len(value) < self.min_length:
                raise InvalidSchemaValue(
                    "Value is shorter ({value}) than the minimum length of {type}",
                    len(value), self.min_length
                )
        if self.max_length is not None:
            if self.max_length < 0:
                raise OpenAPISchemaError(
                    "Schema for string invalid:"
                    " maxLength must be non-negative"
                )
            if len(value) > self.max_length:
                raise InvalidSchemaValue(
                    "Value is longer ({value}) than the maximum length of {type}",
                    len(value), self.max_length
                )
        if self.pattern is not None and not self.pattern.search(value):
            raise InvalidSchemaValue(
                "Value {value} does not match the pattern {type}",
                    value, self.pattern.pattern
            )

        return True
예제 #10
0
    def __call__(self,
                 value,
                 type_format=SchemaFormat.NONE,
                 strict=True,
                 require_all_props=False):
        value = super(PrimitiveTypeUnmarshaller,
                      self).__call__(value,
                                     type_format=type_format,
                                     strict=strict,
                                     require_all_props=require_all_props)

        try:
            schema_format = SchemaFormat(type_format)
        except ValueError:
            formatter = self.custom_formatters.get(type_format)
        else:
            formatters = self.get_formatters()
            formatter = formatters.get(schema_format)

        if formatter is None:
            raise InvalidSchemaValue(
                "Unsupported format {type} unmarshalling "
                "for value {value}", value, type_format)

        try:
            return formatter(value)
        except ValueError as exc:
            raise InvalidCustomFormatSchemaValue(
                "Failed to format value {value} to format {type}: {exception}",
                value, type_format, exc)
예제 #11
0
    def _unmarshal_object(self,
                          value,
                          model_factory=None,
                          custom_formatters=None):
        if not isinstance(value, (dict, )):
            raise InvalidSchemaValue("Value {value} is not of type {type}",
                                     value, self.type)

        model_factory = model_factory or ModelFactory()

        if self.one_of:
            properties = None
            for one_of_schema in self.one_of:
                try:
                    found_props = self._unmarshal_properties(
                        value,
                        one_of_schema,
                        custom_formatters=custom_formatters)
                except OpenAPISchemaError:
                    pass
                else:
                    if properties is not None:
                        raise MultipleOneOfSchema(self.type)
                    properties = found_props

            if properties is None:
                raise NoOneOfSchema(self.type)

        else:
            properties = self._unmarshal_properties(
                value, custom_formatters=custom_formatters)

        return model_factory.create(properties, name=self.model)
예제 #12
0
    def _unmarshal_object(self, value):
        if not isinstance(value, (dict, )):
            raise InvalidSchemaValue(
                "Value of {0} not an object".format(value))

        if self.one_of:
            properties = None
            for one_of_schema in self.one_of:
                try:
                    found_props = self._unmarshal_properties(
                        value, one_of_schema)
                except OpenAPISchemaError:
                    pass
                else:
                    if properties is not None:
                        raise MultipleOneOfSchema(
                            "Exactly one schema should be valid,"
                            "multiple found")
                    properties = found_props

            if properties is None:
                raise NoOneOfSchema(
                    "Exactly one valid schema should be valid, None found.")

        else:
            properties = self._unmarshal_properties(value)

        return ModelFactory().create(properties, name=self.model)
예제 #13
0
    def _unmarshal_object(self,
                          value,
                          model_factory=None,
                          custom_formatters=None,
                          strict=True):
        if not isinstance(value, (dict, )):
            raise InvalidSchemaValue("Value {value} is not of type {type}",
                                     value, self.type)

        model_factory = model_factory or ModelFactory()

        if self.one_of:
            properties = None
            for one_of_schema in self.one_of:
                try:
                    unmarshalled = self._unmarshal_properties(
                        value,
                        one_of_schema,
                        custom_formatters=custom_formatters)
                except OpenAPISchemaError:
                    pass
                else:
                    if properties is not None:
                        log.warning("multiple valid oneOf schemas found")
                        continue
                    properties = unmarshalled

            if properties is None:
                log.warning("valid oneOf schema not found")

        else:
            properties = self._unmarshal_properties(
                value, custom_formatters=custom_formatters)

        return model_factory.create(properties, name=self.model)
예제 #14
0
 def _unmarshal_string(self, value):
     formatter = self.FORMAT_CALLABLE_GETTER[self.format]
     try:
         return formatter(value)
     except ValueError:
         raise InvalidSchemaValue(
             "Failed to format value of {0} to {1}".format(
                 value, self.format))
예제 #15
0
    def unmarshal(self, value):
        """Unmarshal parameter from the value."""
        if self.deprecated:
            warnings.warn("The schema is deprecated", DeprecationWarning)
        if self.in_request_body and self.read_only:
            raise InvalidSchemaValue("Value is readonly!".format(value))
        casted = self.cast(value)

        if casted is None and not self.required:
            return None

        if self.enum and casted not in self.enum:
            raise InvalidSchemaValue(
                "Value of {0} not in enum choices: {1}".format(
                    value, self.enum))

        return casted
예제 #16
0
 def validate(self, value, resolver=None):
     validator = self.get_validator(resolver=resolver)
     try:
         return validator.validate(value)
     except ValidationError:
         # TODO: pass validation errors
         raise InvalidSchemaValue("Value not valid for schema", value,
                                  self.type)
예제 #17
0
 def validate(self, value, resolver=None):
     validator = self.get_validator(resolver=resolver)
     try:
         return validator.validate(value)
     except ValidationError:
         errors_iter = validator.iter_errors(value)
         raise InvalidSchemaValue(value,
                                  self.type,
                                  schema_errors_iter=errors_iter)
예제 #18
0
    def cast(self, value, custom_formatters=None):
        """Cast value to schema type"""
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema", value, self.type)
            return self.default

        cast_mapping = self.get_cast_mapping(custom_formatters=custom_formatters)

        if self.type is not SchemaType.STRING and value == '':
            return None

        cast_callable = cast_mapping[self.type]
        try:
            return cast_callable(value)
        except ValueError:
            raise InvalidSchemaValue(
                "Failed to cast value {value} to type {type}", value, self.type)
예제 #19
0
    def cast(self, value):
        """Cast value to schema type"""
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema")
            return self.default

        cast_mapping = self.get_cast_mapping()

        if self.type is not SchemaType.STRING and value == '':
            return None

        cast_callable = cast_mapping[self.type]
        try:
            return cast_callable(value)
        except ValueError:
            raise InvalidSchemaValue(
                "Failed to cast value of {0} to {1}".format(value, self.type))
예제 #20
0
    def validate(self, value, custom_formatters=None):
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema of type {type}", value, self.type)
            return

        # type validation
        type_validator_callable = self.TYPE_VALIDATOR_CALLABLE_GETTER[
            self.type]
        if not type_validator_callable(value):
            raise InvalidSchemaValue(
                "Value {value} not valid type {type}", value, self.type.value)

        # structure validation
        validator_mapping = self.get_validator_mapping()
        validator_callable = validator_mapping[self.type]
        validator_callable(value, custom_formatters=custom_formatters)

        return value
예제 #21
0
    def test_get_pets_invalid_response(self, spec, response_validator):
        host_url = 'http://petstore.swagger.io/v1'
        path_pattern = '/v1/pets'
        query_params = {
            'limit': '20',
        }

        request = MockRequest(
            host_url, 'GET', '/pets',
            path_pattern=path_pattern, args=query_params,
        )

        parameters = request.get_parameters(spec)
        body = request.get_body(spec)

        assert parameters == {
            'query': {
                'limit': 20,
                'page': 1,
                'search': '',
            }
        }
        assert body is None

        data_json = {
            'data': [
                {
                    'id': 1,
                    'name': {
                        'first_name': 'Cat',
                    },
                }
            ],
        }
        data = json.dumps(data_json)
        response = MockResponse(data)

        response_result = response_validator.validate(request, response)

        assert response_result.errors == [
            InvalidMediaTypeValue(
                original_exception=InvalidSchemaProperty(
                    property_name='data',
                    original_exception=InvalidSchemaProperty(
                        property_name='name',
                        original_exception=InvalidSchemaValue(
                            msg="Value {value} is not of type {type}",
                            type=SchemaType.STRING,
                            value={'first_name': 'Cat'},
                        ),
                    ),
                ),
            ),
        ]
        assert response_result.data is None
예제 #22
0
    def validate(self, value):
        if value is None:
            if not self.nullable:
                raise InvalidSchemaValue("Null value for non-nullable schema")
            return

        # type validation
        type_validator_callable = self.TYPE_VALIDATOR_CALLABLE_GETTER[
            self.type]
        if not type_validator_callable(value):
            raise InvalidSchemaValue(
                "Value of {0} not valid type of {1}".format(
                    value, self.type.value))

        # structure validation
        validator_mapping = self.get_validator_mapping()
        validator_callable = validator_mapping[self.type]
        validator_callable(value)

        return value
예제 #23
0
    def _unmarshal_string(self, value, custom_formatters=None):
        try:
            schema_format = SchemaFormat(self.format)
        except ValueError:
            msg = "Unsupported format {type} unmarshalling for value {value}"
            if custom_formatters is not None:
                formatstring = custom_formatters.get(self.format)
                if formatstring is None:
                    raise InvalidSchemaValue(msg, value, self.format)
            else:
                raise InvalidSchemaValue(msg, value, self.format)
        else:
            formatstring = self.STRING_FORMAT_CALLABLE_GETTER[schema_format]

        try:
            return formatstring.unmarshal(value)
        except ValueError as exc:
            raise InvalidCustomFormatSchemaValue(
                "Failed to format value {value} to format {type}: {exception}",
                value, self.format, exc)
예제 #24
0
    def _unmarshal_collection(self, value, custom_formatters=None, strict=True):
        if not isinstance(value, (list, tuple)):
            raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)

        if self.items is None:
            raise UndefinedItemsSchema(self.type)

        f = functools.partial(
            self.items.unmarshal,
            custom_formatters=custom_formatters, strict=strict,
        )
        return list(map(f, value))
예제 #25
0
    def _unmarshal_number(self, value, custom_formatters=None, strict=True):
        if strict and not isinstance(value, (float, ) + integer_types):
            raise InvalidSchemaValue("Value {value} is not of type {type}", value, self.type)

        try:
            schema_format = SchemaFormat(self.format)
        except ValueError:
            msg = "Unsupported format {type} unmarshalling for value {value}"
            if custom_formatters is not None:
                formatnumber = custom_formatters.get(self.format)
                if formatnumber is None:
                    raise InvalidSchemaValue(msg, value, self.format)
            else:
                raise InvalidSchemaValue(msg, value, self.format)
        else:
            formatnumber = self.NUMBER_FORMAT_CALLABLE_GETTER[schema_format]

        try:
            return formatnumber.unmarshal(value)
        except ValueError as exc:
            raise InvalidCustomFormatSchemaValue(
                "Failed to format value {value} to format {type}: {exception}", value, self.format, exc)
예제 #26
0
    def cast(self, value):
        """Cast value from string to schema type"""
        if value is None:
            return value

        cast_mapping = self.get_cast_mapping()

        cast_callable = cast_mapping[self.type]
        try:
            return cast_callable(value)
        except ValueError:
            raise InvalidSchemaValue(
                "Failed to cast value {value} to type {type}", value,
                self.type)
예제 #27
0
    def unmarshal(self, value, custom_formatters=None):
        """Unmarshal parameter from the value."""
        if self.deprecated:
            warnings.warn("The schema is deprecated", DeprecationWarning)

        casted = self.cast(value, custom_formatters=custom_formatters)

        if casted is None and not self.required:
            return None

        if self.enum and casted not in self.enum:
            raise InvalidSchemaValue(
                "Value {value} not in enum choices: {type}", value, self.enum)

        return casted
예제 #28
0
    def test_get_pets_invalid_response(self, spec, response_validator):
        host_url = 'http://petstore.swagger.io/v1'
        path_pattern = '/v1/pets'
        query_params = {
            'limit': '20',
        }

        request = MockRequest(
            host_url,
            'GET',
            '/pets',
            path_pattern=path_pattern,
            args=query_params,
        )

        parameters = validate_parameters(spec, request)
        body = validate_body(spec, request)

        assert parameters == RequestParameters(query={
            'limit': 20,
            'page': 1,
            'search': '',
        })
        assert body is None

        data_json = {
            'data': [{
                'id': 1,
                'name': {
                    'first_name': 'Cat',
                },
            }],
        }
        data = json.dumps(data_json)
        response = MockResponse(data)

        response_result = response_validator.validate(request, response)

        original_exc = response_result.errors[0].original_exception
        assert response_result.errors == [
            InvalidMediaTypeValue(original_exception=InvalidSchemaValue(
                type=SchemaType.OBJECT,
                value=data_json,
                schema_errors=original_exc.schema_errors,
                schema_errors_iter=original_exc._schema_errors_iter,
            ), ),
        ]
        assert response_result.data is None
예제 #29
0
    def _unmarshal_string(self, value):
        try:
            schema_format = SchemaFormat(self.format)
        except ValueError:
            # @todo: implement custom format unmarshalling support
            raise OpenAPISchemaError(
                "Unsupported {0} format unmarshalling".format(self.format))
        else:
            formatter = self.STRING_FORMAT_CAST_CALLABLE_GETTER[schema_format]

        try:
            return formatter(value)
        except ValueError:
            raise InvalidSchemaValue(
                "Failed to format value of {0} to {1}".format(
                    value, self.format))
예제 #30
0
    def _validate_string(self, value):
        try:
            schema_format = SchemaFormat(self.format)
        except ValueError:
            # @todo: implement custom format validation support
            raise OpenAPISchemaError(
                "Unsupported {0} format validation".format(self.format))
        else:
            format_validator_callable =\
                self.STRING_FORMAT_VALIDATOR_CALLABLE_GETTER[schema_format]

        if not format_validator_callable(value):
            raise InvalidSchemaValue(
                "Value of {0} not valid format of {1}".format(
                    value, self.format))

        return True