Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/jedi/cache.py: 39%

66 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-20 06:09 +0000

1""" 

2This caching is very important for speed and memory optimizations. There's 

3nothing really spectacular, just some decorators. The following cache types are 

4available: 

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 

10This module is one of the reasons why |jedi| is not thread-safe. As you can see 

11there are global variables, which are holding the cache information. Some of 

12these variables are being cleaned after every API usage. 

13""" 

14import time 

15from functools import wraps 

16from typing import Any, Dict, Tuple 

17 

18from jedi import settings 

19from parso.cache import parser_cache 

20 

21_time_caches: Dict[str, Dict[Any, Tuple[float, Any]]] = {} 

22 

23 

24def 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 

47def 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 

79def 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 

102def 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