1919from warnings import warn
2020
2121from ._types import RedisClient
22- from .config import (
23- Backend ,
24- HashFunc ,
25- Mongetter ,
26- _update_with_defaults ,
27- )
22+ from .config import Backend , HashFunc , Mongetter , _update_with_defaults
2823from .cores .base import RecalculationNeeded , _BaseCore
2924from .cores .memory import _MemoryCore
3025from .cores .mongo import _MongoCore
3126from .cores .pickle import _PickleCore
3227from .cores .redis import _RedisCore
3328from .cores .sql import _SQLCore
29+ from .util import parse_bytes
3430
3531MAX_WORKERS_ENVAR_NAME = "CACHIER_MAX_WORKERS"
3632DEFAULT_MAX_WORKERS = 8
@@ -60,11 +56,15 @@ def _function_thread(core, key, func, args, kwds):
6056 print (f"Function call failed with the following exception:\n { exc } " )
6157
6258
63- def _calc_entry (core , key , func , args , kwds ) -> Optional [Any ]:
59+ def _calc_entry (
60+ core , key , func , args , kwds , printer = lambda * _ : None
61+ ) -> Optional [Any ]:
6462 core .mark_entry_being_calculated (key )
6563 try :
6664 func_res = func (* args , ** kwds )
67- core .set_entry (key , func_res )
65+ stored = core .set_entry (key , func_res )
66+ if not stored :
67+ printer ("Result exceeds entry_size_limit; not cached" )
6868 return func_res
6969 finally :
7070 core .mark_entry_not_calculated (key )
@@ -123,6 +123,7 @@ def cachier(
123123 allow_none : Optional [bool ] = None ,
124124 cleanup_stale : Optional [bool ] = None ,
125125 cleanup_interval : Optional [timedelta ] = None ,
126+ entry_size_limit : Optional [Union [int , str ]] = None ,
126127):
127128 """Wrap as a persistent, stale-free memoization decorator.
128129
@@ -191,6 +192,10 @@ def cachier(
191192 thread. Defaults to False.
192193 cleanup_interval: datetime.timedelta, optional
193194 Minimum time between automatic cleanup runs. Defaults to one day.
195+ entry_size_limit: int or str, optional
196+ Maximum serialized size of a cached value. Values exceeding the limit
197+ are returned but not cached. Human readable strings like ``"10MB"`` are
198+ allowed.
194199
195200 """
196201 # Check for deprecated parameters
@@ -204,6 +209,9 @@ def cachier(
204209 # Update parameters with defaults if input is None
205210 backend = _update_with_defaults (backend , "backend" )
206211 mongetter = _update_with_defaults (mongetter , "mongetter" )
212+ size_limit_bytes = parse_bytes (
213+ _update_with_defaults (entry_size_limit , "entry_size_limit" )
214+ )
207215 # Override the backend parameter if a mongetter is provided.
208216 if callable (mongetter ):
209217 backend = "mongo"
@@ -215,28 +223,34 @@ def cachier(
215223 cache_dir = cache_dir ,
216224 separate_files = separate_files ,
217225 wait_for_calc_timeout = wait_for_calc_timeout ,
226+ entry_size_limit = size_limit_bytes ,
218227 )
219228 elif backend == "mongo" :
220229 core = _MongoCore (
221230 hash_func = hash_func ,
222231 mongetter = mongetter ,
223232 wait_for_calc_timeout = wait_for_calc_timeout ,
233+ entry_size_limit = size_limit_bytes ,
224234 )
225235 elif backend == "memory" :
226236 core = _MemoryCore (
227- hash_func = hash_func , wait_for_calc_timeout = wait_for_calc_timeout
237+ hash_func = hash_func ,
238+ wait_for_calc_timeout = wait_for_calc_timeout ,
239+ entry_size_limit = size_limit_bytes ,
228240 )
229241 elif backend == "sql" :
230242 core = _SQLCore (
231243 hash_func = hash_func ,
232244 sql_engine = sql_engine ,
233245 wait_for_calc_timeout = wait_for_calc_timeout ,
246+ entry_size_limit = size_limit_bytes ,
234247 )
235248 elif backend == "redis" :
236249 core = _RedisCore (
237250 hash_func = hash_func ,
238251 redis_client = redis_client ,
239252 wait_for_calc_timeout = wait_for_calc_timeout ,
253+ entry_size_limit = size_limit_bytes ,
240254 )
241255 else :
242256 raise ValueError ("specified an invalid core: %s" % backend )
@@ -324,12 +338,12 @@ def _call(*args, max_age: Optional[timedelta] = None, **kwds):
324338 )
325339 key , entry = core .get_entry ((), kwargs )
326340 if overwrite_cache :
327- return _calc_entry (core , key , func , args , kwds )
341+ return _calc_entry (core , key , func , args , kwds , _print )
328342 if entry is None or (
329343 not entry ._completed and not entry ._processing
330344 ):
331345 _print ("No entry found. No current calc. Calling like a boss." )
332- return _calc_entry (core , key , func , args , kwds )
346+ return _calc_entry (core , key , func , args , kwds , _print )
333347 _print ("Entry found." )
334348 if _allow_none or entry .value is not None :
335349 _print ("Cached result found." )
@@ -362,7 +376,7 @@ def _call(*args, max_age: Optional[timedelta] = None, **kwds):
362376 try :
363377 return core .wait_on_entry_calc (key )
364378 except RecalculationNeeded :
365- return _calc_entry (core , key , func , args , kwds )
379+ return _calc_entry (core , key , func , args , kwds , _print )
366380 if _next_time :
367381 _print ("Async calc and return stale" )
368382 core .mark_entry_being_calculated (key )
@@ -374,15 +388,15 @@ def _call(*args, max_age: Optional[timedelta] = None, **kwds):
374388 core .mark_entry_not_calculated (key )
375389 return entry .value
376390 _print ("Calling decorated function and waiting" )
377- return _calc_entry (core , key , func , args , kwds )
391+ return _calc_entry (core , key , func , args , kwds , _print )
378392 if entry ._processing :
379393 _print ("No value but being calculated. Waiting." )
380394 try :
381395 return core .wait_on_entry_calc (key )
382396 except RecalculationNeeded :
383- return _calc_entry (core , key , func , args , kwds )
397+ return _calc_entry (core , key , func , args , kwds , _print )
384398 _print ("No entry found. No current calc. Calling like a boss." )
385- return _calc_entry (core , key , func , args , kwds )
399+ return _calc_entry (core , key , func , args , kwds , _print )
386400
387401 # MAINTAINER NOTE: The main function wrapper is now a standard function
388402 # that passes *args and **kwargs to _call. This ensures that user
0 commit comments