2424 HashFunc ,
2525 Mongetter ,
2626 _update_with_defaults ,
27+ parse_bytes ,
2728)
2829from .cores .base import RecalculationNeeded , _BaseCore
2930from .cores .memory import _MemoryCore
@@ -60,11 +61,15 @@ def _function_thread(core, key, func, args, kwds):
6061 print (f"Function call failed with the following exception:\n { exc } " )
6162
6263
63- def _calc_entry (core , key , func , args , kwds ) -> Optional [Any ]:
64+ def _calc_entry (
65+ core , key , func , args , kwds , printer = lambda * _ : None
66+ ) -> Optional [Any ]:
6467 core .mark_entry_being_calculated (key )
6568 try :
6669 func_res = func (* args , ** kwds )
67- core .set_entry (key , func_res )
70+ stored = core .set_entry (key , func_res )
71+ if not stored :
72+ printer ("Result exceeds entry_size_limit; not cached" )
6873 return func_res
6974 finally :
7075 core .mark_entry_not_calculated (key )
@@ -123,6 +128,7 @@ def cachier(
123128 allow_none : Optional [bool ] = None ,
124129 cleanup_stale : Optional [bool ] = None ,
125130 cleanup_interval : Optional [timedelta ] = None ,
131+ entry_size_limit : Optional [Union [int , str ]] = None ,
126132):
127133 """Wrap as a persistent, stale-free memoization decorator.
128134
@@ -191,6 +197,10 @@ def cachier(
191197 thread. Defaults to False.
192198 cleanup_interval: datetime.timedelta, optional
193199 Minimum time between automatic cleanup runs. Defaults to one day.
200+ entry_size_limit: int or str, optional
201+ Maximum serialized size of a cached value. Values exceeding the limit
202+ are returned but not cached. Human readable strings like ``"10MB"`` are
203+ allowed.
194204
195205 """
196206 # Check for deprecated parameters
@@ -204,6 +214,9 @@ def cachier(
204214 # Update parameters with defaults if input is None
205215 backend = _update_with_defaults (backend , "backend" )
206216 mongetter = _update_with_defaults (mongetter , "mongetter" )
217+ size_limit_bytes = parse_bytes (
218+ _update_with_defaults (entry_size_limit , "entry_size_limit" )
219+ )
207220 # Override the backend parameter if a mongetter is provided.
208221 if callable (mongetter ):
209222 backend = "mongo"
@@ -215,28 +228,34 @@ def cachier(
215228 cache_dir = cache_dir ,
216229 separate_files = separate_files ,
217230 wait_for_calc_timeout = wait_for_calc_timeout ,
231+ entry_size_limit = size_limit_bytes ,
218232 )
219233 elif backend == "mongo" :
220234 core = _MongoCore (
221235 hash_func = hash_func ,
222236 mongetter = mongetter ,
223237 wait_for_calc_timeout = wait_for_calc_timeout ,
238+ entry_size_limit = size_limit_bytes ,
224239 )
225240 elif backend == "memory" :
226241 core = _MemoryCore (
227- hash_func = hash_func , wait_for_calc_timeout = wait_for_calc_timeout
242+ hash_func = hash_func ,
243+ wait_for_calc_timeout = wait_for_calc_timeout ,
244+ entry_size_limit = size_limit_bytes ,
228245 )
229246 elif backend == "sql" :
230247 core = _SQLCore (
231248 hash_func = hash_func ,
232249 sql_engine = sql_engine ,
233250 wait_for_calc_timeout = wait_for_calc_timeout ,
251+ entry_size_limit = size_limit_bytes ,
234252 )
235253 elif backend == "redis" :
236254 core = _RedisCore (
237255 hash_func = hash_func ,
238256 redis_client = redis_client ,
239257 wait_for_calc_timeout = wait_for_calc_timeout ,
258+ entry_size_limit = size_limit_bytes ,
240259 )
241260 else :
242261 raise ValueError ("specified an invalid core: %s" % backend )
@@ -324,12 +343,12 @@ def _call(*args, max_age: Optional[timedelta] = None, **kwds):
324343 )
325344 key , entry = core .get_entry ((), kwargs )
326345 if overwrite_cache :
327- return _calc_entry (core , key , func , args , kwds )
346+ return _calc_entry (core , key , func , args , kwds , _print )
328347 if entry is None or (
329348 not entry ._completed and not entry ._processing
330349 ):
331350 _print ("No entry found. No current calc. Calling like a boss." )
332- return _calc_entry (core , key , func , args , kwds )
351+ return _calc_entry (core , key , func , args , kwds , _print )
333352 _print ("Entry found." )
334353 if _allow_none or entry .value is not None :
335354 _print ("Cached result found." )
@@ -362,7 +381,7 @@ def _call(*args, max_age: Optional[timedelta] = None, **kwds):
362381 try :
363382 return core .wait_on_entry_calc (key )
364383 except RecalculationNeeded :
365- return _calc_entry (core , key , func , args , kwds )
384+ return _calc_entry (core , key , func , args , kwds , _print )
366385 if _next_time :
367386 _print ("Async calc and return stale" )
368387 core .mark_entry_being_calculated (key )
@@ -374,15 +393,15 @@ def _call(*args, max_age: Optional[timedelta] = None, **kwds):
374393 core .mark_entry_not_calculated (key )
375394 return entry .value
376395 _print ("Calling decorated function and waiting" )
377- return _calc_entry (core , key , func , args , kwds )
396+ return _calc_entry (core , key , func , args , kwds , _print )
378397 if entry ._processing :
379398 _print ("No value but being calculated. Waiting." )
380399 try :
381400 return core .wait_on_entry_calc (key )
382401 except RecalculationNeeded :
383- return _calc_entry (core , key , func , args , kwds )
402+ return _calc_entry (core , key , func , args , kwds , _print )
384403 _print ("No entry found. No current calc. Calling like a boss." )
385- return _calc_entry (core , key , func , args , kwds )
404+ return _calc_entry (core , key , func , args , kwds , _print )
386405
387406 # MAINTAINER NOTE: The main function wrapper is now a standard function
388407 # that passes *args and **kwargs to _call. This ensures that user
0 commit comments