Keeps a cache of requests we've already made and use that for
    generating results if possible.  If the user asked for a root prior
    to this call we can use it to skip a new lookup using `finder`.  A
    top-level lookup will effectively serves as a global cache.

def make_hone_cache_wrapper(inner_func, maxsize, maxage, finder,
                            store_partials):
    """ Keeps a cache of requests we've already made and use that for
    generating results if possible.  If the user asked for a root prior
    to this call we can use it to skip a new lookup using `finder`.  A
    top-level lookup will effectively serves as a global cache. """

    hits = misses = partials = 0
    cache = TTLMapping(maxsize, maxage)

    def wrapper(*args):
        nonlocal hits, misses, partials
        radix = args[-1]
        # Attempt fast cache hit first.
        try:
            r = cache[radix]
        except KeyError:
            pass
        else:
            hits += 1
            return r
        for i in range(len(radix) - 1, -1, -1):
            partial_radix = radix[:i]
            try:
                partial = cache[partial_radix]
            except KeyError:
                continue
            try:
                r = finder(radix, partial_radix, partial)
            except:
                break  # Treat any exception as a miss.
            partials += 1
            if store_partials:
                cache[radix] = r
            return r
        misses += 1
        cache[radix] = r = inner_func(*args)
        return r

    def cache_info():
        """ Emulate lru_cache so this is a low touch replacement. """
        return HoneCacheInfo(hits, misses, maxsize, len(cache), maxage,
                             partials, finder)

    def cache_clear():
        """ Clear cache and stats. """
        nonlocal hits, misses, partials
        hits = misses = partials = 0
        cache.clear()

    wrapper.cache_info = cache_info
    wrapper.cache_clear = cache_clear

    return functools.update_wrapper(wrapper, inner_func)