Format: text/x-python
⬇ Download File (3.6 KB)
   1  """
   2  This caching is very important for speed and memory optimizations. There's
   3  nothing really spectacular, just some decorators. The following cache types are
   4  available:
   5  
   6  - ``time_cache`` can be used to cache something for just a limited time span,
   7    which can be useful if there's user interaction and the user cannot react
   8    faster than a certain time.
   9  
  10  This module is one of the reasons why |jedi| is not thread-safe. As you can see
  11  there are global variables, which are holding the cache information. Some of
  12  these variables are being cleaned after every API usage.
  13  """
  14  import time
  15  from functools import wraps
  16  from typing import Any, Dict, Tuple
  17  
  18  from jedi import settings
  19  from parso.cache import parser_cache
  20  
  21  _time_caches: Dict[str, Dict[Any, Tuple[float, Any]]] = {}
  22  
  23  
  24  def clear_time_caches(delete_all: bool = False) -> None:
  25      """ Jedi caches many things, that should be completed after each completion
  26      finishes.
  27  
  28      :param delete_all: Deletes also the cache that is normally not deleted,
  29          like parser cache, which is important for faster parsing.
  30      """
  31      global _time_caches
  32  
  33      if delete_all:
  34          for cache in _time_caches.values():
  35              cache.clear()
  36          parser_cache.clear()
  37      else:
  38          # normally just kill the expired entries, not all
  39          for tc in _time_caches.values():
  40              # check time_cache for expired entries
  41              for key, (t, value) in list(tc.items()):
  42                  if t < time.time():
  43                      # delete expired entries
  44                      del tc[key]
  45  
  46  
  47  def signature_time_cache(time_add_setting):
  48      """
  49      This decorator works as follows: Call it with a setting and after that
  50      use the function with a callable that returns the key.
  51      But: This function is only called if the key is not available. After a
  52      certain amount of time (`time_add_setting`) the cache is invalid.
  53  
  54      If the given key is None, the function will not be cached.
  55      """
  56      def _temp(key_func):
  57          dct = {}
  58          _time_caches[time_add_setting] = dct
  59  
  60          def wrapper(*args, **kwargs):
  61              generator = key_func(*args, **kwargs)
  62              key = next(generator)
  63              try:
  64                  expiry, value = dct[key]
  65                  if expiry > time.time():
  66                      return value
  67              except KeyError:
  68                  pass
  69  
  70              value = next(generator)
  71              time_add = getattr(settings, time_add_setting)
  72              if key is not None:
  73                  dct[key] = time.time() + time_add, value
  74              return value
  75          return wrapper
  76      return _temp
  77  
  78  
  79  def time_cache(seconds):
  80      def decorator(func):
  81          cache = {}
  82  
  83          @wraps(func)
  84          def wrapper(*args, **kwargs):
  85              key = (args, frozenset(kwargs.items()))
  86              try:
  87                  created, result = cache[key]
  88                  if time.time() < created + seconds:
  89                      return result
  90              except KeyError:
  91                  pass
  92              result = func(*args, **kwargs)
  93              cache[key] = time.time(), result
  94              return result
  95  
  96          wrapper.clear_cache = lambda: cache.clear()
  97          return wrapper
  98  
  99      return decorator
 100  
 101  
 102  def memoize_method(method):
 103      """A normal memoize function."""
 104      @wraps(method)
 105      def wrapper(self, *args, **kwargs):
 106          cache_dict = self.__dict__.setdefault('_memoize_method_dct', {})
 107          dct = cache_dict.setdefault(method, {})
 108          key = (args, frozenset(kwargs.items()))
 109          try:
 110              return dct[key]
 111          except KeyError:
 112              result = method(self, *args, **kwargs)
 113              dct[key] = result
 114              return result
 115      return wrapper
 116