Example #1
0
def unmarshal_object(swagger_spec, object_spec, object_value):
    """Unmarshal a jsonschema type of 'object' into a python dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict
    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])

    result = {}
    for k, v in iteritems(object_value):
        prop_spec = get_spec_for_prop(swagger_spec, object_spec, object_value,
                                      k)
        if v is None and k not in required_fields and prop_spec:
            if schema.has_default(swagger_spec, prop_spec):
                result[k] = schema.get_default(swagger_spec, prop_spec)
            else:
                result[k] = None
        elif prop_spec:
            # Zohar: Ugly hack to fix handling of unicode type, which were recognized as objects
            if type(v) == type(u''):
                result[k] = unmarshal_primitive(swagger_spec, prop_spec, v)
            # elif type(v) == type(list()):
            #     result[k] = unmarshal_array(swagger_spec, prop_spec, v)
            else:
                result[k] = unmarshal_schema_object(swagger_spec, prop_spec, v)
        else:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v

    properties = collapsed_properties(deref(object_spec), swagger_spec)
    for prop_name, prop_spec in iteritems(properties):
        if prop_name not in result and swagger_spec.config[
                'include_missing_properties']:
            result[prop_name] = None
            if schema.has_default(swagger_spec, prop_spec):
                result[prop_name] = schema.get_default(swagger_spec, prop_spec)

    return result
Example #2
0
def marshal_primitive(swagger_spec, primitive_spec, value):
    """Marshal a python primitive type into a jsonschema primitive.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type primitive_spec: dict
    :type value: int, long, float, boolean, string, unicode, or an object
        based on 'format'

    :rtype: int, long, float, boolean, string, unicode, etc
    :raises: SwaggerMappingError
    """
    default_used = False

    if value is None and schema.has_default(swagger_spec, primitive_spec):
        default_used = True
        value = schema.get_default(swagger_spec, primitive_spec)

    if value is None and schema.is_required(swagger_spec, primitive_spec):
        raise SwaggerMappingError(
            'Spec {0} is a required value'.format(primitive_spec))

    if not default_used:
        value = formatter.to_wire(swagger_spec, primitive_spec, value)

    return value
Example #3
0
def marshal_primitive(swagger_spec, primitive_spec, value):
    """Marshal a python primitive type into a jsonschema primitive.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type primitive_spec: dict
    :type value: int, long, float, boolean, string, unicode, or an object
        based on 'format'

    :rtype: int, long, float, boolean, string, unicode, etc
    :raises: SwaggerMappingError
    """
    default_used = False

    if value is None and schema.has_default(swagger_spec, primitive_spec):
        default_used = True
        value = schema.get_default(swagger_spec, primitive_spec)

    if value is None and schema.is_required(swagger_spec, primitive_spec):
        raise SwaggerMappingError(
            'Spec {0} is a required value'.format(primitive_spec))

    if not default_used:
        value = formatter.to_wire(swagger_spec, primitive_spec, value)

    return value
Example #4
0
def unmarshal_param(param, request):
    """Unmarshal the given parameter from the passed in request like object.

    :type param: :class:`bravado_core.param.Param`
    :type request: :class:`bravado_core.request.IncomingRequest`
    :return: value of parameter
    """
    swagger_spec = param.swagger_spec
    deref = swagger_spec.deref
    param_spec = deref(get_param_type_spec(param))
    location = param.location
    param_type = deref(param_spec.get('type'))
    cast_param = partial(cast_request_param, param_type, param.name)

    default_value = schema.get_default(swagger_spec, param_spec)

    if location == 'path':
        raw_value = cast_param(request.path.get(param.name, None))
    elif location == 'query':
        raw_value = cast_param(request.query.get(param.name, default_value))
    elif location == 'header':
        raw_value = cast_param(request.headers.get(param.name, default_value))
    elif location == 'formData':
        if param_type == 'file':
            raw_value = request.files.get(param.name, None)
        else:
            raw_value = cast_param(request.form.get(param.name, default_value))
    elif location == 'body':
        try:
            # TODO: verify content-type header
            raw_value = request.json()
        except ValueError as json_error:
            # If the body parameter is required then we should make sure that an exception
            # is thrown, instead if the body parameter is optional is OK-ish to assume that
            # raw_value is the default_value
            if param.required:
                raise SwaggerMappingError(
                    "Error reading request body JSON: {0}".format(str(json_error)),
                )
            else:
                raw_value = default_value
    else:
        raise SwaggerMappingError(
            "Don't know how to unmarshal_param with location {0}".format(location),
        )

    if raw_value is None and not param.required:
        return None

    if param_type == 'array' and location != 'body':
        raw_value = unmarshal_collection_format(
            swagger_spec, param_spec,
            raw_value,
        )

    if swagger_spec.config['validate_requests']:
        validate_schema_object(swagger_spec, param_spec, raw_value)

    value = unmarshal_schema_object(swagger_spec, param_spec, raw_value)
    return value
Example #5
0
def unmarshal_object(swagger_spec, object_spec, object_value):
    """Unmarshal a jsonschema type of 'object' into a python dict.

    :type swagger_spec: :class:`bravado_core.spec.Spec`
    :type object_spec: dict
    :type object_value: dict
    :rtype: dict
    :raises: SwaggerMappingError
    """
    deref = swagger_spec.deref

    if object_value is None:
        return handle_null_value(swagger_spec, object_spec)

    if not is_dict_like(object_value):
        raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format(
            type(object_value), object_value))

    object_spec = deref(object_spec)
    required_fields = object_spec.get('required', [])
    properties = collapsed_properties(object_spec, swagger_spec)

    result = {}
    for k, v in iteritems(object_value):
        prop_spec = get_spec_for_prop(
            swagger_spec, object_spec, object_value, k, properties)
        if v is None and k not in required_fields and prop_spec:
            if schema.has_default(swagger_spec, prop_spec):
                result[k] = schema.get_default(swagger_spec, prop_spec)
            else:
                result[k] = None
        elif prop_spec:
            result[k] = unmarshal_schema_object(swagger_spec, prop_spec, v)
        else:
            # Don't marshal when a spec is not available - just pass through
            result[k] = v

    for prop_name, prop_spec in iteritems(properties):
        if prop_name not in result and swagger_spec.config['include_missing_properties']:
            result[prop_name] = None
            if schema.has_default(swagger_spec, prop_spec):
                result[prop_name] = schema.get_default(swagger_spec, prop_spec)

    return result
Example #6
0
def unmarshal_param(param, request):
    """Unmarshal the given parameter from the passed in request like object.

    :type param: :class:`bravado_core.param.Param`
    :type request: :class:`bravado_core.request.IncomingRequest`
    :return: value of parameter
    """
    swagger_spec = param.swagger_spec
    deref = swagger_spec.deref
    param_spec = deref(get_param_type_spec(param))
    location = param.location
    param_type = deref(param_spec.get('type'))
    cast_param = partial(cast_request_param, param_type, param.name)

    default_value = schema.get_default(swagger_spec, param_spec)

    if location == 'path':
        raw_value = cast_param(request.path.get(param.name, None))
    elif location == 'query':
        raw_value = cast_param(request.query.get(param.name, default_value))
    elif location == 'header':
        raw_value = cast_param(request.headers.get(param.name, default_value))
    elif location == 'formData':
        if param_type == 'file':
            raw_value = request.files.get(param.name, None)
        else:
            raw_value = cast_param(request.form.get(param.name, default_value))
    elif location == 'body':
        # TODO: verify content-type header
        try:
            raw_value = request.json()
        except ValueError as json_error:
            raise SwaggerMappingError("Error reading request body JSON: {0}".
                                      format(str(json_error)))
    else:
        raise SwaggerMappingError(
            "Don't know how to unmarshal_param with location {0}".
            format(location))

    if raw_value is None and not schema.is_required(swagger_spec, param_spec):
        return None

    if param_type == 'array' and location != 'body':
        raw_value = unmarshal_collection_format(swagger_spec, param_spec,
                                                raw_value)

    if swagger_spec.config['validate_requests']:
        validate_schema_object(swagger_spec, param_spec, raw_value)

    value = unmarshal_schema_object(swagger_spec, param_spec, raw_value)
    return value
Example #7
0
async def unmarshal_param(param, request):
    """Unmarshal the given parameter from the passed in request like object.

    :type param: :class:`bravado_core.param.Param`
    :type request: :class:`bravado_core.request.IncomingRequest`
    :return: value of parameter
    """
    swagger_spec = param.swagger_spec
    deref = swagger_spec.deref
    param_spec = deref(get_param_type_spec(param))
    location = param.location
    param_type = deref(param_spec.get('type'))
    cast_param = partial(cast_request_param, param_type, param.name)

    default_value = schema.get_default(swagger_spec, param_spec)

    if location == Location.path:
        raw_value = cast_param(request.match_info.get(param.name, None))
    elif location == Location.query:
        raw_value = cast_param(request.query.get(param.name, default_value))
    elif location == Location.header:
        raw_value = cast_param(request.headers.get(param.name, default_value))
    elif location == Location.form_data:
        if param_type == 'file':
            raw_value = request.files.get(param.name, None)
        else:
            raw_value = cast_param(request.form.get(param.name, default_value))
    elif location == Location.body:
        # TODO: verify content-type header
        try:
            raw_value = request.json()
        except ValueError as json_error:
            raise SwaggerMappingError(
                "Error reading request body JSON: {0}".format(str(json_error)))
    else:
        raise SwaggerMappingError(
            "Don't know how to unmarshal_param with location {0}".format(
                location))

    if raw_value is None and not schema.is_required(swagger_spec, param_spec):
        return None

    if param_type == 'array' and location != Location.body:
        raw_value = unmarshal_collection_format(swagger_spec, param_spec,
                                                raw_value)

    if swagger_spec.config['validate_requests']:
        validate_schema_object(swagger_spec, param_spec, raw_value)

    value = unmarshal_schema_object(swagger_spec, param_spec, raw_value)
    return value
Example #8
0
def handle_null_value(swagger_spec,
                      object_schema,
                      is_nullable=False,
                      is_marshaling_operation=False):
    # type: (Spec, JSONDict, bool, bool) -> typing.Callable[[FuncType], FuncType]
    # TODO: remove is_nullable support once https://github.com/Yelp/bravado-core/issues/335 is addressed
    """
    Function wrapper that performs some check to the wrapped function parameter.

    In case the parameter is None the decorator ensures that, according to object schema,
    the default value is used or that the null value is properly handled.

    NOTES:
     * the decorator is meant to be used in bravado_core.marshal and bravado_core.unmarshal modules.
     * the decorator could be used as wrapper of functions that accept a single value as parameter.
       Such value will be used for the checks mentioned above
     * nullable parameter is needed to ensure that x-nullable is propagated in the case it is defined
       as sibling in a reference object (ie. `{'x-nullable': True, '$ref': '#/definitions/something'}`)

    """
    default_value = schema.get_default(swagger_spec, object_schema)
    is_nullable = is_nullable or schema.is_prop_nullable(
        swagger_spec, object_schema)

    def external_wrapper(func):
        # type: (FuncType) -> FuncType
        @wraps(func)
        def wrapper(value):
            # type: (typing.Any) -> typing.Any
            if value is None:
                value = default_value

                if value is None:
                    if is_nullable:
                        return None
                    else:
                        raise SwaggerMappingError(
                            'Spec {0} is a required value'.format(
                                object_schema), )
                elif is_marshaling_operation:
                    return value
            return func(value)

        return wrapper

    return external_wrapper
Example #9
0
def unmarshal_param(param, request):
    """Unmarshal the given parameter from the passed in request like object.

    :type param: :class:`bravado_core.param.Param`
    :type request: :class:`bravado_core.request.IncomingRequest`
    :return: value of parameter
    """
    swagger_spec = param.swagger_spec
    deref = swagger_spec.deref
    param_spec = deref(get_param_type_spec(param))
    location = param.location
    param_type = deref(param_spec.get('type'))
    cast_param = partial(cast_request_param, param_type, param.name)

    default_value = schema.get_default(swagger_spec, param_spec)

    if location == 'path':
        raw_value = cast_param(request.path.get(param.name, None))
    elif location == 'query':
        raw_value = cast_param(request.query.get(param.name, default_value))
    elif location == 'header':
        raw_value = cast_param(request.headers.get(param.name, default_value))
    elif location == 'formData':
        if param_type == 'file':
            raw_value = request.files.get(param.name, None)
        else:
            raw_value = cast_param(request.form.get(param.name, default_value))
    elif location == 'body':
        # TODO: verify content-type header
        raw_value = request.json()
    else:
        raise SwaggerMappingError(
            "Don't know how to unmarshal_param with location {0}".format(
                location))

    if param_type == 'array' and location != 'body':
        raw_value = unmarshal_collection_format(swagger_spec, param_spec,
                                                raw_value)

    if swagger_spec.config['validate_requests']:
        validate_schema_object(swagger_spec, param_spec, raw_value)

    value = unmarshal_schema_object(swagger_spec, param_spec, raw_value)
    return value
Example #10
0
def unmarshal_param(param, request):
    """Unmarshal the given parameter from the passed in request like object.

    :type param: :class:`bravado_core.param.Param`
    :type request: :class:`bravado_core.request.IncomingRequest`
    """
    param_spec = get_param_type_spec(param)
    location = param.location
    cast_param = partial(cast_request_param, param_spec['type'], param.name)

    default_value = schema.get_default(param_spec)

    if location == 'path':
        raw_value = cast_param(request.path.get(param.name, None))
    elif location == 'query':
        raw_value = cast_param(request.query.get(param.name, default_value))
    elif location == 'header':
        raw_value = cast_param(request.headers.get(param.name, default_value))
    elif location == 'formData':
        if param_spec['type'] == 'file':
            raw_value = request.files.get(param.name, None)
        else:
            raw_value = cast_param(request.form.get(param.name, default_value))
    elif location == 'body':
        # TODO: verify content-type header
        raw_value = request.json()
    else:
        raise SwaggerMappingError(
            "Don't know how to unmarshal_param with location {0}".
            format(location))

    if param_spec['type'] == 'array' and location != 'body':
        raw_value = unmarshal_collection_format(param_spec, raw_value)

    if param.swagger_spec.config['validate_requests']:
        validate_schema_object(param.swagger_spec, param_spec, raw_value)

    value = unmarshal_schema_object(param.swagger_spec, param_spec, raw_value)
    return value
Example #11
0
def marshal_primitive(spec, value):
    """Marshal a python primitive type into a jsonschema primitive.

    :type spec: dict or jsonref.JsonRef
    :type value: int, long, float, boolean, string, unicode, or an object
        based on 'format'
    :rtype: int, long, float, boolean, string, unicode, etc
    :raises: TypeError
    """
    default_used = False

    if value is None and schema.has_default(spec):
        default_used = True
        value = schema.get_default(spec)

    if value is None and schema.is_required(spec):
        raise TypeError('Spec {0} is a required value'.format(spec))

    if not default_used:
        value = formatter.to_wire(spec, value)

    return value
Example #12
0
def _unmarshaling_method_object(swagger_spec, object_schema, use_models=True):
    # type: (Spec, JSONDict, bool) -> UnmarshalingMethod
    """
    Determine the unmarshaling method needed for a schema of a type object.

    The method will be responsible for the identification of:
     * required, nullable and default value for the all properties
     * unmarshaling methods of all the properties
     * unmarshaling method of the eventual additional properties
     * polymorphic nature of the object (`discriminator` attribute) and list of the associated models

    :param swagger_spec: Spec object
    :param object_schema: Schema of the object type
    # TODO: use_models parameter should be removed once unmarshal_model function is removed
    :param use_models: Flag that enables or disables the usage of Models
    """

    model_type = None  # type: typing.Optional[typing.Type[Model]]
    object_schema = swagger_spec.deref(object_schema)
    if MODEL_MARKER in object_schema:
        model_name = object_schema[MODEL_MARKER]
        model_type = swagger_spec.definitions.get(model_name)
        if use_models and model_type is None:
            return partial(
                _raise_unknown_model,
                model_name,
            )
        if not use_models:
            model_type = None

    properties = collapsed_properties(object_schema, swagger_spec)
    required_properties = object_schema.get('required', [])
    properties_to_unmarshaling_function = {
        prop_name: _get_unmarshaling_method(
            swagger_spec=swagger_spec,
            object_schema=prop_schema,
            is_nullable=prop_schema.get('x-nullable', False)
            or prop_name not in required_properties,
        )
        for prop_name, prop_schema in iteritems(properties)
    }

    additional_properties_unmarshaling_function = _no_op_unmarshaling
    if object_schema.get('additionalProperties') is not False:
        additional_properties_schema = object_schema.get(
            'additionalProperties', {})
        if additional_properties_schema not in ({}, True):
            additional_properties_unmarshaling_function = _get_unmarshaling_method(
                swagger_spec=swagger_spec,
                object_schema=additional_properties_schema,
                is_nullable=False,
            )

    properties_to_default_value = {
        prop_name: unmarshal_schema_object(
            swagger_spec=swagger_spec,
            schema_object_spec=prop_schema,
            value=schema.get_default(swagger_spec, prop_schema),
        )
        for prop_name, prop_schema in iteritems(properties)
        if schema.has_default(swagger_spec, prop_schema)
    }

    discriminator_property = object_schema.get('discriminator')
    possible_discriminated_type_name_to_model = {}
    if model_type and object_schema.get('discriminator'):
        possible_discriminated_type_name_to_model.update({
            k: v
            for k, v in iteritems(swagger_spec.definitions)
            if model_type and model_type.__name__ in v._inherits_from
        })

    return partial(
        _unmarshal_object,
        swagger_spec,
        model_type
        if model_type and swagger_spec.config['use_models'] else dict,
        properties_to_unmarshaling_function,
        additional_properties_unmarshaling_function,
        properties_to_default_value,
        discriminator_property,
        possible_discriminated_type_name_to_model,
    )