77# http://www.opensource.org/licenses/MIT-license
88# Copyright (c) 2016, Shay Palachy <shaypal5@gmail.com>
99
10- # python 2 compatibility
11-
1210import datetime
13- import hashlib
1411import inspect
1512import os
16- import pickle
1713from collections import OrderedDict
1814from concurrent .futures import ThreadPoolExecutor
1915from functools import wraps
20- from typing import TYPE_CHECKING , Callable , Literal , Optional , TypedDict , Union
16+ from typing import Optional , Union
2117from warnings import warn
2218
19+ from .config import (
20+ Backend ,
21+ HashFunc ,
22+ Mongetter ,
23+ _default_params ,
24+ _update_with_defaults ,
25+ )
2326from .cores .base import RecalculationNeeded , _BaseCore
2427from .cores .memory import _MemoryCore
2528from .cores .mongo import _MongoCore
2629from .cores .pickle import _PickleCore
2730
28- if TYPE_CHECKING :
29- import pymongo .collection
30-
31-
3231MAX_WORKERS_ENVAR_NAME = "CACHIER_MAX_WORKERS"
3332DEFAULT_MAX_WORKERS = 8
3433
@@ -68,15 +67,6 @@ def _calc_entry(core, key, func, args, kwds):
6867 core .mark_entry_not_calculated (key )
6968
7069
71- def _default_hash_func (args , kwds ):
72- # Sort the kwargs to ensure consistent ordering
73- sorted_kwargs = sorted (kwds .items ())
74- # Serialize args and sorted_kwargs using pickle or similar
75- serialized = pickle .dumps ((args , sorted_kwargs ))
76- # Create a hash of the serialized data
77- return hashlib .sha256 (serialized ).hexdigest ()
78-
79-
8070def _convert_args_kwargs (
8171 func , _is_method : bool , args : tuple , kwds : dict
8272) -> dict :
@@ -103,44 +93,6 @@ def _convert_args_kwargs(
10393 return OrderedDict (sorted (kwargs .items ()))
10494
10595
106- class MissingMongetter (ValueError ):
107- """Thrown when the mongetter keyword argument is missing."""
108-
109-
110- HashFunc = Callable [..., str ]
111- Mongetter = Callable [[], "pymongo.collection.Collection" ]
112- Backend = Literal ["pickle" , "mongo" , "memory" ]
113-
114-
115- class Params (TypedDict ):
116- caching_enabled : bool
117- hash_func : HashFunc
118- backend : Backend
119- mongetter : Optional [Mongetter ]
120- stale_after : datetime .timedelta
121- next_time : bool
122- cache_dir : Union [str , os .PathLike ]
123- pickle_reload : bool
124- separate_files : bool
125- wait_for_calc_timeout : int
126- allow_none : bool
127-
128-
129- _default_params : Params = {
130- "caching_enabled" : True ,
131- "hash_func" : _default_hash_func ,
132- "backend" : "pickle" ,
133- "mongetter" : None ,
134- "stale_after" : datetime .timedelta .max ,
135- "next_time" : False ,
136- "cache_dir" : "~/.cachier/" ,
137- "pickle_reload" : True ,
138- "separate_files" : False ,
139- "wait_for_calc_timeout" : 0 ,
140- "allow_none" : False ,
141- }
142-
143-
14496def cachier (
14597 hash_func : Optional [HashFunc ] = None ,
14698 hash_params : Optional [HashFunc ] = None ,
@@ -219,13 +171,12 @@ def cachier(
219171 )
220172 warn (message , DeprecationWarning , stacklevel = 2 )
221173 hash_func = hash_params
174+ # Update parameters with defaults if input is None
175+ backend = _update_with_defaults (backend , "backend" )
176+ mongetter = _update_with_defaults (mongetter , "mongetter" )
222177 # Override the backend parameter if a mongetter is provided.
223- if mongetter is None :
224- mongetter = _default_params ["mongetter" ]
225178 if callable (mongetter ):
226179 backend = "mongo"
227- if backend is None :
228- backend = _default_params ["backend" ]
229180 core : _BaseCore
230181 if backend == "pickle" :
231182 core = _PickleCore (
@@ -234,23 +185,16 @@ def cachier(
234185 cache_dir = cache_dir ,
235186 separate_files = separate_files ,
236187 wait_for_calc_timeout = wait_for_calc_timeout ,
237- default_params = _default_params ,
238188 )
239189 elif backend == "mongo" :
240- if mongetter is None :
241- raise MissingMongetter (
242- "must specify ``mongetter`` when using the mongo core"
243- )
244190 core = _MongoCore (
245- mongetter = mongetter ,
246191 hash_func = hash_func ,
192+ mongetter = mongetter ,
247193 wait_for_calc_timeout = wait_for_calc_timeout ,
248- default_params = _default_params ,
249194 )
250195 elif backend == "memory" :
251196 core = _MemoryCore (
252- hash_func = hash_func ,
253- default_params = _default_params ,
197+ hash_func = hash_func , wait_for_calc_timeout = wait_for_calc_timeout
254198 )
255199 else :
256200 raise ValueError ("specified an invalid core: %s" % backend )
@@ -261,11 +205,7 @@ def _cachier_decorator(func):
261205 @wraps (func )
262206 def func_wrapper (* args , ** kwds ):
263207 nonlocal allow_none
264- _allow_none = (
265- allow_none
266- if allow_none is not None
267- else _default_params ["allow_none" ]
268- )
208+ _allow_none = _update_with_defaults (allow_none , "allow_none" )
269209 # print('Inside general wrapper for {}.'.format(func.__name__))
270210 ignore_cache = kwds .pop ("ignore_cache" , False )
271211 overwrite_cache = kwds .pop ("overwrite_cache" , False )
@@ -289,10 +229,10 @@ def func_wrapper(*args, **kwds):
289229 _print ("Entry found." )
290230 if _allow_none or entry .get ("value" , None ) is not None :
291231 _print ("Cached result found." )
292- local_stale_after = (
293- stale_after or _default_params [ "stale_after" ]
232+ local_stale_after = _update_with_defaults (
233+ stale_after , "stale_after"
294234 )
295- local_next_time = next_time or _default_params [ "next_time" ] # noqa: E501
235+ local_next_time = _update_with_defaults ( next_time , "next_time" )
296236 now = datetime .datetime .now ()
297237 if now - entry ["time" ] <= local_stale_after :
298238 _print ("And it is fresh!" )
@@ -362,35 +302,3 @@ def precache_value(*args, value_to_cache, **kwds):
362302 return func_wrapper
363303
364304 return _cachier_decorator
365-
366-
367- def set_default_params (** params ):
368- """Configure global parameters applicable to all memoized functions.
369-
370- This function takes the same keyword parameters as the ones defined in the
371- decorator, which can be passed all at once or with multiple calls.
372- Parameters given directly to a decorator take precedence over any values
373- set by this function.
374-
375- Only 'stale_after', 'next_time', and 'wait_for_calc_timeout' can be changed
376- after the memoization decorator has been applied. Other parameters will
377- only have an effect on decorators applied after this function is run.
378-
379- """
380- valid_params = (p for p in params .items () if p [0 ] in _default_params )
381- _default_params .update (valid_params )
382-
383-
384- def get_default_params ():
385- """Get current set of default parameters."""
386- return _default_params
387-
388-
389- def enable_caching ():
390- """Enable caching globally."""
391- _default_params ["caching_enabled" ] = True
392-
393-
394- def disable_caching ():
395- """Disable caching globally."""
396- _default_params ["caching_enabled" ] = False
0 commit comments