A caching decorator that follows after the style of lru_cache. Calls
    that are sharper than previous requests are returned from the cache after
    honing in on the requested results using the `refineby` technique.

    The `refineby` technique can be `startswith`, `container` or a user
    defined function used to provide a subset of results.

    Eg.
        @hone_cache()
        def completer(prefix):
            print("MISS")
            return set(x for x in {'foo', 'foobar', 'baz'}
                       if x.startswith(prefix))
        completer('f')    # -> {'foo', 'foobar'}
        MISS
        completer('fo')   # -> {'foo', 'foobar'}
        completer('foob') # -> {'foobar'}
        completer('')     # -> {'foo', 'foobar', 'baz'}
        MISS
        completer('ba')   # -> {'baz'}

    If while trying to hone a cache hit there is an exception the wrapped
    function will be called as if it was a full miss.

    The `maxage` argument is an option time-to-live in seconds for each cache
    result.  Any cache entries over the maxage are lazily replaced.

def hone_cache(maxsize=128, maxage=None, refineby='startswith',
               store_partials=False):
    """ A caching decorator that follows after the style of lru_cache. Calls
    that are sharper than previous requests are returned from the cache after
    honing in on the requested results using the `refineby` technique.

    The `refineby` technique can be `startswith`, `container` or a user
    defined function used to provide a subset of results.

    Eg.
        @hone_cache()
        def completer(prefix):
            print("MISS")
            return set(x for x in {'foo', 'foobar', 'baz'}
                       if x.startswith(prefix))
        completer('f')    # -> {'foo', 'foobar'}
        MISS
        completer('fo')   # -> {'foo', 'foobar'}
        completer('foob') # -> {'foobar'}
        completer('')     # -> {'foo', 'foobar', 'baz'}
        MISS
        completer('ba')   # -> {'baz'}

    If while trying to hone a cache hit there is an exception the wrapped
    function will be called as if it was a full miss.

    The `maxage` argument is an option time-to-live in seconds for each cache
    result.  Any cache entries over the maxage are lazily replaced. """
    if not callable(refineby):
        finder = hone_cache_finders[refineby]
    else:
        finder = refineby

    def decorator(inner_func):
        wrapper = make_hone_cache_wrapper(inner_func, maxsize, maxage, finder,
                                          store_partials)
        return functools.update_wrapper(wrapper, inner_func)
    return decorator