예제 #1
0
def ref_validator(
    validator,  # type: Draft4Validator
    ref,  # type: typing.Any
    instance,  # type: typing.Any
    schema,  # type: JSONDict
):
    # type: (...) -> typing.Generator[ValidationError, None, None]
    """When validating a request or response that contain $refs, jsonschema's
     RefResolver only contains scope (RefResolver._scopes_stack) for the
     request_spec or response_spec that it is fed. This scope doesn't contain
     the full scope built when ingesting the spec from its root
     (#/ in swagger.json). So, we need to modify the behavior of ref
     validation to use the `x-scope` annotations that were created during spec
     ingestion (see model_discovery in bravado_core/model.py).

    :param validator: Validator class used to validate the object
    :type validator: :class: `Swagger20Validator` or
        :class: `jsonschema.validators.Draft4Validator`
    :param ref: the target of the ref. eg. #/foo/bar/Baz
    :type ref: string
    :param instance: the object being validated
    :param schema: swagger spec that contains the ref.
        eg {'$ref': '#/foo/bar/Baz'}
    :type schema: dict
    """
    # This is a copy of jsonschema._validators.ref(..) with the
    # in_scope(..) context manager applied before any refs are resolved.
    resolve = getattr(validator.resolver, "resolve")
    if resolve is None:
        with in_scope(validator.resolver, schema):
            with validator.resolver.resolving(ref) as resolved:
                for error in validator.descend(instance, resolved):
                    yield error
    else:
        with in_scope(validator.resolver, schema):
            scope, resolved = validator.resolver.resolve(ref)
        validator.resolver.push_scope(scope)

        try:
            for error in validator.descend(instance, resolved):
                yield error
        finally:
            validator.resolver.pop_scope()
def ref_validator(validator, ref, instance, schema):
    """When validating a request or response that contain $refs, jsonschema's
     RefResolver only contains scope (RefResolver._scopes_stack) for the
     request_spec or response_spec that it is fed. This scope doesn't contain
     the full scope built when ingesting the spec from its root
     (#/ in swagger.json). So, we need to modify the behavior of ref
     validation to use the `x-scope` annotations that were created during spec
     ingestion (see post_process_spec in spec.py).

    :param validator: Validator class used to validate the object
    :type validator: :class: `Swagger20Validator` or
        :class: `jsonschema.validators.Draft4Validator`
    :param ref: the target of the ref. eg. #/foo/bar/Baz
    :type ref: string
    :param instance: the object being validated
    :param schema: swagger spec that contains the ref.
        eg {'$ref': '#/foo/bar/Baz'}
    :type schema: dict
    """
    # This is a copy of jsonscehama._validators.ref(..) with the
    # in_scope(..) context manager applied before any refs are resolved.
    resolve = getattr(validator.resolver, "resolve")
    if resolve is None:
        with in_scope(validator.resolver, schema):
            with validator.resolver.resolving(ref) as resolved:
                for error in validator.descend(instance, resolved):
                    yield error
    else:
        with in_scope(validator.resolver, schema):
            scope, resolved = validator.resolver.resolve(ref)
        validator.resolver.push_scope(scope)

        try:
            for error in validator.descend(instance, resolved):
                yield error
        finally:
            validator.resolver.pop_scope()
예제 #3
0
    def _force_deref(self, ref_dict):
        """Dereference ref_dict (if it is indeed a ref) and return what the
        ref points to.

        :param ref_dict:  {'$ref': '#/blah/blah'}
        :return: dereferenced value of ref_dict
        :rtype: scalar, list, dict
        """
        if ref_dict is None or not is_ref(ref_dict):
            return ref_dict

        # Restore attached resolution scope before resolving since the
        # resolver doesn't have a traversal history (accumulated scope_stack)
        # when asked to resolve.
        with in_scope(self.resolver, ref_dict):
            _, target = self.resolver.resolve(ref_dict['$ref'])
            return target
예제 #4
0
    def _force_deref(self, ref_dict):
        """Dereference ref_dict (if it is indeed a ref) and return what the
        ref points to.

        :param ref_dict:  {'$ref': '#/blah/blah'}
        :return: dereferenced value of ref_dict
        :rtype: scalar, list, dict
        """
        if ref_dict is None or not is_ref(ref_dict):
            return ref_dict

        # Restore attached resolution scope before resolving since the
        # resolver doesn't have a traversal history (accumulated scope_stack)
        # when asked to resolve.
        with in_scope(self.resolver, ref_dict):
            _, target = self.resolver.resolve(ref_dict['$ref'])
            return target
예제 #5
0
    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 deref(ref_dict, resolver):
    """Dereference ref_dict (if it is indeed a ref) and return what the
    ref points to.

    :param ref_dict: Something like {'$ref': '#/blah/blah'}
    :type ref_dict: dict
    :param resolver: Ref resolver used to do the de-referencing
    :type resolver: :class:`jsonschema.RefResolver`

    :return: de-referenced value of ref_dict
    :rtype: scalar, list, dict
    """
    if ref_dict is None or not is_ref(ref_dict):
        return ref_dict

    ref = ref_dict['$ref']
    with in_scope(resolver, ref_dict):
        with resolver.resolving(ref) as target:
            log.debug('Resolving %s', ref)
            return target
예제 #7
0
def deref(ref_dict, resolver):
    """Dereference ref_dict (if it is indeed a ref) and return what the
    ref points to.

    :param ref_dict: Something like {'$ref': '#/blah/blah'}
    :type ref_dict: dict
    :param resolver: Ref resolver used to do the de-referencing
    :type resolver: :class:`jsonschema.RefResolver`

    :return: de-referenced value of ref_dict
    :rtype: scalar, list, dict
    """
    if ref_dict is None or not is_ref(ref_dict):
        return ref_dict

    ref = ref_dict['$ref']
    with in_scope(resolver, ref_dict):
        with resolver.resolving(ref) as target:
            log.debug('Resolving %s', ref)
            return target
예제 #8
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
예제 #9
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