Exemple #1
0
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) + ', ')
Exemple #2
0
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) + ', '
Exemple #3
0
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
Exemple #4
0
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,
    )
Exemple #5
0
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
Exemple #6
0
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
Exemple #7
0
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
Exemple #8
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 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
Exemple #9
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 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
Exemple #10
0
        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
Exemple #11
0
    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)
Exemple #12
0
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
Exemple #13
0
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
Exemple #16
0
    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)
Exemple #17
0
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
Exemple #18
0
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
Exemple #19
0
 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)
Exemple #20
0
 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)
Exemple #21
0
 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])
Exemple #22
0
 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)
Exemple #23
0
 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])
Exemple #24
0
 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)
Exemple #25
0
 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)
Exemple #26
0
    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)
Exemple #28
0
 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)
Exemple #29
0
 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
Exemple #31
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
Exemple #32
0
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))
Exemple #33
0
    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)
Exemple #34
0
 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
Exemple #35
0
    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)
Exemple #36
0
 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
Exemple #37
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
    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
Exemple #39
0
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))
Exemple #40
0
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
Exemple #41
0
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
Exemple #42
0
        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
Exemple #43
0
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')
Exemple #44
0
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
Exemple #45
0
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
Exemple #46
0
    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
Exemple #48
0
    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
Exemple #51
0
    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