Source code for core_mixins.decorators.cache

# -*- coding: utf-8 -*-

"""Caching decorator for memoizing function results."""

import threading
from collections import OrderedDict
from functools import wraps
from typing import Any, Callable, Optional, Tuple


class _CacheWrapper:
    """Wrapper class to maintain cache for decorated function."""

    def __init__(self, fcn: Callable, maxsize: Optional[int] = None) -> None:
        self.fcn = fcn
        self.cache: OrderedDict[Tuple[Any, ...], Any] = OrderedDict()
        self._lock = threading.Lock()
        self.maxsize = maxsize
        wraps(fcn)(self)

    def __call__(self, *args: Any, **kwargs: Any) -> Any:
        cache_key = args + tuple(sorted(kwargs.items()))
        with self._lock:
            if cache_key in self.cache:
                self.cache.move_to_end(cache_key)
                return self.cache[cache_key]

            self.cache[cache_key] = self.fcn(*args, **kwargs)

            if self.maxsize is not None and len(self.cache) > self.maxsize:
                self.cache.popitem(last=False)

            return self.cache[cache_key]


[docs] def cache( fcn: Optional[Callable] = None, *, maxsize: Optional[int] = None, ) -> Callable: """ It maintains a cache of previous function call results that can be used to optimize the performance... :param fcn: The function being decorated. :param maxsize: Maximum number of entries to keep. When the limit is reached the least-recently-used entry is evicted. ``None`` (default) means the cache is unbounded. :return: The wrapped function. :rtype: Callable """ def decorator(_fcn: Callable) -> _CacheWrapper: return _CacheWrapper(_fcn, maxsize=maxsize) if fcn is not None: return decorator(fcn) return decorator