Example #1
0
    def __init__(self, specs, url=None):
        """
    Construct a JSON reference resolver.

    The resolved specs are in the `specs` member after a call to
    `resolve_references` has been made.

    If a URL is given, it is used as a base for calculating the absolute
    URL of relative file references.

    :param dict specs: The parsed specs in which to resolve any references.
    :param str url: [optional] The URL to base relative references on.
    """
        import copy
        self.specs = copy.deepcopy(specs)
        self.url = url

        if self.url:
            self.parsed_url = _url.absurl(self.url)
            self._url_key = _url.urlresource(self.parsed_url)
        else:
            self.parsed_url = self._url_key = None

        self.__resolution_status = self.__RS_UNRESOLVED
        self.__recursion_protection = set()
Example #2
0
    def _fetch_url(self, url):
        """
    Fetch the parsed contents of the given URL.

    Uses a caching mechanism so that each URL is only fetched once.
    """
        url_key = _url.urlresource(url)

        # Same URL key means it's the current file
        if url_key == self._url_key:
            return url, self.specs

        # For all other URLs, we might have a cached parser around already.
        resolver = self.__reference_cache.get(url_key, None)

        # If we don't have a parser for the url yet, create and cache one.
        if not resolver:
            resolver = RefResolver(_url.fetch_url(url), url)
            self.__reference_cache[url_key] = resolver

        # Resolve references *after* (potentially) adding the resolver to the
        # cache. This together with the __recursion_protection allows us to detect
        # and report recursions and bad references.
        resolver.resolve_references()

        # That's it!
        return url, resolver.specs
Example #3
0
    def __init__(self, specs, url):
        """
        Construct a JSON reference translator.

        The translated specs are in the `specs` member after a call to
        `translate_references` has been made.

        If a URL is given, it is used as a base for calculating the absolute
        URL of relative file references.

        :param dict specs: The parsed specs in which to translate any references.
        :param str url: [optional] The URL to base relative references on.
        """
        import copy

        self.specs = copy.deepcopy(specs)

        self.__strict = True
        self.__reference_cache = {}
        self.__collected_references = {}

        if url:
            self.url = _url.absurl(url)
            url_key = (_url.urlresource(self.url), self.__strict)

            # If we have a url, we want to add ourselves to the reference cache
            # - that creates a reference loop, but prevents child resolvers from
            # creating a new resolver for this url.
            self.__reference_cache[url_key] = self.specs
        else:
            self.url = None
Example #4
0
    def __init__(self, specs, url=None, **options):
        """
    Construct a JSON reference resolver.

    The resolved specs are in the `specs` member after a call to
    `resolve_references` has been made.

    If a URL is given, it is used as a base for calculating the absolute
    URL of relative file references.

    :param dict specs: The parsed specs in which to resolve any references.
    :param str url: [optional] The URL to base relative references on.
    :param dict reference_cache: [optional] Reference cache to use. When
        encountering references, nested RefResolvers are created, and this
        parameter is used by the RefResolver hierarchy to create only one
        resolver per unique URL.
        If you wish to use this optimization across distinct RefResolver
        instances, pass a dict here for the RefResolvers you create
        yourself. It's safe to ignore this parameter in other cases.
    :param int recursion_limit: [optional] set the limit on recursive
        references. The default is 1, indicating that an element may be
        refered to exactly once when resolving references. When the limit
        is reached, the recursion_limit_handler is invoked.
    :param callable recursion_limit_handler: [optional] A callable that
        gets invoked when the recursion_limit is reached. Defaults to
        raising ResolutionError. Receives the recursion_limit as the
        first parameter, and the parsed reference URL as the second. As
        the last parameter, it receives a tuple of references that have
        been detected as recursions.
    :param str encoding: [optional] The encoding to use. If not given,
        detect_encoding is used to determine the encoding.
    :param int resolve_types: [optional] Specify which types of references to
        resolve. Defaults to RESOLVE_ALL.
    """
        import copy
        self.specs = copy.deepcopy(specs)
        self.url = url

        self.__reclimit = options.get('recursion_limit', 1)
        self.__reclimit_handler = options.get('recursion_limit_handler',
                                              default_reclimit_handler)
        self.__reference_cache = options.get('reference_cache', {})

        if self.url:
            self.parsed_url = _url.absurl(self.url)
            self._url_key = _url.urlresource(self.parsed_url)

            # If we have a url, we want to add ourselves to the reference cache
            # - that creates a reference loop, but prevents child resolvers from
            # creating a new resolver for this url.
            if self.specs:
                self.__reference_cache[self._url_key] = self.specs
        else:
            self.parsed_url = self._url_key = None

        self.__resolve_types = options.get('resolve_types', RESOLVE_ALL)
        self.__encoding = options.get('encoding', None)
Example #5
0
    def _dereferencing_iterator(self, base_url, partial, path, recursions):
        """
        Iterate over a partial spec, dereferencing all references within.

        Yields the resolved path and value of all items that need substituting.

        :param mixed base_url: URL that the partial specs is located at.
        :param dict partial: The partial specs to work on.
        :param tuple path: The parent path of the partial specs.
        :param tuple recursions: A recursion stack for resolving references.
        """
        from .iterators import reference_iterator

        for _, refstring, item_path in reference_iterator(partial):
            # Split the reference string into parsed URL and object path
            ref_url, obj_path = _url.split_url_reference(base_url, refstring)

            translate = (self.__resolve_method == TRANSLATE_EXTERNAL
                         and self.parsed_url.path != ref_url.path)

            if self._skip_reference(base_url, ref_url):
                continue

            # The reference path is the url resource and object path
            ref_path = (_url.urlresource(ref_url), tuple(obj_path))

            # Count how often the reference path has been recursed into.
            from collections import Counter

            rec_counter = Counter(recursions)
            next_recursions = recursions + (ref_path, )

            if rec_counter[ref_path] >= self.__reclimit:
                # The referenced value may be produced by the handler, or the handler
                # may raise, etc.
                ref_value = self.__reclimit_handler(self.__reclimit, ref_url,
                                                    next_recursions)
            else:
                # The referenced value is to be used, but let's copy it to avoid
                # building recursive structures.
                ref_value = self._dereference(ref_url, obj_path,
                                              next_recursions)

            # Full item path
            full_path = path + item_path

            # First yield parent
            if translate:
                url = self._collect_soft_refs(ref_url, obj_path, ref_value)
                yield full_path, {"$ref": "#/components/schemas/" + url}
            else:
                yield full_path, ref_value
Example #6
0
def test_urlresource():
    parsed = url.absurl('http://foo.bar/asdf?some=query#myfrag')
    res = url.urlresource(parsed)
    assert res == 'http://foo.bar/asdf'