def print_spec(spec, level=0): indent = '\t' * level if is_dict_like(spec): for k, v in spec.items(): print(indent + k + ':') if is_dict_like(v): print('{') print_spec(v, level + 1) print(indent + '}') elif is_list_like(v): print(' [') print_spec(v, level + 1) print(indent + ']') else: print(str(v) + ', ') elif is_list_like(spec): for element in spec: if is_list_like(element): print(' [') print_spec(element, level + 1) print(indent + ']') elif is_dict_like(element): print(indent + '{') print_spec(element, level + 1) print(indent + '},') else: print_spec(element, level + 1) else: print(indent + str(spec) + ', ')
def print_spec(spec, level=0): indent = '\t' * level if is_dict_like(spec): for k, v in spec.iteritems(): print indent + k + ':', if is_dict_like(v): print '{' print_spec(v, level + 1) print indent + '}' elif is_list_like(v): print ' [' print_spec(v, level + 1) print indent + ']' else: print str(v) + ', ' elif is_list_like(spec): for element in spec: if is_list_like(element): print ' [' print_spec(element, level + 1) print indent + ']' elif is_dict_like(element): print indent + '{' print_spec(element, level + 1) print indent + '},' else: print_spec(element, level + 1) else: print indent + str(spec) + ', '
def _equivalent(spec, obj1, obj2): # type: (Spec, Any, Any) -> bool if is_dict_like(obj1) != is_dict_like(obj2) or is_list_like( obj1) != is_list_like(obj2): return False if is_dict_like(obj1): if len(obj1) != len(obj2): return False for key in iterkeys(obj1): if key not in obj2: return False if not _equivalent(spec, spec._force_deref(obj1[key]), spec._force_deref(obj2[key])): return False return True elif is_list_like(obj1): if len(obj1) != len(obj2): return False for key in range(len(obj1)): if not _equivalent(spec, spec._force_deref(obj1[key]), spec._force_deref(obj2[key])): return False return True else: return obj1 == obj2
def _bless_models(container, json_reference, visited_models, swagger_spec): """ Callback used during the swagger spec ingestion process to add ``x-model`` attribute to models which does not define it. The callbacks is in charge of adding MODEL_MARKER in case a model (identifies as an object of type SCHEMA) has enough information for determining a model name (ie. has ``title`` attribute defined) INFO: Implementation detail. Respect ``collect_models`` this callback gets executed on the model_spec's parent container. This is needed because this callback could modify (adding MODEL_MARKER) the model_spec; performing this operation when the container represents model_spec will generate errors because we're iterating over an object that gets mutated by the callback. :param container: container being visited :param json_reference: URI of the current container :type json_reference: str :type visited_models: dict (k,v) == (model_name, path) :type swagger_spec: :class:`bravado_core.spec.Spec` """ if not is_dict_like(container): return key = json_reference.split('/')[-1] deref = swagger_spec.deref model_spec = deref(container.get(key)) if ( not is_dict_like(model_spec) or not is_object(swagger_spec, model_spec, no_default_type=True) or # NOTE: determine_object_type uses a simple heuristic to determine if a model_spec has a SCHEMA type # for this reason is important that model_spec is recognized as model in the most accurate way # so we should not rely on default typing of a schema determine_object_type(model_spec) != ObjectType.SCHEMA or deref(model_spec.get(MODEL_MARKER)) is not None ): return model_name = _get_model_name(model_spec) if not model_name: return _register_visited_model( json_reference=json_reference, model_spec=model_spec, model_name=model_name, visited_models=visited_models, is_blessed=True, swagger_spec=swagger_spec, )
def marshal_object(swagger_spec, object_spec, object_value): """Marshal a jsonschema type of 'object' into a json-like dict. :type swagger_spec: :class:`bravado_core.spec.Spec` :type object_spec: dict or jsonref.JsonRef :type object_value: dict :rtype: dict :raises: SwaggerMappingError """ if not is_dict_like(object_value): raise TypeError('Expected dict like type for {0}:{1}'.format( type(object_value), object_value)) result = {} for k, v in object_value.iteritems(): # Values cannot be None - skip them entirely! if v is None: continue prop_spec = get_spec_for_prop(object_spec, object_value, k) if prop_spec: result[k] = marshal_schema_object(swagger_spec, prop_spec, v) else: # Don't marshal when a spec is not available - just pass through result[k] = v return result
def marshal_object(swagger_spec, object_spec, object_value): """Marshal a jsonschema type of 'object' into a json-like dict. :type swagger_spec: :class:`bravado_core.spec.Spec` :type object_spec: dict or jsonref.JsonRef :type object_value: dict :rtype: dict :raises: SwaggerMappingError """ if not is_dict_like(object_value): raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format( type(object_value), object_value)) result = {} for k, v in iteritems(object_value): # Values cannot be None - skip them entirely! if v is None: continue prop_spec = get_spec_for_prop(object_spec, object_value, k) if prop_spec: result[k] = marshal_schema_object(swagger_spec, prop_spec, v) else: # Don't marshal when a spec is not available - just pass through result[k] = v return result
def unmarshal_model(swagger_spec, model_spec, model_value): """Unmarshal a dict into a Model instance. :type swagger_spec: :class:`bravado_core.spec.Spec` :type model_spec: dict :type model_value: dict :rtype: Model instance :raises: SwaggerMappingError """ deref = swagger_spec.deref model_name = deref(model_spec).get(MODEL_MARKER) model_type = swagger_spec.definitions.get(model_name, None) if model_type is None: raise SwaggerMappingError( 'Unknown model {0} when trying to unmarshal {1}'.format( model_name, model_value)) if not is_dict_like(model_value): raise SwaggerMappingError( "Expected type to be dict for value {0} to unmarshal to a {1}." "Was {1} instead.".format(model_value, model_type, type(model_value))) model_as_dict = unmarshal_object(swagger_spec, model_spec, model_value) model_instance = model_type(**model_as_dict) return model_instance
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 not is_dict_like(object_value): raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format( type(object_value), object_value)) result = {} for k, v in iteritems(object_value): prop_spec = get_spec_for_prop(swagger_spec, object_spec, object_value, k) if 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 # re-introduce and None'ify any properties that weren't passed properties = deref(object_spec).get('properties', {}) for prop_name, prop_spec in iteritems(properties): if prop_name not in result: result[prop_name] = None return result
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 not is_dict_like(object_value): # This is the workaround for Alert Profile API tests, measureParam is # defined as 'object', which will raise exception here. return # raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format( # type(object_value), object_value)) result = {} for k, v in iteritems(object_value): prop_spec = get_spec_for_prop( swagger_spec, object_spec, object_value, k) if 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 # re-introduce and None'ify any properties that weren't passed properties = deref(object_spec).get('properties', {}) for prop_name, prop_spec in iteritems(properties): if prop_name not in result: result[prop_name] = None return result
def _set_references_to_models_descend(value, json_ref): if is_dict_like(value): if ( MODEL_MARKER in value and not re.match('^#/definitions/[^/]+$', json_ref) and value == flattened_spec_dict.get('definitions', {}).get(value[MODEL_MARKER]) ): return { '$ref': '#/definitions/{model_name}'.format(model_name=value[MODEL_MARKER]) } else: return { key: _set_references_to_models_descend(value=subval, json_ref='{}/{}'.format(json_ref, key)) for key, subval in iteritems(value) } elif is_list_like(value): return [ _set_references_to_models_descend(value=subval, json_ref='{}/{}'.format(json_ref, index)) for index, subval in enumerate(value) ] else: return value
def descend(fragment, path, visited_refs): if is_ref(fragment): ref_dict = fragment ref = fragment['$ref'] attach_scope(ref_dict, resolver) # Don't recurse down already visited refs. A ref is not unique # by its name alone. Its scope (attached above) is part of the # equivalence comparison. if ref_dict in visited_refs: log.debug('Already visited %s' % ref) return visited_refs.append(ref_dict) with resolver.resolving(ref) as target: descend(target, path, visited_refs) return # fragment is guaranteed not to be a ref from this point onwards if is_dict_like(fragment): if 'type' not in fragment: if 'properties' in fragment: fragment['type'] = 'object' elif 'items' in fragment: fragment['type'] = 'array' for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)
def determine_object_type(object_dict, default_type_to_object=None): """ Use best guess to determine the object type based on the object keys. NOTE: it assumes that the base swagger specs are validated and perform type detection for the four types of object that could be references in the specs: parameter, path item, response and schema. :type object_dict: dict :default_type_to_object: Default object type attribute to object if missing (as from bravado_core.spec.Spec config) :type default_type_to_object: bool :return: determined type of ``object_dict``. The return values is an ObjectType :rtype: ObjectType """ if not is_dict_like(object_dict): return ObjectType.UNKNOWN if 'in' in object_dict and 'name' in object_dict: # A parameter object is the only object type that could contain 'in' and 'name' at the same time return ObjectType.PARAMETER else: http_operations = { 'get', 'put', 'post', 'delete', 'options', 'head', 'patch' } # A path item object MUST have defined at least one http operation and could optionally have 'parameter' # attribute. NOTE: patterned fields (``^x-``) are acceptable in path item objects object_keys = { key for key in iterkeys(object_dict) if not key.startswith('x-') } if object_keys.intersection(http_operations): remaining_keys = object_keys.difference(http_operations) if not remaining_keys or remaining_keys == {'parameters'}: return ObjectType.PATH_ITEM else: # A response object has: # - mandatory description field # - optional schema, headers and examples field # - no other fields are allowed response_allowed_keys = { 'description', 'schema', 'headers', 'examples' } # If description field is specified and there are no other fields other the allowed response fields if 'description' in object_keys and not bool( object_keys - response_allowed_keys): return ObjectType.RESPONSE else: # A schema object has: # - no mandatory parameters # - long list of optional parameters (ie. description, type, items, properties, discriminator, etc.) # - no other fields are allowed # NOTE: In case the method is mis-determining the type of a schema object, confusing it with a # response type it will be enough to add, to the object, one key that is not defined # in ``response_allowed_keys``. (ie. ``additionalProperties: {}``, implicitly defined be specs) if default_type_to_object or 'type' in object_dict: return ObjectType.SCHEMA else: return ObjectType.UNKNOWN
def _unmarshal_object( swagger_spec, # type: Spec model_type, # type: typing.Union[typing.Type[JSONDict], typing.Type[Model]] properties_to_unmarshaling_function, # type: typing.Dict[typing.Text, UnmarshalingMethod] additional_properties_unmarshaling_function, # type: UnmarshalingMethod properties_to_default_value, # type: JSONDict discriminator_property, # type: typing.Optional[typing.Text] possible_discriminated_type_name_to_model, # type: typing.Dict[typing.Text, Model] model_value, # type: typing.Any ): # type: (...) -> typing.Any """ Unmarshal a dict into a Model instance or a dictionary (according to the 'use_models' swagger_spec configuration). :param swagger_spec: Spec object :param model_type: Type of the return value (:class:`dict` or a subclass of :class:`bravado_core.model.Model`) :param properties_to_unmarshaling_function: Mapping between property name and associated unmarshaling method :param additional_properties_unmarshaling_function: Unmarshaling function of eventual additional properties :param properties_to_default_value: Mapping between property name and the associated unmarshaled default value :param discriminator_property: Discriminator property name. It will be `None` if the schema is not a polymorphic schema :param possible_discriminated_type_name_to_model: Mapping of the possible dereferenced Model names and Model instances. :param model_value: JSON value to unmarshal :raises: SwaggerMappingError """ if not is_dict_like(model_value): raise SwaggerMappingError( "Expected type to be dict for value {0} to unmarshal to a {1}." "Was {2} instead.".format(model_value, model_type, type(model_value)), ) if discriminator_property: discriminator_value = model_value[discriminator_property] discriminated_model = possible_discriminated_type_name_to_model.get( discriminator_value) if discriminated_model is not None: unmarshal_func = _get_unmarshaling_method( swagger_spec=swagger_spec, object_schema=discriminated_model._model_spec, ) return unmarshal_func(model_value) unmarshaled_value = model_type() for property_name, property_value in iteritems(model_value): unmarshaling_function = properties_to_unmarshaling_function.get( property_name, additional_properties_unmarshaling_function, ) unmarshaled_value[property_name] = unmarshaling_function( property_value) if swagger_spec.config['include_missing_properties']: for property_name, unmarshaling_function in iteritems( properties_to_unmarshaling_function): if property_name not in unmarshaled_value: unmarshaled_value[ property_name] = properties_to_default_value.get( property_name) return unmarshaled_value
def unmarshal_model(swagger_spec, model_spec, model_value): """Unmarshal a dict into a Model instance. :type swagger_spec: :class:`bravado_core.spec.Spec` :type model_spec: dict or jsonref.JsonRef :type model_value: dict :rtype: Model instance :raises: SwaggerMappingError """ model_name = model_spec[MODEL_MARKER] model_type = swagger_spec.definitions.get(model_name, None) if model_type is None: raise SwaggerMappingError( 'Unknown model {0} when trying to unmarshal {1}' .format(model_name, model_value)) if not is_dict_like(model_value): raise SwaggerMappingError( "Expected type to be dict for value {0} to unmarshal to a {1}." "Was {1} instead." .format(model_value, model_type, type(model_value))) model_as_dict = unmarshal_object(swagger_spec, model_spec, model_value) model_instance = model_type(**model_as_dict) return model_instance
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 or jsonref.JsonRef :type object_value: dict :rtype: dict :raises: SwaggerMappingError """ if not is_dict_like(object_value): raise SwaggerMappingError('Expected dict like type for {0}:{1}'.format( type(object_value), object_value)) result = {} for k, v in iteritems(object_value): prop_spec = get_spec_for_prop(object_spec, object_value, k) if 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 # re-introduce and None'ify any properties that weren't passed for prop_name, prop_spec in iteritems(object_spec.get('properties', {})): if prop_name not in result: result[prop_name] = None return result
def descend(fragment, path, visited_refs): if is_ref(fragment): ref_dict = fragment ref = fragment['$ref'] attach_scope(ref_dict, resolver) # Don't recurse down already visited refs. A ref is not unique # by its name alone. Its scope (attached above) is part of the # equivalence comparison. if ref_dict in visited_refs: log.debug('Already visited %s' % ref) return visited_refs.append(ref_dict) with resolver.resolving(ref) as target: descend(target, path, visited_refs) return # fragment is guaranteed not to be a ref from this point onwards if is_dict_like(fragment): for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)
def marshal_object(swagger_spec, object_spec, object_value): """Marshal a python dict to json 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 not is_dict_like(object_value): raise SwaggerMappingError("Expected dict like type for {0}:{1}".format(type(object_value), object_value)) result = {} for k, v in iteritems(object_value): # Values cannot be None - skip them entirely! if v is None: continue prop_spec = get_spec_for_prop(swagger_spec, deref(object_spec), object_value, k) if prop_spec: result[k] = marshal_schema_object(swagger_spec, prop_spec, v) else: # Don't marshal when a spec is not available - just pass through result[k] = v return result
def _marshal_object( swagger_spec, # type: Spec properties_to_marshaling_function, # type: typing.Dict[typing.Text, MarshalingMethod] additional_properties_marshaling_function, # type: MarshalingMethod discriminator_property, # type: typing.Optional[typing.Text] possible_discriminated_type_name_to_model, # type: typing.Dict[typing.Text, Model] required_properties, # type: typing.Set[typing.Text] nullable_properties, # type: typing.Set[typing.Text] model_value, # type: typing.Any ): # type: (...) -> typing.Any """ Marshal a dict or Model instance into its JSON Object representation. :param swagger_spec: Spec object :param properties_to_marshaling_function: Mapping between property name and associated unmarshaling method :param additional_properties_marshaling_function: Unmarshaling function of eventual additional properties :param discriminator_property: Discriminator property name. It will be `None` if the schema is not a polymorphic schema :param possible_discriminated_type_name_to_model: Mapping of the possible dereferenced Model names and Model instances. :param required_properties: Set of required properties of the object schema :param nullable_properties: Set of nullable properties of the object schema :param model_value: Python dictionary or Model to marshal as JSON Object :raises: SwaggerMappingError """ if not is_dict_like(model_value) and not isinstance(model_value, Model): raise SwaggerMappingError( "Expected type to be dict or Model to marshal value '{0}' to a dict. Was {1} instead." .format( model_value, type(model_value), ), ) if discriminator_property: discriminator_value = model_value[discriminator_property] discriminated_model = possible_discriminated_type_name_to_model.get( discriminator_value) if discriminated_model is not None: marshaling_function = _get_marshaling_method( swagger_spec=swagger_spec, object_schema=discriminated_model._model_spec) return marshaling_function(model_value) marshaled_value = dict() for property_name in model_value: property_value = model_value[property_name] property_marshaling_function = properties_to_marshaling_function.get( property_name, additional_properties_marshaling_function, ) if (property_value is None and property_name not in required_properties and property_name not in nullable_properties and property_name in properties_to_marshaling_function): continue marshaled_value[property_name] = property_marshaling_function( property_value) return marshaled_value
def descend(fragment): if is_dict_like(fragment): fragment.pop('x-model', None) # Removes 'x-model' key if present for key in iterkeys(fragment): descend(fragment[key]) elif is_list_like(fragment): for element in fragment: descend(element)
def descend(fragment): if is_dict_like(fragment): for key in fragment: fire_callbacks(fragment, key) descend(fragment[key]) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index) descend(fragment[index])
def descend(fragment): # type: (typing.Any) -> None if is_dict_like(fragment): fragment.pop('x-scope', None) # Removes 'x-scope' key if present for key in iterkeys(fragment): descend(fragment[key]) elif is_list_like(fragment): for element in fragment: descend(element)
def descend(fragment): if is_dict_like(fragment): for k, v in iteritems(fragment): if k == '$ref' and v in model_names: fragment[k] = "#/definitions/{0}".format(v) descend(v) elif is_list_like(fragment): for element in fragment: descend(element)
def descend(fragment): if is_dict_like(fragment): for k, v in fragment.items(): if isinstance(v, jsonref.JsonRef): fragment[k] = v.__subject__ descend(fragment[k]) elif is_list_like(fragment): for element in fragment: descend(element)
def rename_definition_references(self, flattened_spec_dict): """ Rename definition references to more "human" names if possible. The used approach is to use model-name as definition key, if this does not conflict with an already existing key. :param flattened_spec_dict: swagger spec dict (pre-flattened) :return: swagger spec dict equivalent to flattened_spec_dict with more human references :rtype: dict """ def _rename_references_descend(value): if is_ref(value): return { '$ref': reference_renaming_mapping.get(value['$ref'], value['$ref']) } elif is_dict_like(value): return { key: _rename_references_descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ _rename_references_descend(value=subval) for index, subval in enumerate(value) ] else: return value definition_key_to_model_name_mapping = { k: v[MODEL_MARKER] for k, v in iteritems(flattened_spec_dict.get('definitions', {})) if is_dict_like(v) and MODEL_MARKER in v } original_definition_keys = set(iterkeys(flattened_spec_dict.get('definitions', {}))) new_definition_keys = set(itervalues(definition_key_to_model_name_mapping)) # Ensure that the new definition keys are not overlapping with already existing ones # if this happens the new definition key needs be kept untouched reference_renaming_mapping = { # old-reference -> new-reference '#/definitions/{}'.format(k): '#/definitions/{}'.format(v) for k, v in iteritems(definition_key_to_model_name_mapping) if v in new_definition_keys and v not in original_definition_keys } for old_reference, new_reference in iteritems(reference_renaming_mapping): new_ref = new_reference.replace('#/definitions/', '') old_ref = old_reference.replace('#/definitions/', '') flattened_spec_dict['definitions'][new_ref] = flattened_spec_dict['definitions'][old_ref] del flattened_spec_dict['definitions'][old_ref] return _rename_references_descend(flattened_spec_dict)
def descend(fragment): if is_dict_like(fragment): for key in list(fragment.keys()): if key == 'x-scope': del fragment['x-scope'] else: descend(fragment[key]) elif is_list_like(fragment): for element in fragment: descend(element)
def descend(fragment): if is_dict_like(fragment): for k, v in iteritems(fragment): if isinstance(v, jsonref.JsonRef): fragment[k] = v.__subject__ descend(fragment[k]) elif is_list_like(fragment): for index, element in enumerate(fragment): if isinstance(element, jsonref.JsonRef): fragment[index] = element.__subject__ descend(element)
def _equivalent(spec, obj1, obj2): if is_dict_like(obj1) != is_dict_like(obj2) or is_list_like(obj1) != is_list_like(obj2): return False if is_dict_like(obj1): if len(obj1) != len(obj2): return False for key in iterkeys(obj1): if key not in obj2: return False return _equivalent(spec, spec._force_deref(obj1[key]), spec._force_deref(obj2[key])) elif is_list_like(obj1): if len(obj1) != len(obj2): return False for key in range(len(obj1)): return _equivalent(spec, spec._force_deref(obj1[key]), spec._force_deref(obj2[key])) else: return obj1 == obj2
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_schema_object(swagger_spec, schema_object_spec, value): """Marshal the value using the given schema object specification. Marshaling includes: - transform the value according to 'format' if available - return the value in a form suitable for 'on-the-wire' transmission :type swagger_spec: :class:`bravado_core.spec.Spec` :type schema_object_spec: dict :type value: int, long, string, unicode, boolean, list, dict, Model type :return: marshaled value :rtype: int, long, string, unicode, boolean, list, dict :raises: SwaggerMappingError """ deref = swagger_spec.deref schema_object_spec = deref(schema_object_spec) obj_type = schema_object_spec['type'] if 'int' in str(type(value)) and obj_type == 'string': schema_object_spec['type'] = 'integer' if obj_type in SWAGGER_PRIMITIVES: return marshal_primitive(swagger_spec, schema_object_spec, value) if obj_type == 'array': return marshal_array(swagger_spec, schema_object_spec, value) if is_model(swagger_spec, schema_object_spec): # Allow models to be passed in as dicts for flexibility. if is_dict_like(value): return marshal_object(swagger_spec, schema_object_spec, value) # It is important that the 'model' check comes before 'object' check # below. Model specs are of type 'object' but also have a MODEL_MARKER # key for identification. return marshal_model(swagger_spec, schema_object_spec, value) if obj_type == 'object': return marshal_object(swagger_spec, schema_object_spec, value) if obj_type == 'file': return value raise SwaggerMappingError('Unknown type {0} for value {1}'.format( obj_type, value))
def descend(fragment, path=None, visited_refs=None): """ :param fragment: node in spec_dict :param path: list of strings that form the current path to fragment :param visited_refs: list of visted ref_dict """ path = path or [] visited_refs = visited_refs or [] if is_dict_like(fragment): for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)
def descend(obj): # Inline modification of obj # This method is needed because JsonRef could produce performance penalties in accessing # the proxied attributes if isinstance(obj, JsonRef): # Extract the proxied value # http://jsonref.readthedocs.io/en/latest/#jsonref.JsonRef.__subject__ return obj.__subject__ if is_dict_like(obj): for key in list(iterkeys(obj)): obj[key] = descend(obj[key]) elif is_list_like(obj): # obj is list like object provided from flattened_spec specs. # This guarantees that it cannot be a tuple instance and # inline object modification are allowed for index in range(len(obj)): obj[index] = descend(obj[index]) return obj
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 descend(self, value): if is_ref(value): # Update spec_resolver scope to be able to dereference relative specs from a not root file with in_scope(self.spec_resolver, value): uri, deref_value = self.resolve(value['$ref']) object_type = determine_object_type( object_dict=deref_value, default_type_to_object=self.default_type_to_object, ) known_mapping_key = object_type.get_root_holder() if known_mapping_key is None: return self.descend(value=deref_value) else: uri = urlparse(uri) if uri not in self.known_mappings.get( known_mapping_key, {}): # The placeholder is present to interrupt the recursion # during the recursive traverse of the data model (``descend``) self.known_mappings[known_mapping_key][uri] = None self.known_mappings[known_mapping_key][ uri] = self.descend(value=deref_value) return { '$ref': '#/{}/{}'.format(known_mapping_key, self.marshal_uri(uri)) } elif is_dict_like(value): return { key: self.descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ self.descend(value=subval) for index, subval in enumerate(value) ] else: return value
def marshal_schema_object(swagger_spec, schema_object_spec, value): """Marshal the value using the given schema object specification. Marshaling includes: - transform the value according to 'format' if available - return the value in a form suitable for 'on-the-wire' transmission :type swagger_spec: :class:`bravado_core.spec.Spec` :type schema_object_spec: dict :type value: int, long, string, unicode, boolean, list, dict, Model type :return: marshaled value :rtype: int, long, string, unicode, boolean, list, dict :raises: SwaggerMappingError """ deref = swagger_spec.deref schema_object_spec = deref(schema_object_spec) obj_type = schema_object_spec.get('type') if obj_type in SWAGGER_PRIMITIVES: return marshal_primitive(swagger_spec, schema_object_spec, value) if obj_type == 'array': return marshal_array(swagger_spec, schema_object_spec, value) if is_model(swagger_spec, schema_object_spec): # Allow models to be passed in as dicts for flexibility. if is_dict_like(value): return marshal_object(swagger_spec, schema_object_spec, value) # It is important that the 'model' check comes before 'object' check # below. Model specs are of type 'object' but also have a MODEL_MARKER # key for identification. return marshal_model(swagger_spec, schema_object_spec, value) if is_object(swagger_spec, schema_object_spec): return marshal_object(swagger_spec, schema_object_spec, value) if obj_type == 'file': return value raise SwaggerMappingError('Unknown type {0} for value {1}'.format( obj_type, value))
def unmarshal_model(swagger_spec, model_spec, model_value): """Unmarshal a dict into a Model instance. :type swagger_spec: :class:`bravado_core.spec.Spec` :type model_spec: dict :type model_value: dict :rtype: Model instance :raises: SwaggerMappingError """ deref = swagger_spec.deref model_name = deref(model_spec).get(MODEL_MARKER) model_type = swagger_spec.definitions.get(model_name, None) if model_type is None: raise SwaggerMappingError( 'Unknown model {0} when trying to unmarshal {1}' .format(model_name, model_value)) if model_value is None: return handle_null_value(swagger_spec, model_spec) if not is_dict_like(model_value): raise SwaggerMappingError( "Expected type to be dict for value {0} to unmarshal to a {1}." "Was {2} instead." .format(model_value, model_type, type(model_value))) # Check if model is polymorphic discriminator = model_spec.get('discriminator') if discriminator is not None: child_model_name = model_value.get(discriminator, None) if child_model_name not in swagger_spec.definitions: raise SwaggerMappingError( 'Unknown model {0} when trying to unmarshal {1}. ' 'Value of {2}\'s discriminator {3} did not match any definitions.' .format(child_model_name, model_value, model_name, discriminator) ) model_type = swagger_spec.definitions.get(child_model_name) model_spec = model_type._model_spec model_as_dict = unmarshal_object(swagger_spec, model_spec, model_value) model_instance = model_type._from_dict(model_as_dict) return model_instance
def unmarshal_model(swagger_spec, model_spec, model_value): """Unmarshal a dict into a Model instance. :type swagger_spec: :class:`bravado_core.spec.Spec` :type model_spec: dict :type model_value: dict :rtype: Model instance :raises: SwaggerMappingError """ deref = swagger_spec.deref model_name = deref(model_spec).get(MODEL_MARKER) model_type = swagger_spec.definitions.get(model_name, None) if model_type is None: raise SwaggerMappingError( 'Unknown model {0} when trying to unmarshal {1}'.format( model_name, model_value)) if model_value is None: return handle_null_value(swagger_spec, model_spec) if not is_dict_like(model_value): raise SwaggerMappingError( "Expected type to be dict for value {0} to unmarshal to a {1}." "Was {2} instead.".format(model_value, model_type, type(model_value))) # Check if model is polymorphic discriminator = model_spec.get('discriminator') if discriminator is not None: child_model_name = model_value.get(discriminator, None) if child_model_name not in swagger_spec.definitions: raise SwaggerMappingError( 'Unknown model {0} when trying to unmarshal {1}. ' 'Value of {2}\'s discriminator {3} did not match any definitions.' .format(child_model_name, model_value, model_name, discriminator)) model_type = swagger_spec.definitions.get(child_model_name) model_spec = model_type._model_spec model_as_dict = unmarshal_object(swagger_spec, model_spec, model_value) model_instance = model_type._from_dict(model_as_dict) return model_instance
def _rename_references_descend(value): if is_ref(value): return { '$ref': reference_renaming_mapping.get(value['$ref'], value['$ref']) } elif is_dict_like(value): return { key: _rename_references_descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ _rename_references_descend(value=subval) for index, subval in enumerate(value) ] else: return value
def annotate_with_xmodel_callback(container, key): """Tags JsonRef proxies which represent Swagger models with 'x-model': <model name>. :type container: list or dict :param key: the key of the object in the container to inspect :type key: string if container is a dict, int if container is a list """ jsonref_proxy = container[key] if not isinstance(jsonref_proxy, jsonref.JsonRef): return ref_target = jsonref_proxy.__reference__['$ref'] match = RE_MODEL_NAME.match(ref_target) if match is None: return model = jsonref_proxy.__subject__ if is_dict_like(model) and MODEL_MARKER not in model: model[MODEL_MARKER] = match.group('model_name')
def marshal_object(swagger_spec, object_spec, object_value): """Marshal a python dict to json 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 not prop_spec: # Don't marshal when a spec is not available - just pass through result[k] = v continue if v is None and k not in required_fields: if not is_prop_nullable(swagger_spec, prop_spec): continue result[k] = marshal_schema_object(swagger_spec, prop_spec, v) return result
def descend(value): if is_ref(value): uri, deref_value = resolve(value['$ref']) # Update spec_resolver scope to be able to dereference relative specs from a not root file with in_scope(spec_resolver, {'x-scope': [uri]}): object_type = _determine_object_type(object_dict=deref_value) if object_type is _TYPE_PATH_ITEM: return descend(value=deref_value) else: mapping_key = _TYPE_PROPERTY_HOLDER_MAPPING.get( object_type, 'definitions') uri = urlparse(uri) if uri not in known_mappings.get(mapping_key, {}): # The placeholder is present to interrupt the recursion # during the recursive traverse of the data model (``descend``) known_mappings[mapping_key][uri] = None known_mappings[mapping_key][uri] = descend( value=deref_value) return { '$ref': '#/{}/{}'.format(mapping_key, marshal_uri(uri)) } elif is_dict_like(value): return { key: descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ descend(value=subval) for index, subval in enumerate(value) ] else: 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', []) 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: 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 # re-introduce and None'ify any properties that weren't passed properties = deref(object_spec).get('properties', {}) for prop_name, prop_spec in iteritems(properties): if prop_name not in result: result[prop_name] = None return result
def descend(fragment, json_reference=None): """ :param fragment: node in spec_dict :param json_reference: JSON Uri where the current fragment could be found :type json_reference: str """ if is_dict_like(fragment): for key, value in sorted(iteritems(fragment)): json_ref = '{}/{}'.format(json_reference or '', key) fire_callbacks(fragment, json_ref) descend( fragment=fragment[key], json_reference=json_ref, ) elif is_list_like(fragment): for index in range(len(fragment)): json_ref = '{}/{}'.format(json_reference or '', index) fire_callbacks(fragment, json_ref) descend( fragment=fragment[index], json_reference=json_ref, )
def descend(fragment, path=None, visited_refs=None): """ :param fragment: node in spec_dict :param path: list of strings that form the current path to fragment :param visited_refs: list of visted ref_dict """ path = path or [] visited_refs = visited_refs or [] if is_ref(fragment): ref_dict = fragment ref = fragment['$ref'] attach_scope(ref_dict, resolver) # Don't recurse down already visited refs. A ref is not unique # by its name alone. Its scope (attached above) is part of the # equivalence comparison. if ref_dict in visited_refs: log.debug('Already visited %s' % ref) return visited_refs.append(ref_dict) with resolver.resolving(ref) as target: descend(target, path, visited_refs) return # fragment is guaranteed not to be a ref from this point onwards if is_dict_like(fragment): for key, value in iteritems(fragment): fire_callbacks(fragment, key, path + [key]) descend(fragment[key], path + [key], visited_refs) elif is_list_like(fragment): for index in range(len(fragment)): fire_callbacks(fragment, index, path + [str(index)]) descend(fragment[index], path + [str(index)], visited_refs)
def descend(value): if is_ref(value): uri, deref_value = resolve(value['$ref']) # Update spec_resolver scope to be able to dereference relative specs from a not root file with in_scope(spec_resolver, {'x-scope': [uri]}): object_type = _determine_object_type(object_dict=deref_value) if object_type is _TYPE_PATH_ITEM: return descend(value=deref_value) else: mapping_key = _TYPE_PROPERTY_HOLDER_MAPPING.get(object_type, 'definitions') uri = urlparse(uri) if uri not in known_mappings.get(mapping_key, {}): # The placeholder is present to interrupt the recursion # during the recursive traverse of the data model (``descend``) known_mappings[mapping_key][uri] = None known_mappings[mapping_key][uri] = descend(value=deref_value) return {'$ref': '#/{}/{}'.format(mapping_key, marshal_uri(uri))} elif is_dict_like(value): return { key: descend(value=subval) for key, subval in iteritems(value) } elif is_list_like(value): return [ descend(value=subval) for index, subval in enumerate(value) ] else: return value
def is_equal(self, other): # type: (typing.Any) -> bool """ Compare self with `other` NOTE: Not implemented as __eq__ otherwise we would need to implement __hash__ to preserve hashability of the class and it would not necessarily be performance effective WARNING: This method operates in "best-effort" mode in the sense that certain attributes are not implementing any equality check and so we're might be ignoring checking them :param other: instance to compare self against :return: True if self and other are the same, False otherwise """ if id(self) == id(other): return True if not isinstance(other, self.__class__): return False # If self and other are of the same type but not pointing to the same memory location then we're going to inspect # all the attributes. for attr_name in set(chain(iterkeys(self.__dict__), iterkeys(other.__dict__))): # Some attributes do not define equality methods. # As those attributes are defined internally only we do not expect that users of the library are modifying them. if attr_name in { 'format_checker', # jsonschema.FormatChecker does not define an equality method 'resolver', # jsonschema.validators.RefResolver does not define an equality method }: continue # In case of fully dereferenced specs _deref_flattened_spec (and consequently _internal_spec_dict) will contain # recursive reference to objects. Python is not capable of comparing them (weird). # As _internal_spec_dict and _deref_flattened_spec are private so we don't expect users modifying them. if self.config['internally_dereference_refs'] and attr_name in { '_internal_spec_dict', '_deref_flattened_spec', }: continue # It has recursive references to Spec and it is not straight-forward defining an equality check to ignore it # As it is a private cached_property we can ignore it as users should not be "touching" it. if attr_name == '_security_definitions': continue try: self_attr = getattr(self, attr_name) other_attr = getattr(other, attr_name) except AttributeError: return False # Define some special exception handling for attributes that have recursive reference to self. if attr_name == 'resources': if not is_dict_like(self_attr) or not is_dict_like(other_attr): return False for key in set(chain(iterkeys(self_attr), iterkeys(other_attr))): try: if not self_attr[key].is_equal(other_attr[key], ignore_swagger_spec=True): return False except KeyError: return False elif attr_name == 'definitions': if not is_dict_like(self_attr) or not is_dict_like(other_attr): return False for key in set(chain(iterkeys(self_attr), iterkeys(other_attr))): try: self_definition = self_attr[key] other_definition = other_attr[key] if not issubclass(self_definition, Model) or not issubclass(other_definition, self_definition): return False except KeyError: return False elif self_attr != other_attr: return False return True