1111import functools
1212import datetime as datetime_module
1313
14+ from python_toolbox import binary_search
1415from python_toolbox import decorator_tools
15-
1616from python_toolbox .sleek_reffing import SleekCallArgs
1717from python_toolbox .nifty_collections import OrderedDict
1818
@@ -24,7 +24,7 @@ class CLEAR_ENTIRE_CACHE(object):
2424
2525
2626@decorator_tools .helpful_decorator_builder
27- def cache (max_size = infinity , time_limit = None ):
27+ def cache (max_size = infinity , time_to_keep = None ):
2828 '''
2929 Cache a function, saving results so they won't have to be computed again.
3030
@@ -56,17 +56,19 @@ def f(a, b=2):
5656 # have to go through so much shit. update: probably it will help only for
5757 # completely argumentless function. so do one for those.
5858
59- if time_limit is not None :
60- if not isinstance (time_limit , datetime_module .timedelta ):
59+ if time_to_keep is not None :
60+ if max_size != infinity :
61+ raise NotImplementedError
62+ if not isinstance (time_to_keep , datetime_module .timedelta ):
6163 try :
62- time_limit = datetime_module .timedelta (** time_limit )
64+ time_to_keep = datetime_module .timedelta (** time_to_keep )
6365 except Exception :
6466 raise TypeError (
6567 '`time_limit` must be either a `timedelta` object or a '
6668 'dict of keyword arguments for constructing a '
6769 '`timedelta` object.'
6870 )
69- assert isinstance (time_limit , datetime_module .timedelta )
71+ assert isinstance (time_to_keep , datetime_module .timedelta )
7072
7173
7274 def decorator (function ):
@@ -76,17 +78,53 @@ def decorator(function):
7678
7779 if max_size == infinity :
7880
79- cache_dict = {}
81+ if time_to_keep :
8082
81- def cached (function , * args , ** kwargs ):
82- sleek_call_args = \
83- SleekCallArgs (cache_dict , function , * args , ** kwargs )
84- try :
85- return cached ._cache [sleek_call_args ]
86- except KeyError :
87- cached ._cache [sleek_call_args ] = value = \
88- function (* args , ** kwargs )
89- return value
83+ cache_dict = OrderedDict ()
84+ sorting_key_function = lambda sleek_call_args : \
85+ cached ._cache [sleek_call_args ][0 ]
86+
87+
88+ def remove_expired_entries ():
89+ cutting_point = binary_search .binary_search_by_index (
90+ cached ._cache ,
91+ sorting_key_function ,
92+ datetime_module .datetime .now (),
93+ rounding = binary_search .LOW
94+ )
95+ if cutting_point is not None :
96+ for key in cached ._cache .keys ()[:cutting_point ]:
97+ del cached ._cache [key ]
98+
99+
100+ def cached (function , * args , ** kwargs ):
101+ remove_expired_entries ()
102+ sleek_call_args = \
103+ SleekCallArgs (cache_dict , function , * args , ** kwargs )
104+ try :
105+ return cached ._cache [sleek_call_args ][0 ]
106+ except KeyError :
107+ value = function (* args , ** kwargs )
108+ cached ._cache [sleek_call_args ] = (
109+ value ,
110+ datetime_module .datetime .now ()
111+ )
112+ cached ._cache .sort (key = sorting_key_function )
113+ return value
114+
115+ else : # not time_to_keep
116+
117+ cache_dict = {}
118+
119+ def cached (function , * args , ** kwargs ):
120+ sleek_call_args = \
121+ SleekCallArgs (cache_dict , function , * args , ** kwargs )
122+ try :
123+ return cached ._cache [sleek_call_args ]
124+ except KeyError :
125+ cached ._cache [sleek_call_args ] = value = \
126+ function (* args , ** kwargs )
127+ return value
90128
91129 else : # max_size < infinity
92130
0 commit comments