def METHOD_NAME(func):
    if hasattr(func, "cache"):
        raise ValueError(
            f"Cannot cache the {func.__name__} function twice! "
            "Pass multiple event names to the `cache_until` decorator."
        )
    cache: Cache = {} if not debug else DebugCacheDict(func)
    @wraps(func)
    def decorator(*a, **kw):
        if IS_CACHING:
            key: tuple[Any] = (a, _KWARGS_SEPARATOR, *kw.items())
            # Check if the value is in the cache; if we have a cache miss,
            # we return a special singleton object `_NOT_FOUND_IN_CACHE`. This way
            # we can also cache a result of 'None' from a function
            value = cache.get(key, _NOT_FOUND_IN_CACHE)
            if value is not _NOT_FOUND_IN_CACHE:
                return value
            value = func(*a, **kw)
            # Sanity check: its not perfect and won't cover all cases like ([],)
            # but it should be good enough
            if isinstance(value, list):
                print(f"Should not cache mutable types! {func.__name__}")
            cache[key] = value
            return value
        return func(*a, **kw)
    # Set the cache on the function so it can be cleared on demand
    # this may be useful for tests
    decorator.cache = cache
    # Register the cache for the given event so it can be cleared
    for event_name in event_names:
        _ALL_CACHE_UNTIL_EVENTS[event_name].add_cache(cache)
    return decorator