| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115 |
- """
- This caching is very important for speed and memory optimizations. There's
- nothing really spectacular, just some decorators. The following cache types are
- available:
- - ``time_cache`` can be used to cache something for just a limited time span,
- which can be useful if there's user interaction and the user cannot react
- faster than a certain time.
- This module is one of the reasons why |jedi| is not thread-safe. As you can see
- there are global variables, which are holding the cache information. Some of
- these variables are being cleaned after every API usage.
- """
- import time
- from functools import wraps
- from typing import Any, Dict, Tuple
- from jedi import settings
- from parso.cache import parser_cache
- _time_caches: Dict[str, Dict[Any, Tuple[float, Any]]] = {}
- def clear_time_caches(delete_all: bool = False) -> None:
- """ Jedi caches many things, that should be completed after each completion
- finishes.
- :param delete_all: Deletes also the cache that is normally not deleted,
- like parser cache, which is important for faster parsing.
- """
- global _time_caches
- if delete_all:
- for cache in _time_caches.values():
- cache.clear()
- parser_cache.clear()
- else:
- # normally just kill the expired entries, not all
- for tc in _time_caches.values():
- # check time_cache for expired entries
- for key, (t, value) in list(tc.items()):
- if t < time.time():
- # delete expired entries
- del tc[key]
- def signature_time_cache(time_add_setting):
- """
- This decorator works as follows: Call it with a setting and after that
- use the function with a callable that returns the key.
- But: This function is only called if the key is not available. After a
- certain amount of time (`time_add_setting`) the cache is invalid.
- If the given key is None, the function will not be cached.
- """
- def _temp(key_func):
- dct = {}
- _time_caches[time_add_setting] = dct
- def wrapper(*args, **kwargs):
- generator = key_func(*args, **kwargs)
- key = next(generator)
- try:
- expiry, value = dct[key]
- if expiry > time.time():
- return value
- except KeyError:
- pass
- value = next(generator)
- time_add = getattr(settings, time_add_setting)
- if key is not None:
- dct[key] = time.time() + time_add, value
- return value
- return wrapper
- return _temp
- def time_cache(seconds):
- def decorator(func):
- cache = {}
- @wraps(func)
- def wrapper(*args, **kwargs):
- key = (args, frozenset(kwargs.items()))
- try:
- created, result = cache[key]
- if time.time() < created + seconds:
- return result
- except KeyError:
- pass
- result = func(*args, **kwargs)
- cache[key] = time.time(), result
- return result
- wrapper.clear_cache = lambda: cache.clear()
- return wrapper
- return decorator
- def memoize_method(method):
- """A normal memoize function."""
- @wraps(method)
- def wrapper(self, *args, **kwargs):
- cache_dict = self.__dict__.setdefault('_memoize_method_dct', {})
- dct = cache_dict.setdefault(method, {})
- key = (args, frozenset(kwargs.items()))
- try:
- return dct[key]
- except KeyError:
- result = method(self, *args, **kwargs)
- dct[key] = result
- return result
- return wrapper
|