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
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
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
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
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
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
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
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
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
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
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, )