Spaces:
Running
on
Zero
Running
on
Zero
| """ | |
| 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 = {} | |
| 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.""" | |
| 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 | |